bshell: add line-editor and file-based input support
This commit is contained in:
+116
@@ -0,0 +1,116 @@
|
||||
#include "file.h"
|
||||
|
||||
#include "line-source.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fx/collections/array.h>
|
||||
#include <fx/string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static enum bshell_status get_name(
|
||||
struct line_source *src,
|
||||
char *buf,
|
||||
size_t count,
|
||||
size_t *nr_read)
|
||||
{
|
||||
struct file *f = (struct file *)src;
|
||||
*nr_read = snprintf(buf, count, "%s", f->f_path);
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
static enum bshell_status get_row(
|
||||
struct line_source *src,
|
||||
size_t row,
|
||||
char *buf,
|
||||
size_t count,
|
||||
size_t *nr_read)
|
||||
{
|
||||
struct file *f = (struct file *)src;
|
||||
size_t nr_rows = fx_array_size(f->f_lines);
|
||||
|
||||
if (row > nr_rows) {
|
||||
return BSHELL_ERR_EOF;
|
||||
}
|
||||
|
||||
fx_string *line = fx_array_at(f->f_lines, row - 1);
|
||||
|
||||
const char *line_str = fx_string_get_cstr(line);
|
||||
size_t line_len = fx_string_get_size(line, FX_STRLEN_NORMAL);
|
||||
size_t copy_len = fx_min(ulong, count, line_len);
|
||||
|
||||
memcpy(buf, line_str, copy_len);
|
||||
buf[copy_len] = 0;
|
||||
buf[strcspn(buf, "\n")] = 0;
|
||||
*nr_read = copy_len;
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
static enum bshell_status readline(
|
||||
struct line_source *src,
|
||||
fx_stringstream *out)
|
||||
{
|
||||
struct file *f = (struct file *)src;
|
||||
fx_wchar c = FX_WCHAR_INVALID;
|
||||
size_t nr_read = 0;
|
||||
|
||||
while (1) {
|
||||
fx_status status = fx_stream_read_char(f->f_strp, &c);
|
||||
if (!FX_OK(status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
fx_stream_write_char(out, c);
|
||||
nr_read++;
|
||||
|
||||
if (c == '\n') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nr_read == 0) {
|
||||
return BSHELL_ERR_EOF;
|
||||
}
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
enum bshell_status file_open(const char *path, struct file **out)
|
||||
{
|
||||
FILE *fp = fopen(path, "r");
|
||||
if (!fp) {
|
||||
return bshell_status_from_errno(errno);
|
||||
}
|
||||
|
||||
fx_stream *strp = fx_stream_open_fp(fp);
|
||||
|
||||
struct file *file = malloc(sizeof *file);
|
||||
if (!file) {
|
||||
fclose(fp);
|
||||
return BSHELL_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
memset(file, 0x0, sizeof *file);
|
||||
|
||||
file->f_base.s_get_name = get_name;
|
||||
file->f_base.s_get_row = get_row;
|
||||
file->f_base.s_readline = readline;
|
||||
file->f_fp = fp;
|
||||
file->f_strp = strp;
|
||||
file->f_path = fx_strdup(path);
|
||||
file->f_lines = fx_array_create();
|
||||
|
||||
*out = file;
|
||||
|
||||
return BSHELL_SUCCESS;
|
||||
}
|
||||
|
||||
void file_close(struct file *file)
|
||||
{
|
||||
fx_stream_unref(file->f_strp);
|
||||
fx_array_unref(file->f_lines);
|
||||
free(file->f_path);
|
||||
fclose(file->f_fp);
|
||||
free(file);
|
||||
}
|
||||
Reference in New Issue
Block a user