commit 52f831c3b92ef9644613765296a1279d8370391c Author: Ringo Watanabe Date: Sat Feb 23 01:32:22 2019 +0000 Initial commit diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e8cbc80 --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +SOURCE:= src/*.c +TEST_SOURCE:= src/test/*.c +INCLUDE:= include/ +CFLAGS:= -Wall --std=gnu99 +OBJ:= obj +BUILD:= build +LFLAGS:= -L./$(BUILD) -lse + +all: clean libse test + +clean: + rm -f $(BUILD)/* + rm -f $(OBJ)/* + +libse: + gcc -c $(SOURCE) -I$(INCLUDE) $(CFLAGS) + mv *.o $(OBJ)/ + ar rcs $(BUILD)/$@.a $(OBJ)/*.o + ranlib $(BUILD)/$@.a + +test: + gcc $(TEST_SOURCE) -I$(INCLUDE) $(CFLAGS) -o $(BUILD)/$@ $(LFLAGS) + $(BUILD)/$@ diff --git a/build/.gitkeep b/build/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/include/internal/exstring.h b/include/internal/exstring.h new file mode 100644 index 0000000..b8dd48c --- /dev/null +++ b/include/internal/exstring.h @@ -0,0 +1,30 @@ +/* Simple extendable string. + * I think this doesn't leak? + */ +#ifndef _EXSTRING_H +#define _EXSTRING_H +#include + +typedef struct { + size_t currentSize; + + char cstr[]; +} exStringOpt; + +typedef char* exString; + +#define EXS(s) (* (char**)(s)) + +exString* exs_new(const char* from); +exString* exs_clone(exString* from); +void exs_free(exString* str); +void exs_nappend(exString* str, const char* from, size_t length); +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_recalc(exString* str); +void exs_reset(exString * str); + +#endif /* _EXSTRING_H */ diff --git a/include/libse.h b/include/libse.h new file mode 100644 index 0000000..c59aeb3 --- /dev/null +++ b/include/libse.h @@ -0,0 +1,27 @@ +#ifndef _LIBSE_H +#define _LIBSE_H +#include + +typedef struct { + void* ptr; + int size; + int alloced; + + int sexpr; +} car_t; + +typedef struct cons { + union { + void* ptr; + car_t car; + }; + struct cons* cdr; +} list_t; + +//TODO: String quoting & escaping. + +list_t* se_parse(const char* sexpr); //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. + +#endif /* _LIBSE_H */ diff --git a/obj/.gitkeep b/obj/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/exstring.c b/src/exstring.c new file mode 100644 index 0000000..e5297ec --- /dev/null +++ b/src/exstring.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include + +#include + +#define min(x,y) ((x)<(y)?(x):(y)) +#define ceil(x, to) \ + ((((x) + (to) - 1) / (to)) * (to)) + +#define GETOPT(str) ((exStringOpt*) (((byte*)*(str))-sizeof(exStringOpt))) +typedef unsigned char byte; + +exString* exs_new(const char* from) +{ + if(from&&!from[0]) return exs_new(NULL); + + size_t deflen = (!from?0:strlen(from))+1; + + exStringOpt *tr = malloc(sizeof(exStringOpt) + deflen); + memset(tr,0,sizeof(exStringOpt) +deflen); + + tr->currentSize = deflen; + + if(from) strncpy(tr->cstr, from, deflen-1); + else tr->cstr[0] = 0; + + exString *ret = malloc(sizeof(exString)); + + *ret = (exString)tr->cstr; + + return ret; +} + +void exs_free(exString* str) +{ + exStringOpt *opt = GETOPT(str); + + free(opt); + free(str); +} + +static char* _exs_extend(exString* str, size_t to) +{ + exStringOpt *opt = GETOPT(str); + + assert(to>opt->currentSize); + + opt = realloc(opt, sizeof(exStringOpt)+to); + memset(opt->cstr+opt->currentSize, 0, to-opt->currentSize); + + size_t oldSize = opt->currentSize; + + opt->currentSize= to; + + *str = opt->cstr; + + return opt->cstr+oldSize; +} + +void exs_nappend(exString* str, const char* from, size_t length) +{ + size_t beflen = GETOPT(str)->currentSize-1; + size_t addlen = length; + + if(addlen<1) return; + + char *cpit = _exs_extend(str, beflen+addlen+1); + + strncpy(cpit-1, from, addlen); +} + +size_t exs_realsize(exString* str) +{ + return GETOPT(str)->currentSize; +} + +void exs_append(exString* str, const char* from) +{ + return exs_nappend(str, from, strlen(from)); +} + +exString* exs_clone(exString* str) +{ + return exs_new(*str); +} + +void exs_appendf(exString* str, const char* fmt, ...) +{ + va_list va; + va_start(va, fmt); + + size_t sz = vsnprintf(NULL, 0, fmt, va); + char buf[sz+2]; + buf[sz+1]=0; + vsnprintf(buf, sz+1, fmt, va); + + va_end(va); + + exs_nappend(str, buf, sz); +} + +void exs_reduce(exString *str, size_t sz) +{ + exStringOpt *opt = GETOPT(str); + + if(opt->currentSize-sz<0) exs_reduce(str, opt->currentSize); + else if(opt->currentSize-sz==0) { + opt = realloc(opt, sizeof(exStringOpt)+1); + opt->cstr[0] = 0; + opt->currentSize = 1; + *str = opt->cstr; + } + else { + size_t ns = opt->currentSize-sz; + opt = realloc(opt, sizeof(exStringOpt)+ns);//+1 is already in currentSize; + opt->cstr[ns-1] = 0; + opt->currentSize = ns; + *str = opt->cstr; + } +} + +void exs_appendtimes(exString *str, char c, int times) +{ + if(!times) return; + else if(times==1) exs_nappend(str, &c, 1); + else { + char* buf = _exs_extend(str, GETOPT(str)->currentSize+times); + memset(buf-1, (byte)c, times); + } +} + +void exs_recalc(exString* str) +{ + register int i=0; + int pos =-1; + for(;icurrentSize;i++) + if(!EXS(str)[i]) { pos = i; break; } + if(pos<0 || pos == GETOPT(str)->currentSize-1) return; + else + exs_reduce(str, GETOPT(str)->currentSize-pos); + +} + +void exs_reset(exString *str) +{ + exs_reduce(str, GETOPT(str)->currentSize); +} diff --git a/src/libse.c b/src/libse.c new file mode 100644 index 0000000..d5be180 --- /dev/null +++ b/src/libse.c @@ -0,0 +1,123 @@ +#include +#include + +#include +#include + +static void _addcar(list_t* out, exString* token) +{ +#ifdef SE_PARSE_NIL + if(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) +{ + list_t* out = malloc(sizeof(list_t)); + memset(out,0,sizeof(list_t)); + exString *token = exs_new(NULL); + + while(*sexpr) { + if(*sexpr==' ') { + if(strlen(EXS(token))>0) { + _addcar(out, token); + + if(*(sexpr+1)) + out->cdr = _parse_list(sexpr, lp); + else out->cdr =NULL; + break; + } + } + else if(*sexpr == ')') + { + _addcar(out, token); + 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; + } + else + exs_nappend(token, sexpr, 1); + sexpr+=1; + (*lp)+=1; + } + + if(strlen(EXS(token))>0) + _addcar(out, token); + else if(!out->ptr && !out->cdr) { + free(out); + out=NULL; + } + + exs_free(token); + return out; +} + +list_t* se_parse(const char* str) +{ + int lp=0; + return _parse_list(str,&lp); +} + +void _list_tostring(exString *out, const list_t* list) +{ + if(!list->ptr) + exs_append(out, "nil"); + else if(list->car.sexpr) { + exs_append(out, "("); + _list_tostring(out, (list_t*)list->ptr); + } + else exs_append(out,(char*)list->ptr); + + if(list->cdr) + { + exString *wtf = exs_new(NULL); + _list_tostring(wtf, list->cdr); + if(EXS(wtf)[0]!=')') + exs_append(out, " "); + exs_append(out, EXS(wtf)); + exs_free(wtf); + } + else exs_append(out, ")"); +} + +void se_print(FILE* fp, const list_t* list) +{ + if(fp == NULL) fp = stdout; + exString* str = exs_new("("); + _list_tostring(str, list); + fprintf(fp, "%s", EXS(str)); + exs_free(str); +} + +void se_free(list_t* list) +{ + if(list->cdr) se_free(list->cdr); + if(list->ptr && list->car.alloced) + free(list->ptr); + free(list); +} diff --git a/src/test/main.c b/src/test/main.c new file mode 100644 index 0000000..4b60084 --- /dev/null +++ b/src/test/main.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include + +void test_exs() +{ + exString *test= exs_new(NULL); + + printf("New success\n"); + + exs_append(test, "Hello"); + exs_append(test, " world."); + + exs_append(test, " Test, "); + exs_append(test, "two, three. FOUR FIVE."); + + exs_reduce(test, 5); + + EXS(test)[strlen(EXS(test))-5] = 0; + + exs_recalc(test); + + exs_append(test, " Scream: "); + + exs_appendtimes(test, 'A', 6); + + exs_appendf(test, "\nCurrent size: %d -> %d", strlen(EXS(test)), exs_realsize(test)); + exs_appendf(test, "AOISDJOAIJS%s", "sokdok"); + + printf("%s\n", EXS(test)); + + printf("strlen() %d, ->currentSize %d\n", strlen(EXS(test)), exs_realsize(test)); + + exs_free(test); +} + +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"); + + se_print(NULL, list); + printf("\n"); +// printf("(car list) -> %s\n", (char*)list->ptr); +// printf("(cadr list) -> %s\n", (list->cdr?(char*)list->cdr->ptr:"nil")); + + se_free(list); +} + +int main() +{ +// test_exs(); + test_parse(); + return 0; +}