You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
4.6 KiB
192 lines
4.6 KiB
3 years ago
|
#include "forth_internal.h"
|
||
|
|
||
|
void fh_push_input(struct fh_thread_s *fh, struct fh_input_spec_s *newinput)
|
||
|
{
|
||
|
if (newinput == NULL) {
|
||
|
LOGE("push input with NULL");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
struct fh_input_spec_s *oldinput = fh->input;
|
||
|
if (NULL == oldinput) {
|
||
|
// no previous input spec, just use the new one
|
||
|
fh->input = newinput;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
fh->input = NULL;
|
||
|
|
||
|
memcpy(&oldinput->saved_buffer[0], &fh->heap[INPUTBUF_ADDR], INPUT_BUFFER_SIZE);
|
||
|
oldinput->saved_inputlen = fh->inputlen;
|
||
|
oldinput->saved_inputptr = fh->inputptr;
|
||
|
newinput->previous = oldinput;
|
||
|
|
||
|
fh->input = newinput;
|
||
|
}
|
||
|
|
||
|
void fh_pop_input(struct fh_thread_s *fh)
|
||
|
{
|
||
|
struct fh_input_spec_s *discarded = fh->input;
|
||
|
fh->input = NULL;
|
||
|
|
||
|
struct fh_input_spec_s *restored = discarded->previous;
|
||
|
if (!restored) {
|
||
|
return;
|
||
|
}
|
||
|
fh->input = restored; // this can be NULL, that must be checked by caller.
|
||
|
|
||
|
memcpy(&fh->heap[INPUTBUF_ADDR], &restored->saved_buffer[0], INPUT_BUFFER_SIZE);
|
||
|
fh->inputlen = restored->saved_inputlen;
|
||
|
fh->inputptr = restored->saved_inputptr;
|
||
|
|
||
|
if (discarded->free_self) {
|
||
|
discarded->free_self(discarded);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct file_input_spec {
|
||
|
struct fh_input_spec_s spec;
|
||
|
FILE *file;
|
||
|
};
|
||
|
|
||
|
struct string_input_spec {
|
||
|
struct fh_input_spec_s spec;
|
||
|
char *str;
|
||
|
size_t len;
|
||
|
size_t readpos;
|
||
|
};
|
||
|
|
||
|
static inline uint8_t *inputbuf_at(struct fh_thread_s *fh, size_t pos)
|
||
|
{
|
||
|
return &fh->heap[INPUTBUF_ADDR + pos];
|
||
|
}
|
||
|
|
||
|
void fh_input_memmove_leftovers(struct fh_thread_s *fh)
|
||
|
{
|
||
|
if (fh->inputptr < fh->inputlen) {
|
||
|
// something is left
|
||
|
uint32_t remains = fh->inputlen - fh->inputptr;
|
||
|
if (remains > 0) {
|
||
|
LOG("Refill, reuse %d bytes left in buffer", remains);
|
||
|
memmove(inputbuf_at(fh, 0), inputbuf_at(fh, fh->inputptr), remains);
|
||
|
fh->inputptr = 0;
|
||
|
fh->inputlen = remains;
|
||
|
} else {
|
||
|
LOG("Refill, nothing reused (1)");
|
||
|
fh->inputptr = 0;
|
||
|
fh->inputlen = 0;
|
||
|
}
|
||
|
} else {
|
||
|
LOG("Refill, nothing reused (2)");
|
||
|
fh->inputptr = 0;
|
||
|
fh->inputlen = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool file_refill(struct fh_thread_s *fh, struct fh_input_spec_s *spec)
|
||
|
{
|
||
|
struct file_input_spec *fis = (struct file_input_spec *) spec;
|
||
|
fh_input_memmove_leftovers(fh);
|
||
|
uint32_t space_left = INPUT_BUFFER_SIZE - fh->inputlen;
|
||
|
char *wp = (char *) inputbuf_at(fh, fh->inputptr);
|
||
|
LOG("spec %p, fgets %d", spec, space_left);
|
||
|
if (fgets(wp, (int) space_left, fis->file)) {
|
||
|
spec->linenum++;
|
||
|
fh->inputlen = strnlen(wp, INPUT_BUFFER_SIZE);
|
||
|
return true;
|
||
|
} else {
|
||
|
return fh->inputptr > fh->inputlen; // return false only if there is nothing left
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static bool str_refill(struct fh_thread_s *fh, struct fh_input_spec_s *spec)
|
||
|
{
|
||
|
struct string_input_spec *fis = (struct string_input_spec *) spec;
|
||
|
fh_input_memmove_leftovers(fh);
|
||
|
uint32_t space_left = INPUTBUF_ADDR - fh->inputlen;
|
||
|
char *wp = (char *) inputbuf_at(fh, fh->inputptr);
|
||
|
|
||
|
uint32_t chars_remaining_in_string = fis->len - fis->readpos;
|
||
|
if (chars_remaining_in_string > 0) {
|
||
|
if (chars_remaining_in_string < space_left) {
|
||
|
space_left = chars_remaining_in_string;
|
||
|
}
|
||
|
|
||
|
memcpy(wp, &fis->str[fis->readpos], space_left);
|
||
|
return true;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void free_filespec(void *p)
|
||
|
{
|
||
|
struct file_input_spec *spec = (struct file_input_spec *) p;
|
||
|
if (spec->file != stdin) {
|
||
|
fclose(spec->file);
|
||
|
spec->file = NULL;
|
||
|
}
|
||
|
free(spec);
|
||
|
}
|
||
|
|
||
|
struct fh_input_spec_s *fh_create_input_from_filestruct(FILE *f)
|
||
|
{
|
||
|
struct file_input_spec *spec = calloc(sizeof(struct file_input_spec), 1);
|
||
|
if (!spec) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
spec->spec.free_self = free;
|
||
|
spec->spec.refill_input_buffer = file_refill;
|
||
|
spec->file = f;
|
||
|
return (struct fh_input_spec_s*) spec;
|
||
|
}
|
||
|
|
||
|
struct fh_input_spec_s *fh_create_input_from_filename(char *path)
|
||
|
{
|
||
|
struct file_input_spec *spec = calloc(sizeof(struct file_input_spec), 1);
|
||
|
if (!spec) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
FILE *f = fopen(path, "r");
|
||
|
if (!f) {
|
||
|
free(spec);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
spec->spec.free_self = free_filespec;
|
||
|
spec->spec.refill_input_buffer = file_refill;
|
||
|
spec->file = f;
|
||
|
return (struct fh_input_spec_s*) spec;
|
||
|
}
|
||
|
|
||
|
struct fh_input_spec_s *fh_create_input_from_string(char *str, size_t len)
|
||
|
{
|
||
|
struct string_input_spec *spec = calloc(sizeof(struct string_input_spec), 1);
|
||
|
if (!spec) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
spec->spec.free_self = free;
|
||
|
spec->spec.refill_input_buffer = str_refill;
|
||
|
spec->str = str;
|
||
|
spec->readpos = 0;
|
||
|
spec->len = len;
|
||
|
return (struct fh_input_spec_s*) spec;
|
||
|
}
|
||
|
|
||
|
void fh_input_teardown(struct fh_thread_s *fh)
|
||
|
{
|
||
|
struct fh_input_spec_s *s = fh->input;
|
||
|
if (!s) return;
|
||
|
|
||
|
while (s) {
|
||
|
struct fh_input_spec_s *prev = s->previous;
|
||
|
if (s->free_self) {
|
||
|
s->free_self(s);
|
||
|
}
|
||
|
s = prev;
|
||
|
}
|
||
|
}
|