diff --git a/include/fh_input.h b/include/fh_input.h index f50a58d..c420bb6 100644 --- a/include/fh_input.h +++ b/include/fh_input.h @@ -15,17 +15,19 @@ typedef bool (*fh_input_refill_t)(struct fh_thread_s *fh, struct fh_input_spec_s /** Spec free func */ typedef void (*fh_input_free_t)(void *spec); -typedef void (*fh_input_start_t)(struct fh_thread_s *fh, struct fh_input_spec_s *spec); +typedef void (*fh_input_void_method_t)(struct fh_thread_s *fh, struct fh_input_spec_s *spec); -typedef void (*fh_input_pushpop_t)(struct fh_thread_s *fh, struct fh_input_spec_s *spec); +typedef enum fh_error (*fh_input_error_method_t)(struct fh_thread_s *fh, struct fh_input_spec_s *spec); struct fh_input_spec_s { struct fh_input_spec_s *previous; fh_input_refill_t refill_input_buffer; - fh_input_start_t start; + fh_input_void_method_t start; fh_input_free_t free_self; - fh_input_pushpop_t push_prepare; - fh_input_pushpop_t pop_restore; + fh_input_void_method_t push_prepare; + fh_input_void_method_t pop_restore; + fh_input_error_method_t save_input; + fh_input_error_method_t restore_input; uint32_t linenum; char *cwd; // CWD of the input, used for relative includes. malloc'd (strdup) diff --git a/src/fh_builtins_meta.c b/src/fh_builtins_meta.c index f538720..d63472b 100644 --- a/src/fh_builtins_meta.c +++ b/src/fh_builtins_meta.c @@ -603,6 +603,22 @@ static enum fh_error w_evaluate(struct fh_thread_s *fh, const struct fh_word_s * return FH_OK; } +static enum fh_error w_save_input(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + fh->input->save_input(fh, fh->input); + return FH_OK; +} + +static enum fh_error w_restore_input(struct fh_thread_s *fh, const struct fh_word_s *w) +{ + (void) w; + enum fh_error rv; + fh->input->restore_input(fh, fh->input); + return FH_OK; +} + static enum fh_error w_included(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; @@ -738,11 +754,13 @@ const struct name_and_handler fh_builtins_meta[] = { {"'", wp_tick, 1, 0}, {"[']", wp_tick, 1, 1}, {"execute", w_execute, 0, 0}, + {"save-input", w_save_input, 0, 0}, + {"restore-input",w_restore_input, 0, 0}, {"environment?", w_env_query, 0, 0}, {"marker", w_marker, 0, 0}, {"compile,", w_compile_comma, 0, 0}, {"evaluate", w_evaluate, 0, 0}, {"included", w_included, 0, 0}, - {"include", w_include, 0, 0}, + {"include", w_include, 0, 0}, { /* end marker */ } }; diff --git a/src/fh_input.c b/src/fh_input.c index f66f43c..e9f82c4 100644 --- a/src/fh_input.c +++ b/src/fh_input.c @@ -1,5 +1,17 @@ #include "forth_internal.h" +struct file_input_spec { + struct fh_input_spec_s spec; + char saved_buffer[INPUT_BUFFER_SIZE]; + FILE *file; +}; + +struct string_input_spec { + struct fh_input_spec_s spec; + const char *str; + size_t len; +}; + enum fh_error fh_push_input(struct fh_thread_s *fh, struct fh_input_spec_s *newinput) { LOG("--- Push input spec ---"); @@ -70,17 +82,78 @@ enum fh_error fh_pop_input(struct fh_thread_s *fh) return FH_OK; } -struct file_input_spec { - struct fh_input_spec_s spec; - char saved_buffer[INPUT_BUFFER_SIZE]; - FILE *file; -}; +static enum fh_error file_save_input(struct fh_thread_s *fh, struct fh_input_spec_s *spec) +{ + enum fh_error rv; + struct file_input_spec *fspec = (void*) spec; + + if (isatty(fileno(fspec->file))) { + TRY(ds_push(fh, 0)); + return FH_OK; + } + + uint32_t pos = (uint32_t) ftell(fspec->file); + + TRY(ds_push(fh, spec->linenum)); + TRY(ds_push(fh, fh->inputptr)); + TRY(ds_push(fh, pos - fh->inputlen)); + TRY(ds_push(fh, 3)); + return FH_OK; +} -struct string_input_spec { - struct fh_input_spec_s spec; - const char *str; - size_t len; -}; +static enum fh_error file_restore_input(struct fh_thread_s *fh, struct fh_input_spec_s *spec) +{ + enum fh_error rv; + struct file_input_spec *fspec = (void*) spec; + uint32_t n; + TRY(ds_pop(fh, &n)); + if (n == 3) { + uint32_t filepos; + TRY(ds_pop(fh, &filepos)); + fseek(fspec->file, filepos, SEEK_SET); + TRY(ds_pop(fh, &fh->inputptr)); + TRY(ds_pop(fh, &spec->linenum)); + + LOG("file input, restore filepos %d, inptr %d, linenum %d", + filepos, fh->inputptr, spec->linenum); + + fgets(&fh->heap[INPUTBUF_ADDR], INPUT_BUFFER_SIZE, fspec->file); + TRY(ds_push(fh, 0)); + } else { + LOG("file input, restore nothing, bad N!"); + TRY(ds_push(fh, TOBOOL(1))); + } + + return FH_OK; +} + +static enum fh_error str_save_input(struct fh_thread_s *fh, struct fh_input_spec_s *spec) +{ + enum fh_error rv; + TRY(ds_push(fh, spec->linenum)); + TRY(ds_push(fh, fh->inputptr)); + TRY(ds_push(fh, 2)); + return FH_OK; +} + +static enum fh_error str_restore_input(struct fh_thread_s *fh, struct fh_input_spec_s *spec) +{ + enum fh_error rv; + uint32_t n; + TRY(ds_pop(fh, &n)); + if (n == 2) { + TRY(ds_pop(fh, &fh->inputptr)); + TRY(ds_pop(fh, &spec->linenum)); + + LOG("str input, inptr %d, linenum %d", + fh->inputptr, spec->linenum); + TRY(ds_push(fh, 0)); + } else { + LOG("str input, restore nothing, bad N!"); + TRY(ds_push(fh, TOBOOL(1))); + } + return FH_OK; +} static void file_push_prepare(struct fh_thread_s *fh, struct fh_input_spec_s *spec) { @@ -160,26 +233,8 @@ static bool file_refill(struct fh_thread_s *fh, struct fh_input_spec_s *spec) static bool str_refill(struct fh_thread_s *fh, struct fh_input_spec_s *spec) { + // no refilling, the string exists in its entirety on heap return fh->inputptr < fh->inputlen; -// struct string_input_spec *fis = (struct string_input_spec *) spec; -// fh_input_memmove_leftovers(fh); -// uint32_t space_left = INPUT_BUFFER_SIZE - fh->inputlen - 1; -// 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); -// *(wp + space_left) = 0; -// fis->readpos += space_left; -// fh->inputlen += space_left; -// return true; -// } else { -// return false; -// } } static void free_filespec(void *p) @@ -220,6 +275,8 @@ struct fh_input_spec_s *fh_create_input_from_filestruct(FILE *f, const char *cwd spec->spec.push_prepare = file_push_prepare; spec->spec.pop_restore = file_pop_restore; spec->spec.refill_input_buffer = file_refill; + spec->spec.save_input = file_save_input; + spec->spec.restore_input = file_restore_input; spec->file = f; if (cwd) { spec->spec.cwd = strdup(cwd); @@ -247,6 +304,8 @@ struct fh_input_spec_s *fh_create_input_from_filename(char *path) spec->spec.push_prepare = file_push_prepare; spec->spec.pop_restore = file_pop_restore; spec->spec.refill_input_buffer = file_refill; + spec->spec.save_input = file_save_input; + spec->spec.restore_input = file_restore_input; spec->file = f; char pwd[PATH_MAX+1]; @@ -275,6 +334,8 @@ struct fh_input_spec_s *fh_create_input_from_string(char *str, size_t len, const spec->spec.push_prepare = str_push_prepare; spec->spec.pop_restore = str_pop_restore; spec->spec.start = str_start; + spec->spec.save_input = str_save_input; + spec->spec.restore_input = str_restore_input; spec->str = str; spec->len = len; spec->spec.cwd = cwd ? strdup(cwd) : NULL; diff --git a/src/fh_parse.c b/src/fh_parse.c index b6ddf03..15247f2 100644 --- a/src/fh_parse.c +++ b/src/fh_parse.c @@ -386,7 +386,7 @@ enum fh_error fh_process_line(struct fh_thread_s *fh) } } else if (fh->parse_if_level == 0) { /* eval a word */ - LOG("Handle \"%.*s\", len %d", (int) length, rp, length); + LOG("Handle \"%.*s\"", (int) length, rp); TRY(fh_handle_ascii_word(fh, rp, length)); } else { if (EQ(rp, "\\", length)) { diff --git a/testfiles/saverestore.f b/testfiles/saverestore.f new file mode 100644 index 0000000..6eb4438 --- /dev/null +++ b/testfiles/saverestore.f @@ -0,0 +1,19 @@ +\ 1 debug + +VARIABLE SI_INC 0 SI_INC ! + +: SI1 + SI_INC @ >IN +! + 15 SI_INC ! +; + +: S$ S" SAVE-INPUT SI1 RESTORE-INPUT 12345" ; + +S$ EVALUATE SI_INC @ + +. . . + +\ 0 2345 15 + +bye +