diff --git a/Makefile b/Makefile index e8cbc80..385679a 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ SOURCE:= src/*.c TEST_SOURCE:= src/test/*.c INCLUDE:= include/ -CFLAGS:= -Wall --std=gnu99 +CFLAGS:= -Wall -g --std=gnu99 OBJ:= obj BUILD:= build LFLAGS:= -L./$(BUILD) -lse diff --git a/include/internal/exstring.h b/include/internal/exstring.h index b8dd48c..d0ebbf6 100644 --- a/include/internal/exstring.h +++ b/include/internal/exstring.h @@ -15,6 +15,9 @@ typedef char* exString; #define EXS(s) (* (char**)(s)) +typedef char (*exsp_select)(void* state, char mapchar); +typedef int (*exsp_where)(void* state, char mapchar); + exString* exs_new(const char* from); exString* exs_clone(exString* from); void exs_free(exString* str); @@ -23,8 +26,18 @@ void exs_append(exString* str, const char* from); void exs_appendf(exString* str, const char* fmt, ...); size_t exs_realsize(exString* str); void exs_reduce(exString* str, size_t by); -void exs_appendtimes(exString* str, char c, int times); +void exs_nappendc(exString* str, char c, int times); +void exs_appendc(exString* str, char c); void exs_recalc(exString* str); void exs_reset(exString * str); +exString* exs_where(exString* str, exsp_where func, void* state); +exString* exs_select(exString *str, exsp_select func, void* state); +void exs_whereip(exString* str, exsp_where, void* state); +void exs_selectip(exString* str, exsp_select, void* state); + +char exspf_upper(void* state, char c); +char exspf_lower(void* state, char c); +int exspf_only(void* state, char c); +int exspf_only_not(void* state, char c); #endif /* _EXSTRING_H */ diff --git a/include/libse.h b/include/libse.h index c59aeb3..ae6538d 100644 --- a/include/libse.h +++ b/include/libse.h @@ -18,9 +18,15 @@ typedef struct cons { struct cons* cdr; } list_t; -//TODO: String quoting & escaping. +#define SET_PARSE_NIL (1<<0) +#define SET_PARSE_QUOTE (1<<1) +#define SET_PARSE_ESCAPE (1<<2) +#define SET_PARSE_INSENSITIVE (1<<3) -list_t* se_parse(const char* sexpr); //Parse string into list. +#define SETP_DEFAULT (SET_PARSE_QUOTE | SET_PARSE_ESCAPE) +#define SETP_LISP (SETP_DEFAULT | SET_PARSE_INSENSITIVE | SET_PARSE_NIL) + +list_t* se_parse(const char* sexpr, unsigned int flags); //Parse string into list. void se_free(list_t* list); //Free whole list. void se_print(FILE* fp, const list_t* list); //Print list to fp, if fp is NULL, print to stdout. diff --git a/src/exstring.c b/src/exstring.c index e5297ec..caef837 100644 --- a/src/exstring.c +++ b/src/exstring.c @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -122,7 +123,7 @@ void exs_reduce(exString *str, size_t sz) } } -void exs_appendtimes(exString *str, char c, int times) +void exs_nappendc(exString *str, char c, int times) { if(!times) return; else if(times==1) exs_nappend(str, &c, 1); @@ -132,6 +133,11 @@ void exs_appendtimes(exString *str, char c, int times) } } +void exs_appendc(exString* str, char c) +{ + exs_nappendc(str, c, 1); +} + void exs_recalc(exString* str) { register int i=0; @@ -144,7 +150,71 @@ void exs_recalc(exString* str) } +exString* exs_select(exString* from, exsp_select func, void* data) +{ + exString *ret = exs_clone(from); + memset(*ret, 0, GETOPT(ret)->currentSize); + for(register int i=0;icurrentSize); + for(register int i=0,j=0;icurrentSize); } + +char exspf_upper(void* state, char c) +{ + return toupper((unsigned char)c); +} + +char exspf_lower(void* state, char c) +{ + return tolower((unsigned char)c); +} + +int exspf_only(void *state, char c) +{ + char* st = state; + for(;*st;st++) if(*st==c) return 1; + return 0; +} + +int exspf_only_not(void *state, char c) +{ + char* st = state; + for(;*st;st++) if(*st==c) return 0; + return 1; +} diff --git a/src/libse.c b/src/libse.c index d5be180..4030195 100644 --- a/src/libse.c +++ b/src/libse.c @@ -1,65 +1,93 @@ #include #include - +#include +#include #include #include -static void _addcar(list_t* out, exString* token) +static void _addcar(list_t* out, exString* token, int nil, int ucase) { -#ifdef SE_PARSE_NIL - if(strcmp(EXS(token), "nil")==0) + if(ucase) + for(char* t = *token; *t; t++) + *t = toupper((unsigned char)*t); + if(nil&&strcmp(EXS(token), "NIL")==0) out->ptr = NULL; else { -#endif out->ptr = strdup(EXS(token)); out->car.size = strlen(out->ptr); out->car.alloced = 1; exs_reset(token); -#ifdef SE_PARSE_NIL } -#endif } -static list_t* _parse_list(const char* sexpr, int* lp) +static list_t* _parse_list(const char* sexpr, int* lp, unsigned int flags) { list_t* out = malloc(sizeof(list_t)); memset(out,0,sizeof(list_t)); exString *token = exs_new(NULL); + int instr=0; + int inesc=0; + while(*sexpr) { - if(*sexpr==' ') { + if(inesc) + { + exs_nappend(token, sexpr, 1); + inesc=0; + } + else if(instr) + { + if(*sexpr=='\"') + instr=0; + else exs_nappend(token, sexpr, 1); + } + else if(*sexpr==' ' || *sexpr == '\r' || *sexpr == '\n' || *sexpr == '\t') { if(strlen(EXS(token))>0) { - _addcar(out, token); + _addcar(out, token, flags & SET_PARSE_NIL, flags & SET_PARSE_INSENSITIVE); if(*(sexpr+1)) - out->cdr = _parse_list(sexpr, lp); + out->cdr = _parse_list(sexpr, lp, flags); else out->cdr =NULL; break; } } else if(*sexpr == ')') { - _addcar(out, token); + if(**token) + _addcar(out, token, flags & SET_PARSE_NIL, flags & SET_PARSE_INSENSITIVE); out->cdr=NULL; (*lp)+=1; break; } else if(*sexpr == '(') { - int hp =0; - list_t* nc = _parse_list(sexpr+1, &hp); - out->ptr = nc; - out->car.alloced=1; - out->car.sexpr=1; - out->car.size = sizeof(list_t); - sexpr+= hp+1; - (*lp) += hp+1; - - if(*(sexpr)) - out->cdr = _parse_list(sexpr, lp); - else out->cdr =NULL; - break; + if(**token) { + _addcar(out, token, flags & SET_PARSE_NIL, flags&SET_PARSE_INSENSITIVE); + if(*(sexpr+1)) + out->cdr = _parse_list(sexpr, lp ,flags); + else out->cdr = NULL; //Invalid syntax. + break; + } + else { + int hp =0; + list_t* nc = _parse_list(sexpr+1, &hp, flags); + out->ptr = nc; + out->car.alloced=1; + out->car.sexpr=1; + out->car.size = sizeof(list_t); + sexpr+= hp+1; + (*lp) += hp+1; + + if(*(sexpr)) + out->cdr = _parse_list(sexpr, lp, flags); + else out->cdr =NULL; + break; + } } + else if(flags & SET_PARSE_QUOTE && *sexpr == '\"') + instr = 1; + else if(flags & SET_PARSE_ESCAPE && *sexpr == '\\') + inesc = 1; else exs_nappend(token, sexpr, 1); sexpr+=1; @@ -67,7 +95,7 @@ static list_t* _parse_list(const char* sexpr, int* lp) } if(strlen(EXS(token))>0) - _addcar(out, token); + _addcar(out, token, flags & SET_PARSE_NIL, flags & SET_PARSE_INSENSITIVE); else if(!out->ptr && !out->cdr) { free(out); out=NULL; @@ -77,10 +105,89 @@ static list_t* _parse_list(const char* sexpr, int* lp) return out; } -list_t* se_parse(const char* str) +static int iws(char c) +{ + switch(c) + { + case ' ': + case '\t': + case '\n': + case '\r': + return 1; + default: return 0; + } +} + +static int nows(const char* str) +{ + register int i=0; + for(;*str&&iws(*str);str++) i++; + return !*str?0:i; +} + +int se_valid(const char* str) +{ + exString* s = exs_new(str); + exs_whereip(s, &exspf_only_not, " \t\n\r"); + + char *ns = EXS(s); + int ret = *ns && !(*ns=='(' && memcmp(ns, ns+1, strlen(ns)-1)==0); + exs_free(s); + + return ret; +} + +list_t* se_parse(const char* str, unsigned int flags) +{ + if(!str) return NULL; + int lp=0,tst=0; + if(*str=='(') + str+=1; + else if( (tst=nows(str))>0) + return se_parse(str+tst, flags); + if(!se_valid(str)) return NULL; + return _parse_list(str,&lp, flags); +} + +static int _se_add_quotes(const char* inp) +{ + do { + switch (*inp) { + case '\"': + case ' ': + case ')': + case '(': + return 1; + default: break; + } + inp+=1; + } + while (*inp); + return 0; +} + +void _se_append(exString *out, const char* thing) { - int lp=0; - return _parse_list(str,&lp); + int q = _se_add_quotes(thing); + exString* str = exs_new(NULL); + + for(;*thing;thing++) + { + switch(*thing) + { + case '\"': + exs_appendc(str, '\\'); + default:break; + } + exs_nappend(str, thing, 1); + } + if(q) + { + exs_appendc(out, '\"'); + exs_appendc(str, '\"'); + } + exs_append(out, *str); + exs_free(str); } void _list_tostring(exString *out, const list_t* list) @@ -91,7 +198,7 @@ void _list_tostring(exString *out, const list_t* list) exs_append(out, "("); _list_tostring(out, (list_t*)list->ptr); } - else exs_append(out,(char*)list->ptr); + else _se_append(out,(char*)list->ptr); if(list->cdr) { diff --git a/src/test/main.c b/src/test/main.c index 4b60084..094fe52 100644 --- a/src/test/main.c +++ b/src/test/main.c @@ -23,7 +23,7 @@ void test_exs() exs_append(test, " Scream: "); - exs_appendtimes(test, 'A', 6); + exs_nappendc(test, 'A', 6); exs_appendf(test, "\nCurrent size: %d -> %d", strlen(EXS(test)), exs_realsize(test)); exs_appendf(test, "AOISDJOAIJS%s", "sokdok"); @@ -37,10 +37,28 @@ void test_exs() void test_parse() { - const char* parse = "hello (there (firend) (i) (love (you a lot))) how are (you (doing today?))"; - list_t* list = se_parse(parse); - - printf("Parse okay\n"); + FILE* fp = fopen("test.se", "rb"); + exString *buf = exs_new(NULL); + char rb[8]; + int rd=0; + memset(rb,0,sizeof(rb)); + + while( (rd=fread(rb, 1, 8, fp))>0) + { + exs_nappend(buf, rb, rd); + } + + fclose(fp); + const char* parse = EXS(buf); + //printf("%s\n", parse); + //exs_free(buf); + list_t* list = se_parse(parse, SETP_DEFAULT); + if(!list) + { + printf("Parse failed.\n"); + return; + } + //printf("Parse okay.\n"); se_print(NULL, list); printf("\n"); @@ -48,6 +66,7 @@ void test_parse() // printf("(cadr list) -> %s\n", (list->cdr?(char*)list->cdr->ptr:"nil")); se_free(list); + exs_free(buf); } int main() diff --git a/test.se b/test.se new file mode 100644 index 0000000..86a70a3 --- /dev/null +++ b/test.se @@ -0,0 +1,12 @@ +(root + ("name1" + (key value) + (key "value string") + (key value) + ) + ("name 2" + (key2 value2) + (key2 "value string 2") + (\"key4 \(\)) + ) +)