commit
52f831c3b9
@ -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)/$@
|
@ -0,0 +1,30 @@
|
|||||||
|
/* Simple extendable string.
|
||||||
|
* I think this doesn't leak?
|
||||||
|
*/
|
||||||
|
#ifndef _EXSTRING_H
|
||||||
|
#define _EXSTRING_H
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
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 */
|
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef _LIBSE_H
|
||||||
|
#define _LIBSE_H
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
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 */
|
@ -0,0 +1,150 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <internal/exstring.h>
|
||||||
|
|
||||||
|
#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(;i<GETOPT(str)->currentSize;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);
|
||||||
|
}
|
@ -0,0 +1,123 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <libse.h>
|
||||||
|
#include <internal/exstring.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
#include <libse.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <internal/exstring.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
Loading…
Reference in new issue