parse.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <thread.h>
  4. #include <bio.h>
  5. #include <ctype.h>
  6. #include "object.h"
  7. #include "catset.h"
  8. #include "parse.h"
  9. #define MAXTOKEN 1024
  10. Biobuf *f;
  11. static int str;
  12. char *file;
  13. Token tokenlistinit[] = {
  14. { "category", Obj, Category , "music" , {nil,0}},
  15. { "cddata", Obj, Cddata , nil , {nil,0}},
  16. { "command", Obj, Cmd , nil , {nil,0}},
  17. { "file", Obj, File , "file" , {nil,0}},
  18. { "include", Obj, Include , nil , {nil,0}},
  19. { "key", Obj, Key , nil , {nil,0}},
  20. { "lyrics", Obj, Lyrics , "lyrics" , {nil,0}},
  21. { "part", Obj, Part , "title" , {nil,0}},
  22. { "path", Obj, Path , nil , {nil,0}},
  23. { "performance",Obj, Performance , "artist" , {nil,0}},
  24. { "recording", Obj, Recording , "title" , {nil,0}},
  25. { "root", Obj, Root , nil , {nil,0}},
  26. { "search", Obj, Search , nil , {nil,0}},
  27. { "soloists", Obj, Soloists , "artist" , {nil,0}},
  28. { "time", Obj, Time , "time" , {nil,0}},
  29. { "track", Obj, Track , "title" , {nil,0}},
  30. { "work", Obj, Work , "title" , {nil,0}},
  31. };
  32. Token *tokenlist;
  33. int ntoken = nelem(tokenlistinit);
  34. int catnr = 0;
  35. Cmdlist cmdlist[] = {
  36. { Sort, "sort" },
  37. { Enum, "number" },
  38. { 0x00, 0 },
  39. };
  40. static char *curtext;
  41. void
  42. inittokenlist(void)
  43. {
  44. int i;
  45. ntoken = nelem(tokenlistinit);
  46. tokenlist = malloc(sizeof(tokenlistinit));
  47. memmove(tokenlist, tokenlistinit, sizeof(tokenlistinit));
  48. for(i = 0; i< ntoken; i++){
  49. tokenlist[i].name = strdup(tokenlist[i].name);
  50. catsetinit(&tokenlist[i].categories, tokenlist[i].value);
  51. }
  52. curtext = smprint("{");
  53. }
  54. Type
  55. gettoken(char *token)
  56. {
  57. char *p, *q;
  58. int i, n;
  59. Token *t;
  60. for(;;){
  61. if(curtext){
  62. p = &curtext[strspn(curtext, " \t")];
  63. if(*p && *p != '\n')
  64. break;
  65. }
  66. do {
  67. str++;
  68. free(curtext);
  69. if((curtext = Brdstr(f, '\n', 0)) == nil)
  70. return Eof;
  71. } while(curtext[0] == '#');
  72. }
  73. if(*p == '{'){
  74. *token++ = *p;
  75. *token = 0;
  76. *p = ' ';
  77. return BraceO;
  78. }
  79. if(*p == '}'){
  80. *token++ = *p;
  81. *token = 0;
  82. *p = ' ';
  83. return BraceC;
  84. }
  85. if(*p == '='){
  86. *token++ = *p;
  87. *token = 0;
  88. *p = ' ';
  89. return Equals;
  90. }
  91. t = nil;
  92. n = 0;
  93. for(i = 0; i < ntoken; i++){
  94. t = &tokenlist[i];
  95. if(strncmp(p, t->name, n=strlen(t->name)) == 0){
  96. q = &p[n];
  97. if(isalnum(*q) || *q == '-') continue;
  98. q += strspn(q, " \t");
  99. if(t->kind == Obj && *q == '{')
  100. break;
  101. if(t->kind == Cat && *q == '=')
  102. break;
  103. }
  104. }
  105. if(i < ntoken){
  106. strcpy(token, t->name);
  107. memset(p, ' ', n);
  108. return i;
  109. }
  110. assert(strlen(token) < MAXTOKEN);
  111. if(strchr(p, '{'))
  112. sysfatal("Illegal keyword or parse error: %s", p);
  113. if((q = strchr(p, '='))){
  114. if(q == p) goto tx;
  115. *q = 0;
  116. strcpy(token, p);
  117. assert(strlen(token) < MAXTOKEN);
  118. memset(p, ' ', q-p);
  119. *q = '=';
  120. for(q = token; *q; q++)
  121. if(!isalnum(*q) && !isspace(*q)) break;
  122. if(*q) return Txt;
  123. while(isspace(*--q)) *q = 0;
  124. return Newcat;
  125. }
  126. tx: if((q = strchr(p, '}'))){
  127. *q = 0;
  128. strcpy(token, p);
  129. assert(strlen(token) < MAXTOKEN);
  130. memset(p, ' ', q-p);
  131. *q = '}';
  132. return Txt;
  133. }
  134. strcpy(token, p);
  135. assert(strlen(token) < MAXTOKEN);
  136. free(curtext);
  137. curtext = nil;
  138. return Txt;
  139. }
  140. Object *
  141. getobject(Type t, Object *parent)
  142. {
  143. char *token;
  144. char *textbuf;
  145. char *tp, *p, *q;
  146. int i;
  147. Object *o, *oo, *child;
  148. Token *ot;
  149. Type nt;
  150. token = malloc(MAXTOKEN);
  151. textbuf = malloc(8192);
  152. tp = textbuf;
  153. o = newobject(t, parent);
  154. o->flags |= Hier;
  155. if(parent == nil){
  156. root = o;
  157. o->path = strdup(startdir);
  158. setmalloctag(o->path, 0x100001);
  159. }
  160. if(gettoken(token) != BraceO)
  161. sysfatal("Parse error: no brace, str %d", str);
  162. for(;;){
  163. t = gettoken(token);
  164. if(t >= 0)
  165. switch(tokenlist[t].kind){
  166. case Obj:
  167. switch(t){
  168. case Key:
  169. case Cmd:
  170. case Path:
  171. if(getobject(t, o) != nil)
  172. sysfatal("Non-null child?");
  173. break;
  174. case Include:
  175. case Category:
  176. child = getobject(t, o);
  177. if(child) addchild(o, child, "case Category");
  178. break;
  179. default:
  180. /* subobject */
  181. child = getobject(t, o);
  182. if(child == nil)
  183. sysfatal("Null child?");
  184. addchild(o, child, "default");
  185. break;
  186. }
  187. break;
  188. case Cat:
  189. catcase: nt = gettoken(token);
  190. if(nt != Equals)
  191. sysfatal("Expected Equals, not %s", token);
  192. nt = gettoken(token);
  193. if(nt != Txt)
  194. sysfatal("Expected Text, not %s", token);
  195. if((p = strchr(token, '\n'))) *p = 0;
  196. p = token;
  197. if(o->type == Category){
  198. if(catsetisset(&o->categories)){
  199. fprint(2, "Category object must have one category\n");
  200. }
  201. catsetcopy(&o->categories, &tokenlist[t].categories);
  202. strncpy(o->key, p, KEYLEN);
  203. if(catobjects[t] == 0)
  204. sysfatal("Class %s not yet defined", tokenlist[t].name);
  205. for(i = 0; i < catobjects[t]->nchildren; i++)
  206. if(strcmp(catobjects[t]->children[i]->key, p) == 0)
  207. break;
  208. if(i == catobjects[t]->nchildren){
  209. /* It's a new key for the category */
  210. addchild(catobjects[t], o, "new key for cat");
  211. }else{
  212. /* Key already existed */
  213. oo = catobjects[t]->children[i];
  214. if(oo->value)
  215. sysfatal("Duplicate category object for %s", oo->value);
  216. catobjects[t]->children[i] = o;
  217. if(oo->nchildren){
  218. for(i = 0; i < oo->nchildren; i++){
  219. if(oo->children[i]->parent == oo)
  220. oo->children[i]->parent = o;
  221. addchild(o, oo->children[i], "key already existed");
  222. }
  223. }
  224. freeobject(oo, "a");
  225. }
  226. o->parent = catobjects[t];
  227. }else{
  228. catsetorset(&o->categories, &tokenlist[t].categories);
  229. for(i = 0; i < catobjects[t]->nchildren; i++)
  230. if(strcmp(catobjects[t]->children[i]->key, p) == 0)
  231. break;
  232. if(i == catobjects[t]->nchildren){
  233. oo = newobject(Category, catobjects[t]);
  234. /*
  235. oo->value = strdup(token);
  236. */
  237. strncpy(oo->key, p, KEYLEN);
  238. catsetcopy(&oo->categories, &tokenlist[t].categories);
  239. addchild(catobjects[t], oo, "catobjects[t],oo");
  240. }
  241. addchild(catobjects[t]->children[i], o, "children[i]");
  242. }
  243. break;
  244. }
  245. else
  246. switch(t){
  247. case Eof:
  248. if(o->type == Root){
  249. free(token);
  250. free(textbuf);
  251. return o;
  252. }
  253. sysfatal("Unexpected Eof in %s, file %s", tokenlist[o->type].name, file);
  254. case Newcat:
  255. /* New category, make an entry in the tokenlist */
  256. tokenlist = realloc(tokenlist, (ntoken+1)*sizeof(Token));
  257. ot = &tokenlist[ntoken];
  258. ot->name = strdup(token);
  259. setmalloctag(ot->name, 0x100002);
  260. ot->kind = Cat;
  261. ot->value = -1;
  262. memset(&ot->categories, 0, sizeof(Catset));
  263. catsetinit(&ot->categories, catnr++);
  264. /* And make an entry in the catobjects table */
  265. if(ncat <= ntoken){
  266. catobjects = realloc(catobjects, (ntoken+1)*sizeof(Object*));
  267. while(ncat <= ntoken) catobjects[ncat++] = nil;
  268. }
  269. if(catobjects[ntoken] != nil)
  270. sysfatal("Class %s already defined in %s:%d", token, file, str);
  271. if(0) fprint(2, "newcat: token %s catnr %d ntoken %d ncat %d\n",
  272. token, catnr, ntoken, ncat);
  273. catobjects[ntoken] = newobject(Category, root);
  274. if(o->type == Category)
  275. catobjects[ntoken]->flags = o->flags&Hier;
  276. catobjects[ntoken]->flags |= Sort;
  277. strncpy(catobjects[ntoken]->key, token, KEYLEN);
  278. catsetcopy(&catobjects[ntoken]->categories, &ot->categories);
  279. addchild(root, catobjects[ntoken], "root");
  280. t = ntoken;
  281. ntoken++;
  282. goto catcase;
  283. case Txt:
  284. strcpy(tp, token);
  285. tp += strlen(token);
  286. break;
  287. case BraceC:
  288. while(tp > textbuf && tp[-1] == '\n') *--tp = 0;
  289. if((o->type == File || o->type == Include) && o->path){
  290. o->value = smprint("%s/%s", o->path, textbuf);
  291. }else if(tp > textbuf){
  292. o->value = strdup(textbuf);
  293. setmalloctag(o->value, 0x100003);
  294. }
  295. switch(o->type){
  296. case Cmd:
  297. q = strtok(o->value, " \t,;\n");
  298. while(q){
  299. if(*q) for(i = 0; cmdlist[i].name; i++){
  300. if(strcmp(q, cmdlist[i].name) == 0){
  301. o->parent->flags |= cmdlist[i].flag;
  302. break;
  303. }
  304. if(cmdlist[i].name == 0)
  305. fprint(2, "Unknown command: %s\n", q);
  306. }
  307. q = strtok(nil, " \t,;\n");
  308. }
  309. freeobject(o, "b");
  310. free(token);
  311. free(textbuf);
  312. return nil;
  313. case Path:
  314. p = o->value;
  315. free(o->parent->path);
  316. if(p[0] == '/' || o->path == nil){
  317. o->parent->path = strdup(p);
  318. setmalloctag(o->parent->path, 0x100004);
  319. }else{
  320. o->parent->path = smprint("%s/%s", o->path, p);
  321. setmalloctag(o->parent->path, 0x100005);
  322. }
  323. freeobject(o, "b");
  324. free(token);
  325. free(textbuf);
  326. return nil;
  327. case Include:
  328. free(token);
  329. free(textbuf);
  330. return getinclude(o);
  331. case Category:
  332. /*
  333. if(o->nchildren) break;
  334. */
  335. free(token);
  336. free(textbuf);
  337. return nil;
  338. case Key:
  339. strncpy(o->parent->key, o->value, KEYLEN);
  340. freeobject(o, "d");
  341. free(token);
  342. free(textbuf);
  343. return nil;
  344. default:
  345. break;
  346. }
  347. free(token);
  348. free(textbuf);
  349. return o;
  350. default:
  351. fprint(2, "Unexpected token: %s\n", token);
  352. free(token);
  353. free(textbuf);
  354. return nil;
  355. }
  356. }
  357. }
  358. Object *
  359. getinclude(Object *o)
  360. {
  361. char *savetext;
  362. Biobuf *savef = f;
  363. char *savefile, fname[256];
  364. Object *oo;
  365. int savestr = str;
  366. char token[MAXTOKEN], *dirname, *filename;
  367. Type t;
  368. str = 0;
  369. if(curtext){
  370. savetext = strdup(curtext);
  371. setmalloctag(savetext, 0x100006);
  372. }else
  373. savetext = nil;
  374. if((f = Bopen(o->value, OREAD)) == nil)
  375. sysfatal("getinclude: %s: %r", o->value);
  376. savefile = file;
  377. file = strdup(o->value);
  378. strncpy(fname, o->value, 256);
  379. if((filename = strrchr(fname, '/'))){
  380. *filename = 0;
  381. dirname = fname;
  382. filename++;
  383. }else{
  384. dirname = "";
  385. filename = fname;
  386. }
  387. while((t = gettoken(token)) != Eof){
  388. if(t < 0){
  389. if(*dirname)
  390. sysfatal("Bad include file %s/%s, token %s, str %d",
  391. dirname, filename, token, str);
  392. else
  393. sysfatal("Bad include file %s, token %s, str %d",
  394. filename, token, str);
  395. }
  396. free(o->path);
  397. o->path = strdup(dirname);
  398. setmalloctag(o->path, 0x100007);
  399. oo = getobject(t, o->parent);
  400. if(oo) addchild(o->parent, oo, "o->parent, oo");
  401. }
  402. freeobject(o, "e");
  403. free(curtext);
  404. curtext = nil;
  405. if(savetext)
  406. curtext = savetext;
  407. free(file);
  408. file = savefile;
  409. str = savestr;
  410. Bterm(f);
  411. f = savef;
  412. return nil;
  413. }
  414. void
  415. addchild(Object *parent, Object *child, char *where)
  416. {
  417. int i;
  418. /* First check if child's already been added
  419. * This saves checking elsewhere
  420. */
  421. for(i = 0; i < parent->nchildren; i++)
  422. if(parent->children[i] == child) return;
  423. parent->children = realloc(parent->children, (i+1)*4);
  424. parent->children[i] = child;
  425. parent->nchildren++;
  426. if(parent->type == Category && child->type == Category)
  427. return;
  428. if(parent->type == Work && child->type == Work)
  429. return;
  430. if(parent->type == Work && child->type == Track)
  431. return;
  432. if(parent->type == Track && child->type == File)
  433. return;
  434. if(child->parent == child)
  435. return;
  436. if(parent->type == Root)
  437. return;
  438. if(parent->parent->type == Root)
  439. return;
  440. // addcatparent(parent, child);
  441. i = child->ncatparents;
  442. if(0) fprint(2, "addcatparent %s parent %d type %d child %d type %d\n",where,
  443. parent->tabno, parent->type, child->tabno, child->type);
  444. child->catparents = realloc(child->catparents, (i+1)*4);
  445. child->catparents[i] = parent;
  446. child->ncatparents++;
  447. }
  448. void
  449. addcatparent(Object *parent, Object *child)
  450. {
  451. int i;
  452. /* First check if child's already been added
  453. * This saves checking elsewhere
  454. */
  455. if(child->parent == child)
  456. return;
  457. // for(i = 0; i < child->ncatparents; i++)
  458. // if(child->catparents[i] == parent) return;
  459. i = child->ncatparents;
  460. fprint(2, "addcatparent parent %d child %d\n", parent->tabno, child->tabno);
  461. child->catparents = realloc(child->catparents, (i+1)*4);
  462. child->catparents[i] = parent;
  463. child->ncatparents++;
  464. }
  465. void
  466. sortprep(char *out, int n, Object *o)
  467. {
  468. char *p, *q;
  469. if(*o->key)
  470. q = o->key;
  471. else if (o->value)
  472. q = o->value;
  473. else
  474. q = "";
  475. if(p = strchr(q, '~'))
  476. p++;
  477. else
  478. p = q;
  479. for(q = out; *p && q < out+n-1; q++)
  480. *q = tolower(*p++);
  481. *q = 0;
  482. }
  483. void
  484. childsort(Object *o)
  485. {
  486. Object *oo;
  487. int i, j, n;
  488. char si[256], sj[256];
  489. /* sort the kids by key or by value */
  490. n = o->nchildren;
  491. if(n > 1){
  492. for(i = 0; i < n-1; i++){
  493. sortprep(si, nelem(si), o->children[i]);
  494. for(j = i+1; j < n; j++){
  495. sortprep(sj, nelem(sj), o->children[j]);
  496. if(strncmp(si, sj, sizeof(si)) > 0){
  497. oo = o->children[i];
  498. o->children[i] = o->children[j];
  499. o->children[j] = oo;
  500. strncpy(si, sj, sizeof(si));
  501. }
  502. }
  503. }
  504. }
  505. }
  506. void
  507. childenum(Object *o){
  508. Object *oo;
  509. int i, n = 1;
  510. for(i = 0; i < o->nchildren; i++){
  511. oo = o->children[i];
  512. if(tokenlist[oo->type].kind == Cat)
  513. oo->num = n++;
  514. else
  515. switch(oo->type){
  516. case Category:
  517. case Part:
  518. case Recording:
  519. case Track:
  520. case Work:
  521. oo->num = n++;
  522. default:
  523. break;
  524. }
  525. }
  526. }
  527. Object *
  528. newobject(Type t, Object *parent){
  529. Object *o;
  530. int tabno;
  531. if(hotab){
  532. for(tabno = 0; tabno < notab; tabno++)
  533. if(otab[tabno] == nil)
  534. break;
  535. if(tabno == notab)
  536. sysfatal("lost my hole");
  537. hotab--;
  538. }else{
  539. if(sotab < notab+1){
  540. sotab += 512;
  541. otab = realloc(otab, sizeof(Object*)*sotab);
  542. if(otab == nil)
  543. sysfatal("realloc: %r");
  544. }
  545. tabno = notab++;
  546. }
  547. o = mallocz(sizeof(Object), 1);
  548. o->tabno = tabno;
  549. otab[tabno] = o;
  550. o->type = t;
  551. o->parent = parent;
  552. if(parent && parent->path){
  553. o->path = strdup(parent->path);
  554. setmalloctag(o->path, 0x100008);
  555. }
  556. return o;
  557. }
  558. void
  559. freeobject(Object *o, char*){
  560. free(o->children);
  561. if(o->orig == nil)
  562. free(o->value);
  563. free(o->path);
  564. free(o->catparents);
  565. catsetfree(&o->categories);
  566. otab[o->tabno] = nil;
  567. hotab++;
  568. free(o);
  569. }
  570. void
  571. freetree(Object *o)
  572. {
  573. int i;
  574. for(i = 0; i < o->nchildren; i++)
  575. if(o->children[i]->parent == o)
  576. freetree(o->children[i]);
  577. free(o->children);
  578. if(o->orig == nil)
  579. free(o->value);
  580. free(o->path);
  581. free(o->catparents);
  582. catsetfree(&o->categories);
  583. otab[o->tabno] = nil;
  584. hotab++;
  585. free(o);
  586. }