libc: Implement fgets, fgetc, getc, getchar (with buffered read IO)
This commit is contained in:
parent
51e024588e
commit
27a18a608c
@ -1,3 +1,4 @@
|
|||||||
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <luna.h>
|
#include <luna.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -135,37 +136,41 @@ void command_execute(command* cmd)
|
|||||||
show_prompt();
|
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)
|
void command_concat(command* cmd, const char* str)
|
||||||
{
|
{
|
||||||
while (*str)
|
while (*str)
|
||||||
{
|
{
|
||||||
if (*str == '\b')
|
command_concat_char(cmd, *str);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
str++;
|
str++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,21 +179,22 @@ int main()
|
|||||||
{
|
{
|
||||||
show_prompt();
|
show_prompt();
|
||||||
|
|
||||||
char buffer[33];
|
|
||||||
|
|
||||||
command shell_command;
|
command shell_command;
|
||||||
command_init(&shell_command);
|
command_init(&shell_command);
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
size_t nread = fread(buffer, sizeof(buffer) - 1, 1, stdin);
|
int c = getchar();
|
||||||
if (ferror(stdin))
|
if (c == EOF)
|
||||||
{
|
{
|
||||||
perror("fread");
|
if (ferror(stdin))
|
||||||
return 1;
|
{
|
||||||
|
perror("getchar");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (feof(stdin)) { return 0; }
|
||||||
|
assert(false); // we should never get here
|
||||||
}
|
}
|
||||||
if (feof(stdin)) { return 0; }
|
command_concat_char(&shell_command, (char)c);
|
||||||
buffer[nread] = 0;
|
|
||||||
command_concat(&shell_command, buffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,6 +13,10 @@ typedef struct
|
|||||||
int f_fd;
|
int f_fd;
|
||||||
int f_eof;
|
int f_eof;
|
||||||
int f_err;
|
int f_err;
|
||||||
|
char* f_buf;
|
||||||
|
long f_bufsize;
|
||||||
|
long f_bufoff;
|
||||||
|
long f_bufrsize;
|
||||||
} FILE;
|
} FILE;
|
||||||
|
|
||||||
extern FILE* stderr;
|
extern FILE* stderr;
|
||||||
@ -22,6 +26,8 @@ extern FILE* stdin;
|
|||||||
#define stdout stdout
|
#define stdout stdout
|
||||||
#define stderr stderr
|
#define stderr stderr
|
||||||
|
|
||||||
|
#define EOF -1
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
long f_offset;
|
long f_offset;
|
||||||
@ -74,6 +80,18 @@ extern "C"
|
|||||||
/* Writes nmemb items of size size from buf into the file stream. */
|
/* 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);
|
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. */
|
/* Returns nonzero if the error flag in stream was set. */
|
||||||
int ferror(FILE* stream);
|
int ferror(FILE* stream);
|
||||||
|
|
||||||
|
@ -9,10 +9,33 @@ FILE* stderr;
|
|||||||
FILE* stdout;
|
FILE* stdout;
|
||||||
FILE* stdin;
|
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"
|
extern "C"
|
||||||
{
|
{
|
||||||
int fclose(FILE* stream)
|
int fclose(FILE* stream)
|
||||||
{
|
{
|
||||||
|
if (stream->f_buf) free(stream->f_buf);
|
||||||
int status = close(stream->f_fd);
|
int status = close(stream->f_fd);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
{
|
{
|
||||||
@ -49,6 +72,9 @@ extern "C"
|
|||||||
if (!stream) { return 0; }
|
if (!stream) { return 0; }
|
||||||
stream->f_fd = fd;
|
stream->f_fd = fd;
|
||||||
clearerr(stream);
|
clearerr(stream);
|
||||||
|
stream->f_buf = 0;
|
||||||
|
stream->f_bufoff = 0;
|
||||||
|
stream->f_bufsize = 0;
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +99,9 @@ extern "C"
|
|||||||
|
|
||||||
size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream)
|
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)
|
if (status < 0)
|
||||||
{
|
{
|
||||||
stream->f_err = 1;
|
stream->f_err = 1;
|
||||||
@ -83,6 +111,65 @@ extern "C"
|
|||||||
return (size_t)status;
|
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)
|
int ferror(FILE* stream)
|
||||||
{
|
{
|
||||||
return stream->f_err;
|
return stream->f_err;
|
||||||
|
Loading…
Reference in New Issue
Block a user