16 Token tokenlistinit[] = {
17 { "category", Obj, Category , "music" , {nil,0}},
18 { "cddata", Obj, Cddata , nil , {nil,0}},
19 { "command", Obj, Cmd , nil , {nil,0}},
20 { "file", Obj, File , "file" , {nil,0}},
21 { "include", Obj, Include , nil , {nil,0}},
22 { "key", Obj, Key , nil , {nil,0}},
23 { "lyrics", Obj, Lyrics , "lyrics" , {nil,0}},
24 { "part", Obj, Part , "title" , {nil,0}},
25 { "path", Obj, Path , nil , {nil,0}},
26 { "performance",Obj, Performance , "artist" , {nil,0}},
27 { "recording", Obj, Recording , "title" , {nil,0}},
28 { "root", Obj, Root , nil , {nil,0}},
29 { "search", Obj, Search , nil , {nil,0}},
30 { "soloists", Obj, Soloists , "artist" , {nil,0}},
31 { "time", Obj, Time , "time" , {nil,0}},
32 { "track", Obj, Track , "title" , {nil,0}},
33 { "work", Obj, Work , "title" , {nil,0}},
36 int ntoken = nelem(tokenlistinit);
52 ntoken = nelem(tokenlistinit);
53 tokenlist = malloc(sizeof(tokenlistinit));
54 memmove(tokenlist, tokenlistinit, sizeof(tokenlistinit));
55 for(i = 0; i< ntoken; i++){
56 tokenlist[i].name = strdup(tokenlist[i].name);
57 catsetinit(&tokenlist[i].categories, tokenlist[i].value);
59 curtext = smprint("{");
71 p = &curtext[strspn(curtext, " \t")];
78 if((curtext = Brdstr(f, '\n', 0)) == nil)
80 } while(curtext[0] == '#');
102 for(i = 0; i < ntoken; i++){
104 if(strncmp(p, t->name, n=strlen(t->name)) == 0){
106 if(isalnum(*q) || *q == '-') continue;
107 q += strspn(q, " \t");
108 if(t->kind == Obj && *q == '{')
110 if(t->kind == Cat && *q == '=')
115 strcpy(token, t->name);
119 assert(strlen(token) < MAXTOKEN);
121 sysfatal("Illegal keyword or parse error: %s", p);
122 if((q = strchr(p, '='))){
126 assert(strlen(token) < MAXTOKEN);
129 for(q = token; *q; q++)
130 if(!isalnum(*q) && !isspace(*q)) break;
132 while(isspace(*--q)) *q = 0;
135 tx: if((q = strchr(p, '}'))){
138 assert(strlen(token) < MAXTOKEN);
144 assert(strlen(token) < MAXTOKEN);
151 getobject(Type t, Object *parent)
157 Object *o, *oo, *child;
161 token = malloc(MAXTOKEN);
162 textbuf = malloc(8192);
165 o = newobject(t, parent);
169 o->path = strdup(startdir);
170 setmalloctag(o->path, 0x100001);
172 if(gettoken(token) != BraceO)
173 sysfatal("Parse error: no brace, str %d", str);
177 switch(tokenlist[t].kind){
183 if(getobject(t, o) != nil)
184 sysfatal("Non-null child?");
188 child = getobject(t, o);
189 if(child) addchild(o, child, "case Category");
193 child = getobject(t, o);
195 sysfatal("Null child?");
196 addchild(o, child, "default");
201 catcase: nt = gettoken(token);
203 sysfatal("Expected Equals, not %s", token);
204 nt = gettoken(token);
206 sysfatal("Expected Text, not %s", token);
207 if((p = strchr(token, '\n'))) *p = 0;
209 if(o->type == Category){
210 if(catsetisset(&o->categories)){
211 fprint(2, "Category object must have one category\n");
213 catsetcopy(&o->categories, &tokenlist[t].categories);
214 strncpy(o->key, p, KEYLEN);
215 if(catobjects[t] == 0)
216 sysfatal("Class %s not yet defined", tokenlist[t].name);
217 for(i = 0; i < catobjects[t]->nchildren; i++)
218 if(strcmp(catobjects[t]->children[i]->key, p) == 0)
220 if(i == catobjects[t]->nchildren){
221 /* It's a new key for the category */
222 addchild(catobjects[t], o, "new key for cat");
224 /* Key already existed */
225 oo = catobjects[t]->children[i];
227 sysfatal("Duplicate category object for %s", oo->value);
228 catobjects[t]->children[i] = o;
230 for(i = 0; i < oo->nchildren; i++){
231 if(oo->children[i]->parent == oo)
232 oo->children[i]->parent = o;
233 addchild(o, oo->children[i], "key already existed");
238 o->parent = catobjects[t];
240 catsetorset(&o->categories, &tokenlist[t].categories);
241 for(i = 0; i < catobjects[t]->nchildren; i++)
242 if(strcmp(catobjects[t]->children[i]->key, p) == 0)
244 if(i == catobjects[t]->nchildren){
245 oo = newobject(Category, catobjects[t]);
247 oo->value = strdup(token);
249 strncpy(oo->key, p, KEYLEN);
250 catsetcopy(&oo->categories, &tokenlist[t].categories);
251 addchild(catobjects[t], oo, "catobjects[t],oo");
253 addchild(catobjects[t]->children[i], o, "children[i]");
265 sysfatal("Unexpected Eof in %s, file %s", tokenlist[o->type].name, file);
267 /* New category, make an entry in the tokenlist */
268 tokenlist = realloc(tokenlist, (ntoken+1)*sizeof(Token));
269 ot = &tokenlist[ntoken];
270 ot->name = strdup(token);
271 setmalloctag(ot->name, 0x100002);
274 memset(&ot->categories, 0, sizeof(Catset));
275 catsetinit(&ot->categories, catnr++);
276 /* And make an entry in the catobjects table */
278 catobjects = realloc(catobjects, (ntoken+1)*sizeof(Object*));
279 while(ncat <= ntoken) catobjects[ncat++] = nil;
281 if(catobjects[ntoken] != nil)
282 sysfatal("Class %s already defined in %s:%d", token, file, str);
283 if(0) fprint(2, "newcat: token %s catnr %d ntoken %d ncat %d\n",
284 token, catnr, ntoken, ncat);
285 catobjects[ntoken] = newobject(Category, root);
286 if(o->type == Category)
287 catobjects[ntoken]->flags = o->flags&Hier;
288 catobjects[ntoken]->flags |= Sort;
289 strncpy(catobjects[ntoken]->key, token, KEYLEN);
290 catsetcopy(&catobjects[ntoken]->categories, &ot->categories);
291 addchild(root, catobjects[ntoken], "root");
300 while(tp > textbuf && tp[-1] == '\n') *--tp = 0;
301 if((o->type == File || o->type == Include) && o->path){
302 o->value = smprint("%s/%s", o->path, textbuf);
303 }else if(tp > textbuf){
304 o->value = strdup(textbuf);
305 setmalloctag(o->value, 0x100003);
309 q = strtok(o->value, " \t,;\n");
311 if(*q) for(i = 0; cmdlist[i].name; i++){
312 if(strcmp(q, cmdlist[i].name) == 0){
313 o->parent->flags |= cmdlist[i].flag;
316 if(cmdlist[i].name == 0)
317 fprint(2, "Unknown command: %s\n", q);
319 q = strtok(nil, " \t,;\n");
327 free(o->parent->path);
328 if(p[0] == '/' || o->path == nil){
329 o->parent->path = strdup(p);
330 setmalloctag(o->parent->path, 0x100004);
332 o->parent->path = smprint("%s/%s", o->path, p);
333 setmalloctag(o->parent->path, 0x100005);
342 return getinclude(o);
345 if(o->nchildren) break;
351 strncpy(o->parent->key, o->value, KEYLEN);
363 fprint(2, "Unexpected token: %s\n", token);
372 getinclude(Object *o)
376 char *savefile, fname[256];
379 char token[MAXTOKEN], *dirname, *filename;
384 savetext = strdup(curtext);
385 setmalloctag(savetext, 0x100006);
388 if((f = Bopen(o->value, OREAD)) == nil)
389 sysfatal("getinclude: %s: %r", o->value);
391 file = strdup(o->value);
392 strncpy(fname, o->value, 256);
393 if((filename = strrchr(fname, '/'))){
401 while((t = gettoken(token)) != Eof){
404 sysfatal("Bad include file %s/%s, token %s, str %d",
405 dirname, filename, token, str);
407 sysfatal("Bad include file %s, token %s, str %d",
408 filename, token, str);
411 o->path = strdup(dirname);
412 setmalloctag(o->path, 0x100007);
413 oo = getobject(t, o->parent);
414 if(oo) addchild(o->parent, oo, "o->parent, oo");
430 addchild(Object *parent, Object *child, char *where)
434 /* First check if child's already been added
435 * This saves checking elsewhere
437 for(i = 0; i < parent->nchildren; i++)
438 if(parent->children[i] == child) return;
439 parent->children = realloc(parent->children, (i+1)*4);
440 parent->children[i] = child;
442 if(parent->type == Category && child->type == Category)
444 if(parent->type == Work && child->type == Work)
446 if(parent->type == Work && child->type == Track)
448 if(parent->type == Track && child->type == File)
450 if(child->parent == child)
452 if(parent->type == Root)
454 if(parent->parent->type == Root)
456 // addcatparent(parent, child);
457 i = child->ncatparents;
458 if(0) fprint(2, "addcatparent %s parent %d type %d child %d type %d\n",where,
459 parent->tabno, parent->type, child->tabno, child->type);
460 child->catparents = realloc(child->catparents, (i+1)*4);
461 child->catparents[i] = parent;
462 child->ncatparents++;
466 addcatparent(Object *parent, Object *child)
470 /* First check if child's already been added
471 * This saves checking elsewhere
473 if(child->parent == child)
475 // for(i = 0; i < child->ncatparents; i++)
476 // if(child->catparents[i] == parent) return;
477 i = child->ncatparents;
478 fprint(2, "addcatparent parent %d child %d\n", parent->tabno, child->tabno);
479 child->catparents = realloc(child->catparents, (i+1)*4);
480 child->catparents[i] = parent;
481 child->ncatparents++;
485 sortprep(char *out, int n, Object *o)
495 if(p = strchr(q, '~'))
499 for(q = out; *p && q < out+n-1; q++)
509 char si[256], sj[256];
510 /* sort the kids by key or by value */
514 for(i = 0; i < n-1; i++){
515 sortprep(si, nelem(si), o->children[i]);
516 for(j = i+1; j < n; j++){
517 sortprep(sj, nelem(sj), o->children[j]);
518 if(strncmp(si, sj, sizeof(si)) > 0){
520 o->children[i] = o->children[j];
522 strncpy(si, sj, sizeof(si));
530 childenum(Object *o){
534 for(i = 0; i < o->nchildren; i++){
536 if(tokenlist[oo->type].kind == Cat)
553 newobject(Type t, Object *parent){
558 for(tabno = 0; tabno < notab; tabno++)
559 if(otab[tabno] == nil)
562 sysfatal("lost my hole");
567 otab = realloc(otab, sizeof(Object*)*sotab);
569 sysfatal("realloc: %r");
573 o = mallocz(sizeof(Object), 1);
578 if(parent && parent->path){
579 o->path = strdup(parent->path);
580 setmalloctag(o->path, 0x100008);
586 freeobject(Object *o, char*){
593 catsetfree(&o->categories);
594 otab[o->tabno] = nil;
604 for(i = 0; i < o->nchildren; i++)
605 if(o->children[i]->parent == o)
606 freetree(o->children[i]);
612 catsetfree(&o->categories);
613 otab[o->tabno] = nil;