libc: Implement fgets, fgetc, getc, getchar (with buffered read IO)

This commit is contained in:
apio 2022-10-22 11:38:16 +02:00
parent 51e024588e
commit 27a18a608c
3 changed files with 148 additions and 37 deletions

View File

@ -1,3 +1,4 @@
#include <assert.h>
#include <errno.h>
#include <luna.h>
#include <stdio.h>
@ -135,37 +136,41 @@ void command_execute(command* cmd)
show_prompt();
}
void command_concat_char(command* cmd, char c)
{
if (c == '\b')
{
if (cmd->size != 0)
{
putchar(c);
command_pop(cmd);
}
}
else if (c == '\n')
{
if (cmd->size == 0)
{
putchar(c);
show_prompt();
}
else
{
putchar(c);
command_execute(cmd);
}
}
else
{
putchar(c);
command_push(cmd, c);
}
}
void command_concat(command* cmd, const char* str)
{
while (*str)
{
if (*str == '\b')
{
if (cmd->size == 0)
{
str++;
continue;
}
putchar(*str);
command_pop(cmd);
}
else if (*str == '\n')
{
if (cmd->size == 0)
{
putchar(*str);
show_prompt();
str++;
continue;
}
putchar(*str);
command_execute(cmd);
}
else
{
putchar(*str);
command_push(cmd, *str);
}
command_concat_char(cmd, *str);
str++;
}
}
@ -174,21 +179,22 @@ int main()
{
show_prompt();
char buffer[33];
command shell_command;
command_init(&shell_command);
while (1)
{
size_t nread = fread(buffer, sizeof(buffer) - 1, 1, stdin);
if (ferror(stdin))
int c = getchar();
if (c == EOF)
{
perror("fread");
return 1;
if (ferror(stdin))
{
perror("getchar");
return 1;
}
if (feof(stdin)) { return 0; }
assert(false); // we should never get here
}
if (feof(stdin)) { return 0; }
buffer[nread] = 0;
command_concat(&shell_command, buffer);
command_concat_char(&shell_command, (char)c);
}
}

View File

@ -13,6 +13,10 @@ typedef struct
int f_fd;
int f_eof;
int f_err;
char* f_buf;
long f_bufsize;
long f_bufoff;
long f_bufrsize;
} FILE;
extern FILE* stderr;
@ -22,6 +26,8 @@ extern FILE* stdin;
#define stdout stdout
#define stderr stderr
#define EOF -1
typedef struct
{
long f_offset;
@ -74,6 +80,18 @@ extern "C"
/* Writes nmemb items of size size from buf into the file stream. */
size_t fwrite(const void* buf, size_t size, size_t nmemb, FILE* stream);
/* Reads a line from stream into buf. */
char* fgets(char* buf, int size, FILE* stream);
/* Retrieves a character from stream. */
int fgetc(FILE* stream);
/* Retrieves a character from stream. */
int getc(FILE* stream);
/* Retrieves a character from standard input. */
int getchar();
/* Returns nonzero if the error flag in stream was set. */
int ferror(FILE* stream);

View File

@ -9,10 +9,33 @@ FILE* stderr;
FILE* stdout;
FILE* stdin;
void file_read_buf(FILE* stream)
{
if (!stream->f_buf)
{
stream->f_buf = (char*)malloc(32);
stream->f_bufrsize = 32;
}
stream->f_bufoff = 0;
ssize_t nread = read(stream->f_fd, stream->f_buf, stream->f_bufrsize);
if (nread < 0)
{
stream->f_err = 1;
return;
}
if (nread == 0)
{
stream->f_eof = 1;
return;
}
stream->f_bufsize = nread;
}
extern "C"
{
int fclose(FILE* stream)
{
if (stream->f_buf) free(stream->f_buf);
int status = close(stream->f_fd);
if (status < 0)
{
@ -49,6 +72,9 @@ extern "C"
if (!stream) { return 0; }
stream->f_fd = fd;
clearerr(stream);
stream->f_buf = 0;
stream->f_bufoff = 0;
stream->f_bufsize = 0;
return stream;
}
@ -73,7 +99,9 @@ extern "C"
size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream)
{
ssize_t status = read(stream->f_fd, buf, size * nmemb);
ssize_t status =
read(stream->f_fd, buf,
size * nmemb); // FIXME: This function should use file_read_buf() to not conflict with fgets().
if (status < 0)
{
stream->f_err = 1;
@ -83,6 +111,65 @@ extern "C"
return (size_t)status;
}
char* fgets(char* buf, int size, FILE* stream)
{
char* s = buf;
int original_size = size;
while (size > 1)
{
if (stream->f_bufoff < stream->f_bufsize)
{
*buf = *(stream->f_buf + stream->f_bufoff);
stream->f_bufoff++;
if (*buf == '\n')
{
buf++;
break;
}
buf++;
size--;
}
else
{
file_read_buf(stream);
if (ferror(stream)) return NULL;
if (feof(stream)) break;
}
}
if (size == original_size && feof(stream)) return NULL; // EOF while reading the first character
*buf = 0;
return s;
}
int fgetc(FILE* stream)
{
char result;
read:
if (stream->f_bufoff < stream->f_bufsize)
{
result = *(stream->f_buf + stream->f_bufoff);
stream->f_bufoff++;
}
else
{
file_read_buf(stream);
if (ferror(stream)) return EOF;
if (feof(stream)) return EOF;
goto read;
}
return (int)result;
}
int getc(FILE* stream)
{
return fgetc(stream);
}
int getchar()
{
return fgetc(stdin);
}
int ferror(FILE* stream)
{
return stream->f_err;