123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616 |
- #include <u.h>
- #include <libc.h>
- #include <thread.h>
- #include <bio.h>
- #include <ctype.h>
- #include "object.h"
- #include "catset.h"
- #include "parse.h"
- #define MAXTOKEN 1024
- Biobuf *f;
- static int str;
- char *file;
- Token tokenlistinit[] = {
- { "category", Obj, Category , "music" , {nil,0}},
- { "cddata", Obj, Cddata , nil , {nil,0}},
- { "command", Obj, Cmd , nil , {nil,0}},
- { "file", Obj, File , "file" , {nil,0}},
- { "include", Obj, Include , nil , {nil,0}},
- { "key", Obj, Key , nil , {nil,0}},
- { "lyrics", Obj, Lyrics , "lyrics" , {nil,0}},
- { "part", Obj, Part , "title" , {nil,0}},
- { "path", Obj, Path , nil , {nil,0}},
- { "performance",Obj, Performance , "artist" , {nil,0}},
- { "recording", Obj, Recording , "title" , {nil,0}},
- { "root", Obj, Root , nil , {nil,0}},
- { "search", Obj, Search , nil , {nil,0}},
- { "soloists", Obj, Soloists , "artist" , {nil,0}},
- { "time", Obj, Time , "time" , {nil,0}},
- { "track", Obj, Track , "title" , {nil,0}},
- { "work", Obj, Work , "title" , {nil,0}},
- };
- Token *tokenlist;
- int ntoken = nelem(tokenlistinit);
- int catnr = 0;
- Cmdlist cmdlist[] = {
- { Sort, "sort" },
- { Enum, "number" },
- { 0x00, 0 },
- };
- static char *curtext;
- void
- inittokenlist(void)
- {
- int i;
- ntoken = nelem(tokenlistinit);
- tokenlist = malloc(sizeof(tokenlistinit));
- memmove(tokenlist, tokenlistinit, sizeof(tokenlistinit));
- for(i = 0; i< ntoken; i++){
- tokenlist[i].name = strdup(tokenlist[i].name);
- catsetinit(&tokenlist[i].categories, tokenlist[i].value);
- }
- curtext = smprint("{");
- }
- Type
- gettoken(char *token)
- {
- char *p, *q;
- int i, n;
- Token *t;
- for(;;){
- if(curtext){
- p = &curtext[strspn(curtext, " \t")];
- if(*p && *p != '\n')
- break;
- }
- do {
- str++;
- free(curtext);
- if((curtext = Brdstr(f, '\n', 0)) == nil)
- return Eof;
- } while(curtext[0] == '#');
- }
- if(*p == '{'){
- *token++ = *p;
- *token = 0;
- *p = ' ';
- return BraceO;
- }
- if(*p == '}'){
- *token++ = *p;
- *token = 0;
- *p = ' ';
- return BraceC;
- }
- if(*p == '='){
- *token++ = *p;
- *token = 0;
- *p = ' ';
- return Equals;
- }
- t = nil;
- n = 0;
- for(i = 0; i < ntoken; i++){
- t = &tokenlist[i];
- if(strncmp(p, t->name, n=strlen(t->name)) == 0){
- q = &p[n];
- if(isalnum(*q) || *q == '-') continue;
- q += strspn(q, " \t");
- if(t->kind == Obj && *q == '{')
- break;
- if(t->kind == Cat && *q == '=')
- break;
- }
- }
- if(i < ntoken){
- strcpy(token, t->name);
- memset(p, ' ', n);
- return i;
- }
- assert(strlen(token) < MAXTOKEN);
- if(strchr(p, '{'))
- sysfatal("Illegal keyword or parse error: %s", p);
- if((q = strchr(p, '='))){
- if(q == p) goto tx;
- *q = 0;
- strcpy(token, p);
- assert(strlen(token) < MAXTOKEN);
- memset(p, ' ', q-p);
- *q = '=';
- for(q = token; *q; q++)
- if(!isalnum(*q) && !isspace(*q)) break;
- if(*q) return Txt;
- while(isspace(*--q)) *q = 0;
- return Newcat;
- }
- tx: if((q = strchr(p, '}'))){
- *q = 0;
- strcpy(token, p);
- assert(strlen(token) < MAXTOKEN);
- memset(p, ' ', q-p);
- *q = '}';
- return Txt;
- }
- strcpy(token, p);
- assert(strlen(token) < MAXTOKEN);
- free(curtext);
- curtext = nil;
- return Txt;
- }
- Object *
- getobject(Type t, Object *parent)
- {
- char *token;
- char *textbuf;
- char *tp, *p, *q;
- int i;
- Object *o, *oo, *child;
- Token *ot;
- Type nt;
- token = malloc(MAXTOKEN);
- textbuf = malloc(8192);
- tp = textbuf;
- o = newobject(t, parent);
- o->flags |= Hier;
- if(parent == nil){
- root = o;
- o->path = strdup(startdir);
- setmalloctag(o->path, 0x100001);
- }
- if(gettoken(token) != BraceO)
- sysfatal("Parse error: no brace, str %d", str);
- for(;;){
- t = gettoken(token);
- if(t >= 0)
- switch(tokenlist[t].kind){
- case Obj:
- switch(t){
- case Key:
- case Cmd:
- case Path:
- if(getobject(t, o) != nil)
- sysfatal("Non-null child?");
- break;
- case Include:
- case Category:
- child = getobject(t, o);
- if(child) addchild(o, child, "case Category");
- break;
- default:
- /* subobject */
- child = getobject(t, o);
- if(child == nil)
- sysfatal("Null child?");
- addchild(o, child, "default");
- break;
- }
- break;
- case Cat:
- catcase: nt = gettoken(token);
- if(nt != Equals)
- sysfatal("Expected Equals, not %s", token);
- nt = gettoken(token);
- if(nt != Txt)
- sysfatal("Expected Text, not %s", token);
- if((p = strchr(token, '\n'))) *p = 0;
- p = token;
- if(o->type == Category){
- if(catsetisset(&o->categories)){
- fprint(2, "Category object must have one category\n");
- }
- catsetcopy(&o->categories, &tokenlist[t].categories);
- strncpy(o->key, p, KEYLEN);
- if(catobjects[t] == 0)
- sysfatal("Class %s not yet defined", tokenlist[t].name);
- for(i = 0; i < catobjects[t]->nchildren; i++)
- if(strcmp(catobjects[t]->children[i]->key, p) == 0)
- break;
- if(i == catobjects[t]->nchildren){
- /* It's a new key for the category */
- addchild(catobjects[t], o, "new key for cat");
- }else{
- /* Key already existed */
- oo = catobjects[t]->children[i];
- if(oo->value)
- sysfatal("Duplicate category object for %s", oo->value);
- catobjects[t]->children[i] = o;
- if(oo->nchildren){
- for(i = 0; i < oo->nchildren; i++){
- if(oo->children[i]->parent == oo)
- oo->children[i]->parent = o;
- addchild(o, oo->children[i], "key already existed");
- }
- }
- freeobject(oo, "a");
- }
- o->parent = catobjects[t];
- }else{
- catsetorset(&o->categories, &tokenlist[t].categories);
- for(i = 0; i < catobjects[t]->nchildren; i++)
- if(strcmp(catobjects[t]->children[i]->key, p) == 0)
- break;
- if(i == catobjects[t]->nchildren){
- oo = newobject(Category, catobjects[t]);
- /*
- oo->value = strdup(token);
- */
- strncpy(oo->key, p, KEYLEN);
- catsetcopy(&oo->categories, &tokenlist[t].categories);
- addchild(catobjects[t], oo, "catobjects[t],oo");
- }
- addchild(catobjects[t]->children[i], o, "children[i]");
- }
- break;
- }
- else
- switch(t){
- case Eof:
- if(o->type == Root){
- free(token);
- free(textbuf);
- return o;
- }
- sysfatal("Unexpected Eof in %s, file %s", tokenlist[o->type].name, file);
- case Newcat:
- /* New category, make an entry in the tokenlist */
- tokenlist = realloc(tokenlist, (ntoken+1)*sizeof(Token));
- ot = &tokenlist[ntoken];
- ot->name = strdup(token);
- setmalloctag(ot->name, 0x100002);
- ot->kind = Cat;
- ot->value = -1;
- memset(&ot->categories, 0, sizeof(Catset));
- catsetinit(&ot->categories, catnr++);
- /* And make an entry in the catobjects table */
- if(ncat <= ntoken){
- catobjects = realloc(catobjects, (ntoken+1)*sizeof(Object*));
- while(ncat <= ntoken) catobjects[ncat++] = nil;
- }
- if(catobjects[ntoken] != nil)
- sysfatal("Class %s already defined in %s:%d", token, file, str);
- if(0) fprint(2, "newcat: token %s catnr %d ntoken %d ncat %d\n",
- token, catnr, ntoken, ncat);
- catobjects[ntoken] = newobject(Category, root);
- if(o->type == Category)
- catobjects[ntoken]->flags = o->flags&Hier;
- catobjects[ntoken]->flags |= Sort;
- strncpy(catobjects[ntoken]->key, token, KEYLEN);
- catsetcopy(&catobjects[ntoken]->categories, &ot->categories);
- addchild(root, catobjects[ntoken], "root");
- t = ntoken;
- ntoken++;
- goto catcase;
- case Txt:
- strcpy(tp, token);
- tp += strlen(token);
- break;
- case BraceC:
- while(tp > textbuf && tp[-1] == '\n') *--tp = 0;
- if((o->type == File || o->type == Include) && o->path){
- o->value = smprint("%s/%s", o->path, textbuf);
- }else if(tp > textbuf){
- o->value = strdup(textbuf);
- setmalloctag(o->value, 0x100003);
- }
- switch(o->type){
- case Cmd:
- q = strtok(o->value, " \t,;\n");
- while(q){
- if(*q) for(i = 0; cmdlist[i].name; i++){
- if(strcmp(q, cmdlist[i].name) == 0){
- o->parent->flags |= cmdlist[i].flag;
- break;
- }
- if(cmdlist[i].name == 0)
- fprint(2, "Unknown command: %s\n", q);
- }
- q = strtok(nil, " \t,;\n");
- }
- freeobject(o, "b");
- free(token);
- free(textbuf);
- return nil;
- case Path:
- p = o->value;
- free(o->parent->path);
- if(p[0] == '/' || o->path == nil){
- o->parent->path = strdup(p);
- setmalloctag(o->parent->path, 0x100004);
- }else{
- o->parent->path = smprint("%s/%s", o->path, p);
- setmalloctag(o->parent->path, 0x100005);
- }
- freeobject(o, "b");
- free(token);
- free(textbuf);
- return nil;
- case Include:
- free(token);
- free(textbuf);
- return getinclude(o);
- case Category:
- /*
- if(o->nchildren) break;
- */
- free(token);
- free(textbuf);
- return nil;
- case Key:
- strncpy(o->parent->key, o->value, KEYLEN);
- freeobject(o, "d");
- free(token);
- free(textbuf);
- return nil;
- default:
- break;
- }
- free(token);
- free(textbuf);
- return o;
- default:
- fprint(2, "Unexpected token: %s\n", token);
- free(token);
- free(textbuf);
- return nil;
- }
- }
- }
- Object *
- getinclude(Object *o)
- {
- char *savetext;
- Biobuf *savef = f;
- char *savefile, fname[256];
- Object *oo;
- int savestr = str;
- char token[MAXTOKEN], *dirname, *filename;
- Type t;
- str = 0;
- if(curtext){
- savetext = strdup(curtext);
- setmalloctag(savetext, 0x100006);
- }else
- savetext = nil;
- if((f = Bopen(o->value, OREAD)) == nil)
- sysfatal("getinclude: %s: %r", o->value);
- savefile = file;
- file = strdup(o->value);
- strncpy(fname, o->value, 256);
- if((filename = strrchr(fname, '/'))){
- *filename = 0;
- dirname = fname;
- filename++;
- }else{
- dirname = "";
- filename = fname;
- }
- while((t = gettoken(token)) != Eof){
- if(t < 0){
- if(*dirname)
- sysfatal("Bad include file %s/%s, token %s, str %d",
- dirname, filename, token, str);
- else
- sysfatal("Bad include file %s, token %s, str %d",
- filename, token, str);
- }
- free(o->path);
- o->path = strdup(dirname);
- setmalloctag(o->path, 0x100007);
- oo = getobject(t, o->parent);
- if(oo) addchild(o->parent, oo, "o->parent, oo");
- }
- freeobject(o, "e");
- free(curtext);
- curtext = nil;
- if(savetext)
- curtext = savetext;
- free(file);
- file = savefile;
- str = savestr;
- Bterm(f);
- f = savef;
- return nil;
- }
- void
- addchild(Object *parent, Object *child, char *where)
- {
- int i;
- /* First check if child's already been added
- * This saves checking elsewhere
- */
- for(i = 0; i < parent->nchildren; i++)
- if(parent->children[i] == child) return;
- parent->children = realloc(parent->children, (i+1)*4);
- parent->children[i] = child;
- parent->nchildren++;
- if(parent->type == Category && child->type == Category)
- return;
- if(parent->type == Work && child->type == Work)
- return;
- if(parent->type == Work && child->type == Track)
- return;
- if(parent->type == Track && child->type == File)
- return;
- if(child->parent == child)
- return;
- if(parent->type == Root)
- return;
- if(parent->parent->type == Root)
- return;
- // addcatparent(parent, child);
- i = child->ncatparents;
- if(0) fprint(2, "addcatparent %s parent %d type %d child %d type %d\n",where,
- parent->tabno, parent->type, child->tabno, child->type);
- child->catparents = realloc(child->catparents, (i+1)*4);
- child->catparents[i] = parent;
- child->ncatparents++;
- }
- void
- addcatparent(Object *parent, Object *child)
- {
- int i;
- /* First check if child's already been added
- * This saves checking elsewhere
- */
- if(child->parent == child)
- return;
- // for(i = 0; i < child->ncatparents; i++)
- // if(child->catparents[i] == parent) return;
- i = child->ncatparents;
- fprint(2, "addcatparent parent %d child %d\n", parent->tabno, child->tabno);
- child->catparents = realloc(child->catparents, (i+1)*4);
- child->catparents[i] = parent;
- child->ncatparents++;
- }
- void
- sortprep(char *out, int n, Object *o)
- {
- char *p, *q;
- if(*o->key)
- q = o->key;
- else if (o->value)
- q = o->value;
- else
- q = "";
- if(p = strchr(q, '~'))
- p++;
- else
- p = q;
- for(q = out; *p && q < out+n-1; q++)
- *q = tolower(*p++);
- *q = 0;
- }
- void
- childsort(Object *o)
- {
- Object *oo;
- int i, j, n;
- char si[256], sj[256];
- /* sort the kids by key or by value */
- n = o->nchildren;
- if(n > 1){
- for(i = 0; i < n-1; i++){
- sortprep(si, nelem(si), o->children[i]);
- for(j = i+1; j < n; j++){
- sortprep(sj, nelem(sj), o->children[j]);
- if(strncmp(si, sj, sizeof(si)) > 0){
- oo = o->children[i];
- o->children[i] = o->children[j];
- o->children[j] = oo;
- strncpy(si, sj, sizeof(si));
- }
- }
- }
- }
- }
- void
- childenum(Object *o){
- Object *oo;
- int i, n = 1;
- for(i = 0; i < o->nchildren; i++){
- oo = o->children[i];
- if(tokenlist[oo->type].kind == Cat)
- oo->num = n++;
- else
- switch(oo->type){
- case Category:
- case Part:
- case Recording:
- case Track:
- case Work:
- oo->num = n++;
- default:
- break;
- }
- }
- }
- Object *
- newobject(Type t, Object *parent){
- Object *o;
- int tabno;
- if(hotab){
- for(tabno = 0; tabno < notab; tabno++)
- if(otab[tabno] == nil)
- break;
- if(tabno == notab)
- sysfatal("lost my hole");
- hotab--;
- }else{
- if(sotab < notab+1){
- sotab += 512;
- otab = realloc(otab, sizeof(Object*)*sotab);
- if(otab == nil)
- sysfatal("realloc: %r");
- }
- tabno = notab++;
- }
- o = mallocz(sizeof(Object), 1);
- o->tabno = tabno;
- otab[tabno] = o;
- o->type = t;
- o->parent = parent;
- if(parent && parent->path){
- o->path = strdup(parent->path);
- setmalloctag(o->path, 0x100008);
- }
- return o;
- }
- void
- freeobject(Object *o, char*){
- free(o->children);
- if(o->orig == nil)
- free(o->value);
- free(o->path);
- free(o->catparents);
- catsetfree(&o->categories);
- otab[o->tabno] = nil;
- hotab++;
- free(o);
- }
- void
- freetree(Object *o)
- {
- int i;
- for(i = 0; i < o->nchildren; i++)
- if(o->children[i]->parent == o)
- freetree(o->children[i]);
- free(o->children);
- if(o->orig == nil)
- free(o->value);
- free(o->path);
- free(o->catparents);
- catsetfree(&o->categories);
- otab[o->tabno] = nil;
- hotab++;
- free(o);
- }
|