#include #include #include #include #include "read.h" #include "strbst.h" #include "nodelink.h" #include "ll.h" static void consumespaces(FILE* file) { // used to consume spaces in an item ("- list item" -> "list item") int c; while ( ( c = fgetc(file) ) != EOF && c == ' ' ); ungetc(c, file); } static void wsclean(char* txt, size_t* sz){ // "string\n \n" -> "string\n" (must always end with \n) for (; *sz > 0; (*sz)--) { // start at end [i-1] and dec if (txt[*sz-1] != ' ' && txt[*sz-1] != '\n') break; } txt[*sz] = '\n'; txt[*sz+1] = 0;// finish string } static char* empty(void) { // "" with a freeable memory address char* str = malloc(sizeof(char)); *str = 0; return str; } static char* getline(size_t* n, FILE* file) { // Can probably be improved by using posix file apis size_t sz = 100; *n = 0; int c; char* out = malloc(sizeof(char)*sz); while ( (c = fgetc(file)) != EOF ) { if (*n == sz-1) out = realloc(out, sizeof(char) * (sz *= 2)); out[*n] = c; (*n)++; if (c == '\n') break; } out[*n] = 0; return realloc(out, sizeof(char) * (*n+1) ); } static char* line(FILE* file, bool nl) { // gets a line from file size_t n; char* link = getline(&n, file); // getline stores a line of len n (size n+1) in link wsclean(link, &n); // removes trailing whitespace if (n == 0) { // "\n" => "" free(link); return empty(); } else { // else return obtained if (!nl) link[n] = 0; //truncate the newline return link; } } static link* insorget(strbst* tgt, char* name, bool tofree) { link* get = query(tgt, name); if (!get) { get = newlink(newnode()); insbst(tgt, name, get); } else if (tofree) { free(name); } return get; } static link* addbstlink(strbst* tree, char* name, node* to, bool f) { link* l = query(tree, name); if (l && f) { free(name); return l; } l = newlink(to); insbst(tree, name, l); return l; } static char* resolvell(llnode* tail, size_t sz) { char *out, *pos; pos = out = malloc(sizeof(char)*(sz+1)); out[sz] = 0; while (tail != NULL) { size_t len = strlen(tail->str); memcpy(pos, tail->str, len); pos += len; llnode* tmp = tail; tail = tail->next; free(tmp->str); free(tmp); } return out; } static void stradd(char** orig, char* new) { // new is freed size_t nsz = strlen(new)+1; size_t olen = strlen(*orig); *orig = realloc(*orig,olen+nsz); memcpy(*orig+olen,new,nsz); free(new); } node* readfile(char* name) { FILE* read = fopen(name, "r"); node *root, *cur; cur = root = newnode(); link* curl = addbstlink(root->links, "", root, false); llnode start; start.next = NULL; // empty desc isn't undefined llnode *head, *tail; head = tail = &start; size_t sz = 0; int c; while ( ( c = fgetc(read) ) != EOF ) { if (c == ':' || c == '-') { stradd(&(curl->desc),resolvell(head->next, sz)); head->next = NULL; tail = head; sz = 0; consumespaces(read); } switch (c) { case ':': curl = insorget(root->links, line(read, false), true); cur = curl->to; break; case '-': ; // ': ;' (empty expr) needed before 'char*' char* lname = line(read, false); node* at = insorget(root->links, lname, false)->to; curl = addbstlink(cur->links, lname, at, true); break; case '!': ; char* l = line(read,false); FILE* f = fopen(l,"r"); if (!f) { printf("Failed to open %s\n",l); break; } char* ln; size_t n; while ( *(ln = getline(&n,f)) ) { if (*ln=='\n'){ free(ln); ln = empty(); sz -= n; } tail = appendll(tail, ln); sz += n; } fclose(f); break; default: ungetc(c, read); case '.': tail = appendll(tail, line(read, true)); // TODO: appendll should change strlen, and // line() needs to return a size sz += strlen(tail->str); break; } } stradd(&(curl->desc),resolvell(head->next, sz)); fclose(read); return root; }