From 7320e6fa3a5b25b2339efc03a8fddb40bb7abb5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Borggr=C3=A9n-Franck?= Date: Tue, 13 Sep 2011 12:23:02 +0200 Subject: [PATCH] Implemented simple (read-only) (ungetc-able) string-stream Refactored the stream interface and implemented a simple stringstream. Now have working filestream and stringstream. Next up is make eval read "(repl)" from stringstream. --- .gitignore | 1 + src/ast-walker/filestream.c | 33 ++++++++++++++++ src/ast-walker/filestream.h | 9 +++++ src/ast-walker/memory.c | 5 +++ src/ast-walker/memory.h | 1 + src/ast-walker/stringstream.c | 71 +++++++++++++++++++++++++++++++++++ src/ast-walker/stringstream.h | 10 +++++ src/ast-walker/t_stream.c | 31 --------------- src/ast-walker/t_stream.h | 3 -- src/ast-walker/token.c | 1 + test/test_stringstream.c | 47 +++++++++++++++++++++++ 11 files changed, 178 insertions(+), 34 deletions(-) create mode 100644 src/ast-walker/filestream.c create mode 100644 src/ast-walker/filestream.h create mode 100644 src/ast-walker/stringstream.c create mode 100644 src/ast-walker/stringstream.h create mode 100644 test/test_stringstream.c diff --git a/.gitignore b/.gitignore index e5f59b3..30afe71 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ TAGS /src/vm/cpp_vm.d /src/vm/test/test_context.d /tlisp +/test/test_stringstream diff --git a/src/ast-walker/filestream.c b/src/ast-walker/filestream.c new file mode 100644 index 0000000..2510841 --- /dev/null +++ b/src/ast-walker/filestream.c @@ -0,0 +1,33 @@ +#include "filestream.h" + +int filestream_getc(STREAM *stream); +int filestream_ungetc(int ch, STREAM *stream); +int filestream_flush(STREAM *stream); +int filestream_close(STREAM *stream); + +int make_filestream(STREAM *stream, FILE *f) { + stream->payload = f; + stream->fgetc_fun = filestream_getc; + stream->ungetc_fun = filestream_ungetc; + stream->flush_fun = filestream_flush; + stream->close_fun = filestream_close; + return 1; +} + +int filestream_getc(STREAM *stream) { + return fgetc((FILE *)stream->payload); +} + +int filestream_ungetc(int ch, STREAM *stream) { + return ungetc(ch, (FILE *)stream->payload); +} + +int filestream_flush(STREAM *stream) { + return fflush((FILE *)stream->payload); +} + +int filestream_close(STREAM *stream) { + FILE *f = (FILE *)stream->payload; + stream->payload = NULL; + return fclose(f); +} diff --git a/src/ast-walker/filestream.h b/src/ast-walker/filestream.h new file mode 100644 index 0000000..b4d2328 --- /dev/null +++ b/src/ast-walker/filestream.h @@ -0,0 +1,9 @@ +#ifndef _FILESTREAM_H +#define _FILESTREAM_H 1 + +#include +#include "t_stream.h" + +int make_filestream(STREAM *stream, FILE *f); + +#endif /* _FILESTREAM_H */ diff --git a/src/ast-walker/memory.c b/src/ast-walker/memory.c index eaedae1..e9fa18b 100644 --- a/src/ast-walker/memory.c +++ b/src/ast-walker/memory.c @@ -33,6 +33,11 @@ void *malloc_or_bail(size_t bytes) { return tmp; } +/* Off-heap free. */ +void free_malloced(void *ptr) { + free(ptr); +} + /* On-heap malloc that only returns if it succeeds */ void *mem_sys_safe_alloc(size_t bytes) { void *t; diff --git a/src/ast-walker/memory.h b/src/ast-walker/memory.h index 88c8cbf..e1819aa 100644 --- a/src/ast-walker/memory.h +++ b/src/ast-walker/memory.h @@ -5,6 +5,7 @@ void *mem_sys_safe_alloc(size_t bytes); void *malloc_or_bail(size_t bytes); +void free_malloced(void *ptr); void *u8_new(size_t bytes); #define new(type) ((type *)mem_sys_safe_alloc(sizeof(type)/sizeof(char))) diff --git a/src/ast-walker/stringstream.c b/src/ast-walker/stringstream.c new file mode 100644 index 0000000..aec1f64 --- /dev/null +++ b/src/ast-walker/stringstream.c @@ -0,0 +1,71 @@ +#include "stringstream.h" + +#include +#include + +#include "memory.h" + +int stringstream_getc(STREAM *stream); +int stringstream_ungetc(int ch, STREAM *stream); +int stringstream_flush(STREAM *stream); +int stringstream_close(STREAM *stream); + +typedef struct string_info { + char *str; + size_t len; + size_t index; +} string_info; + +int make_stringstream(STREAM *stream, const char *str, size_t size) { + char *target; + string_info *s = new_malloc(string_info); + + /* This will at most trigger a read overflow + pagefault. Sweet */ + if(strlen(str) >= size) { /* str + '\0' must fit in size */ + memset(stream, 0, sizeof(STREAM)/sizeof(char)); + return 0; + } else if (size < 1) { + memset(stream, 0, sizeof(STREAM)/sizeof(char)); + return 0; + } + + target = malloc_or_bail(size); + strcpy(target, str); // we got here, len(target) >= len(str + 1) + s->len = size-1; + s->index = 0; + s->str = target; + + stream->payload = s; + + stream->fgetc_fun = stringstream_getc; + stream->ungetc_fun = stringstream_ungetc; + stream->flush_fun = stringstream_flush; + stream->close_fun = stringstream_close; + return 1; +} + +int stringstream_getc(STREAM *stream) { + string_info *s = (string_info *)stream->payload; + if (s->index >= s->len) + return EOF; + return (int)((unsigned char)*(s->str + s->index++)); +} + +int stringstream_ungetc(int ch, STREAM *stream) { + string_info *s = (string_info *)stream->payload; + if (s->index <= 0) + return EOF; + + *(s->str + --(s->index)) = (char)ch; + return ch; +} + +int stringstream_flush(STREAM *stream) { + return 1; +} + +int stringstream_close(STREAM *stream) { + free_malloced(((string_info *)stream->payload)->str); + free_malloced(stream->payload); + return 1; +} diff --git a/src/ast-walker/stringstream.h b/src/ast-walker/stringstream.h new file mode 100644 index 0000000..e11d87d --- /dev/null +++ b/src/ast-walker/stringstream.h @@ -0,0 +1,10 @@ +#ifndef _STRINGSTREAM_H +#define _STRINGSTREAM_H 1 + +#include + +#include "t_stream.h" + +int make_stringstream(STREAM *stream, const char *str, size_t size); + +#endif /* _STRINGSTREAM_H */ diff --git a/src/ast-walker/t_stream.c b/src/ast-walker/t_stream.c index 7180f3b..6a32ced 100644 --- a/src/ast-walker/t_stream.c +++ b/src/ast-walker/t_stream.c @@ -1,9 +1,5 @@ #include "t_stream.h" -int filestream_getc(STREAM *stream); -int filestream_ungetc(int ch, STREAM *stream); -int filestream_flush(STREAM *stream); -int filestream_close(STREAM *stream); int stream_getc(STREAM *stream) { return (stream->fgetc_fun)(stream); @@ -20,30 +16,3 @@ int stream_flush(STREAM *stream) { int stream_close(STREAM *stream) { return (stream->close_fun)(stream); } - -STREAM *make_filestream(STREAM *stream, FILE *f) { - stream->payload = f; - stream->fgetc_fun = filestream_getc; - stream->ungetc_fun = filestream_ungetc; - stream->flush_fun = filestream_flush; - stream->close_fun = filestream_close; - return stream; -} - -int filestream_getc(STREAM *stream) { - return fgetc((FILE *)stream->payload); -} - -int filestream_ungetc(int ch, STREAM *stream) { - return ungetc(ch, (FILE *)stream->payload); -} - -int filestream_flush(STREAM *stream) { - return fflush((FILE *)stream->payload); -} - -int filestream_close(STREAM *stream) { - FILE *f = (FILE *)stream->payload; - stream->payload = NULL; - return fclose(f); -} diff --git a/src/ast-walker/t_stream.h b/src/ast-walker/t_stream.h index bc420ab..8ab5e98 100644 --- a/src/ast-walker/t_stream.h +++ b/src/ast-walker/t_stream.h @@ -14,7 +14,4 @@ int stream_ungetc(int ch, STREAM *stream); int stream_flush(STREAM *stream); int stream_close(STREAM *stream); -#include -STREAM *make_filestream(STREAM *stream, FILE *f); - #endif /* _T_STREAM_H */ diff --git a/src/ast-walker/token.c b/src/ast-walker/token.c index 469900e..fca4fbb 100644 --- a/src/ast-walker/token.c +++ b/src/ast-walker/token.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "errors.h" diff --git a/test/test_stringstream.c b/test/test_stringstream.c new file mode 100644 index 0000000..3fc029e --- /dev/null +++ b/test/test_stringstream.c @@ -0,0 +1,47 @@ +#include "../src/ast-walker/stringstream.c" +#include "../src/ast-walker/memory.h" +#include "../src/ast-walker/memory.c" +#include "../src/ast-walker/t_stream.h" +#include "../src/ast-walker/t_stream.c" + +#include + +int main(void) { + STREAM s; + const char *tmp = "hej pa dig"; + int ch, i; + + make_stringstream(&s, tmp, strlen(tmp)+1); + + while((ch = stream_getc(&s)) != EOF) + putchar(ch); + + printf("END\n"); + stream_close(&s); + + printf("%s\n", tmp); + + make_stringstream(&s, tmp, strlen(tmp)+1); + for (i = 0; i < 4; i++) + ch = stream_getc(&s); + + stream_ungetc('.', &s); + stream_ungetc('J', &s); + stream_ungetc('O', &s); + stream_ungetc('H', &s); + + ch = stream_ungetc('2', &s); + if (ch != EOF) { + printf("Should get EOF\n"); + } else { + printf("All ok, got EOF\n"); + } + + printf("UNCHANGED: %s\n", tmp); + + while((ch = stream_getc(&s)) != EOF) + putchar(ch); + printf("END\n"); + + stream_close(&s); +}