Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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