]> git.eli173.com Git - klapaucius/commitdiff
very basic file io, support for escape characters
authorElijah Cohen <eli@eli173.com>
Thu, 7 Nov 2024 02:25:46 +0000 (20:25 -0600)
committerElijah Cohen <eli@eli173.com>
Thu, 7 Nov 2024 02:25:46 +0000 (20:25 -0600)
src/builtins/io.c
src/builtins/io.h
src/builtins/strings.c
src/builtins/strings.h
src/parser.c

index 25ce07bf691229b0ed3372b42b679d48fee5529b..8da2589c36eef9ae9cee0984d7be14e7ec086306 100644 (file)
@@ -52,6 +52,75 @@ Sexpr* io_print_b(Sexpr* b, Sexpr* rest, Sexpr* env) {
        return cons(from_t(), rest);
 }
 
+Sexpr* io_readfile(Sexpr* b, Sexpr* rest, Sexpr* env) {
+       if(IO_READFILE_ARGS != u64_get_num_args(b)) {
+               return cons(b, rest);
+       }
+       Sexpr* firstarg = eval(clone(car(b->value.b.args)), env);
+#ifdef TYPECHECK
+       if(firstarg->type != STR) {
+               ERR("readfile: ", "argument not a string");
+               sexpr_free(firstarg);
+               sexpr_free(b);
+               return cons(from_nil(), rest);
+       }
+#endif
+       FILE* thefile = fopen(firstarg->value.str, "r");
+       if(!thefile) {
+               ERR("readfile: file not found: ", firstarg->value.str);
+               sexpr_free(firstarg);
+               sexpr_free(b);
+               return cons(from_nil(), rest);
+       }
+       fseek(thefile, 0, SEEK_END);
+       size_t fsz = ftell(thefile);
+       fseek(thefile, 0, SEEK_SET);
+       char* buf = malloc(sizeof(char)*fsz);
+       if(!buf) {
+               ERR("readfile: ", "unable to allocate memory for file");
+               fclose(thefile);
+               return cons(from_nil(), rest);
+       }
+       fread(buf, 1, fsz, thefile);
+       fclose(thefile);
+       Sexpr* f = from_string(buf);
+       free(buf);
+       return cons(f, rest);
+}
+
+Sexpr* io_writefile(Sexpr* b, Sexpr* rest, Sexpr* env) {
+       if(IO_WRITEFILE_ARGS != u64_get_num_args(b)) {
+               return cons(b, rest);
+       }
+       Sexpr* args = b->value.b.args;
+       Sexpr* filearg = eval(clone(car(cdr(args))), env);
+       Sexpr* strarg = eval(clone(car(args)), env);
+#ifdef TYPECHECK
+       if(filearg->type != STR || strarg->type != STR) {
+               ERR("writefile: ", "arguments not strings");
+               sexpr_free(filearg);
+               sexpr_free(strarg);
+               sexpr_free(b);
+               return cons(from_nil(), rest);
+       }
+#endif
+       char* filestring = filearg->value.str;
+       FILE* thefile = fopen(filestring, "w");
+       if(!thefile) {
+               ERR("writefile: file not found: ", filestring);
+               sexpr_free(filearg);
+               sexpr_free(strarg);
+               sexpr_free(b);
+               return cons(from_nil(), rest);
+       }
+       size_t num_written = fwrite(strarg->value.str, sizeof(char), strlen(strarg->value.str), thefile);
+       fclose(thefile);
+       sexpr_free(filearg);
+       sexpr_free(strarg);
+       sexpr_free(b);
+       return cons(from_uint(num_written), rest);
+}
+
 
 Sexpr* x_io_dispatch(Sexpr* b, Sexpr* rest, Sexpr* env) {
        uint64_t code = b->value.b.opcode & 0xff;
@@ -63,6 +132,10 @@ Sexpr* x_io_dispatch(Sexpr* b, Sexpr* rest, Sexpr* env) {
                return io_printstr(b, rest, env);
        case IO_PB:
                return io_print_b(b, rest, env);
+       case IO_READFILE:
+               return io_readfile(b, rest, env);
+       case IO_WRITEFILE:
+               return io_writefile(b, rest, env);
        default:
                return from_nil();
        }
@@ -73,6 +146,8 @@ Sexpr* load_io_env(Sexpr* env) {
        load_builtin(IO_PRINT_STR, (IO_PREFIX << 8) | IO_PRINT, env);
        load_builtin(IO_PRINTSTR_STR, (IO_PREFIX << 8) | IO_PRINTSTR, env);
        load_builtin(IO_PB_STR, (IO_PREFIX << 8) | IO_PB, env);
+       load_builtin(IO_READFILE_STR, (IO_PREFIX << 8) | IO_READFILE, env);
+       load_builtin(IO_WRITEFILE_STR, (IO_PREFIX << 8) | IO_WRITEFILE, env);
 
        return env;
 }
index 7b805fe57634967ce6f5e0d9a6e2f981cfd7845d..f62db668473e79842292062050f00054af66909c 100644 (file)
 #define IO_PB 0x02
 #define IO_PB_ARGS 1
 #define IO_PB_STR "pb"
+#define IO_READFILE 0x03
+#define IO_READFILE_ARGS 1
+#define IO_READFILE_STR "readfile"
+#define IO_WRITEFILE 0x04
+#define IO_WRITEFILE_ARGS 2
+#define IO_WRITEFILE_STR "writefile"
 
 Sexpr* x_io_dispatch(Sexpr* s, Sexpr* rest, Sexpr* env);
 Sexpr* load_io_env(Sexpr* env);
index 8d2660bf52cb92edc51bb3683959135342c26017..a99e54626c1771757e3513001bd0cb6c13cd85f8 100644 (file)
@@ -152,6 +152,39 @@ Sexpr* s_substr(Sexpr* b, Sexpr* rest, Sexpr* env) {
        return cons(from_quote(newres), rest);
 }
 
+Sexpr* s_strtok(Sexpr* b, Sexpr* rest, Sexpr* env) {
+       if(STRINGS_STRTOK_ARGS != u64_get_num_args(b)) {
+               return cons(b, rest);
+       }
+       Sexpr* args = b->value.b.args;
+       Sexpr* delimex = eval(clone(car(cdr(args))), env);
+       Sexpr* strex = eval(clone(car(args)), env);
+#ifdef TYPECHECK
+       if(delimex->type != STR || strex->type != STR) {
+               ERR("strtok: ", "arguments not strings");
+               sexpr_free(delimex);
+               sexpr_free(strex);
+               sexpr_free(b);
+               return cons(from_nil(), rest);
+       }
+#endif
+       Sexpr* result = from_nil();
+       char* delim = delimex->value.str;
+       char* str = strex->value.str;
+       char* out = strtok(str, delim);
+       while(out != NULL) {
+               result = cons(from_string(out), result);
+               out = strtok(NULL, delim);
+       }
+       Sexpr* newres = reverse(result);
+       sexpr_free(b);
+       sexpr_free(delimex);
+       sexpr_free(strex);
+       sexpr_free(result);
+       return cons(from_quote(newres), rest);
+}
+
+
 Sexpr* x_strings_dispatch(Sexpr* b, Sexpr* rest, Sexpr* env) {
        uint64_t code = b->value.b.opcode & 0xff;
        switch(code) {
@@ -165,6 +198,8 @@ Sexpr* x_strings_dispatch(Sexpr* b, Sexpr* rest, Sexpr* env) {
                return s_strexpand(b, rest, env);
        case STRINGS_SUBSTR:
                return s_substr(b, rest, env);
+       case STRINGS_STRTOK:
+               return s_strtok(b, rest, env);
        default:
                return from_nil();
        }
@@ -178,5 +213,6 @@ Sexpr* load_strings_env(Sexpr* env) {
                load_builtin(STRINGS_STRAT_STR, (STRINGS_PREFIX << 8) | STRINGS_STRAT, env);
                load_builtin(STRINGS_STREXPAND_STR, (STRINGS_PREFIX << 8) | STRINGS_STREXPAND, env);
                                load_builtin(STRINGS_SUBSTR_STR, (STRINGS_PREFIX << 8) | STRINGS_SUBSTR, env);
+                               load_builtin(STRINGS_STRTOK_STR, (STRINGS_PREFIX << 8) | STRINGS_STRTOK, env);
        return env;
 }
index 76c4e0741b0d9caf9d73fb5c03be18e6a07a3ee4..f5d2defe8298690c1e8610d2f1ef2d8325e62079 100644 (file)
@@ -22,6 +22,9 @@
 #define STRINGS_SUBSTR 0x04
 #define STRINGS_SUBSTR_ARGS 2
 #define STRINGS_SUBSTR_STR "substr"
+#define STRINGS_STRTOK 0x05
+#define STRINGS_STRTOK_ARGS 2
+#define STRINGS_STRTOK_STR "strtok"
 
 Sexpr* x_strings_dispatch(Sexpr* s, Sexpr* rest, Sexpr* env);
 Sexpr* load_strings_env(Sexpr* env);
index c35f9c77507a05e1767419e5b42655c2996a5f0c..fc06b25d79ae3574a1afd8f72186ac18cc6c5c82 100644 (file)
@@ -19,6 +19,96 @@ Sexpr* append_fragment(Sexpr* tokens, char* tok_start, size_t currlen) {
        return cons(newtok, tokens);
 }
 
+char* escapify(char* s) {
+       // converts strings that are indeed supposed to be 'strings'
+       // into properly escaped versions of themselves
+       // i.e. the two-character "\n" gets converted to the single-character newline
+       char* out = malloc(sizeof(char)*strlen(s));
+       char* outidx = out;
+       char* sidx = s; // index on s
+       char tmp[3] = {0, 0, 0};
+       while(*sidx != '\0') {
+               if(*sidx == '\\') {
+                       switch(*(sidx+1)) {
+                       case '\\':
+                               *outidx = '\\';
+                               outidx++;
+                               sidx++;
+                               break;
+                       case '?':
+                               *outidx = '?';
+                               outidx++;
+                               sidx++;
+                               break;
+                       case '"':
+                               *outidx = '"';
+                               outidx++;
+                               sidx++;
+                               break;
+                       case 'n':
+                               *outidx = '\n';
+                               outidx++;
+                               sidx++;
+                               break;
+                       case 'a':
+                               *outidx = '\a';
+                               outidx++;
+                               sidx++;
+                               break;
+                       case 'b':
+                               *outidx = '\b';
+                               outidx++;
+                               sidx++;
+                               break;
+                       case 'e':
+                               *outidx = '\e';
+                               outidx++;
+                               sidx++;
+                               break;
+                       case 'f':
+                               *outidx = '\f';
+                               outidx++;
+                               sidx++;
+                               break;
+                       case 'r':
+                               *outidx = '\r';
+                               outidx++;
+                               sidx++;
+                               break;
+                       case 't':
+                               *outidx = '\t';
+                               outidx++;
+                               sidx++;
+                               break;
+                       case 'v':
+                               *outidx = '\v';
+                               outidx++;
+                               sidx++;
+                               break;
+                       case '\'':
+                               *outidx = '\'';
+                               outidx++;
+                               sidx++;
+                               break;
+                       case 'x':
+                               tmp[0] = *(sidx+2);
+                               tmp[1] = *(sidx+3);
+                               *outidx = strtol(tmp, NULL, 0x10);
+                               outidx++;
+                               sidx+=3;
+                               break;
+                       default:
+                               ERR("string literal escape: ", "not supported");
+                       }
+               }
+               else {
+                       *outidx = *sidx;
+                       outidx++;
+               }
+               sidx++;
+       }
+       return out;
+}
 
 Sexpr* tokenize(char* s) {
        // note: also reverses
@@ -46,7 +136,12 @@ Sexpr* tokenize(char* s) {
                                // just mark the start, then iterate til close quote, then append?
                                // but what if uncompleted quote?
                                tok_start = s;
-                               do {s++;} while(*s != '"' && *s != '\0');
+                               do {
+                                       s++;
+                                       if(*s == '\\') {
+                                               s += 2;
+                                       }
+                               } while(*s != '"' && *s != '\0');
                                //s++;
                                tokens = append_fragment(tokens, tok_start, (s + 1 - tok_start));
                        }
@@ -97,7 +192,9 @@ Sexpr* vals_parse(Sexpr* tokens) {
                }
                else if (*s == '"') { // issa string
                        s[strlen(s) - 1] = '\0'; // replaces close quote with
-                       next = from_string(s + 1);
+                       char* escaped = escapify(s+1);
+                       next = from_string(escaped);
+                       free(escaped);
                }
                else {
                        next = from_sym(s);