xref: /inferno-os/libtk/parse.c (revision 61d0ba9cf1fac12977df33d5fa8509ff13322614)
137da2899SCharles.Forsyth #include "lib9.h"
237da2899SCharles.Forsyth #include "kernel.h"
337da2899SCharles.Forsyth #include "draw.h"
437da2899SCharles.Forsyth #include "tk.h"
537da2899SCharles.Forsyth 
637da2899SCharles.Forsyth #define	O(t, e)		((long)(&((t*)0)->e))
737da2899SCharles.Forsyth 
837da2899SCharles.Forsyth static char* pdist(TkTop*, TkOption*, void*, char**, char*, char*);
937da2899SCharles.Forsyth static char* pstab(TkTop*, TkOption*, void*, char**, char*, char*);
1037da2899SCharles.Forsyth static char* ptext(TkTop*, TkOption*, void*, char**, char*, char*);
1137da2899SCharles.Forsyth static char* pwinp(TkTop*, TkOption*, void*, char**, char*, char*);
1237da2899SCharles.Forsyth static char* pbmap(TkTop*, TkOption*, void*, char**, char*, char*);
1337da2899SCharles.Forsyth static char* pbool(TkTop*, TkOption*, void*, char**, char*, char*);
1437da2899SCharles.Forsyth static char* pfont(TkTop*, TkOption*, void*, char**, char*, char*);
1537da2899SCharles.Forsyth static char* pfrac(TkTop*, TkOption*, void*, char**, char*, char*);
1637da2899SCharles.Forsyth static char* pnnfrac(TkTop*, TkOption*, void*, char**, char*, char*);
1737da2899SCharles.Forsyth static char* pctag(TkTop*, TkOption*, void*, char**, char*, char*);
1837da2899SCharles.Forsyth static char* ptabs(TkTop*, TkOption*, void*, char**, char*, char*);
1937da2899SCharles.Forsyth static char* pcolr(TkTop*, TkOption*, void*, char**, char*, char*);
2037da2899SCharles.Forsyth static char* pimag(TkTop*, TkOption*, void*, char**, char*, char*);
2137da2899SCharles.Forsyth static char* psize(TkTop*, TkOption*, void*, char**, char*, char*);
2237da2899SCharles.Forsyth static char* pnndist(TkTop*, TkOption*, void*, char**, char*, char*);
2337da2899SCharles.Forsyth static char* pact(TkTop*, TkOption*, void*, char**, char*, char*);
2437da2899SCharles.Forsyth static char* pignore(TkTop*, TkOption*, void*, char**, char*, char*);
2537da2899SCharles.Forsyth static char* psticky(TkTop*, TkOption*, void*, char**, char*, char*);
2637da2899SCharles.Forsyth static char* plist(TkTop*, TkOption*, void*, char**, char*, char*);
2737da2899SCharles.Forsyth 
2837da2899SCharles.Forsyth static char* (*oparse[])(TkTop*, TkOption*, void*, char**, char*, char*) =
2937da2899SCharles.Forsyth {
3037da2899SCharles.Forsyth 	/* OPTdist */	pdist,
3137da2899SCharles.Forsyth 	/* OPTstab */	pstab,
3237da2899SCharles.Forsyth 	/* OPTtext */	ptext,
3337da2899SCharles.Forsyth 	/* OPTwinp */	pwinp,
3437da2899SCharles.Forsyth 	/* OPTflag */	pstab,
3537da2899SCharles.Forsyth 	/* OPTbmap */	pbmap,
3637da2899SCharles.Forsyth 	/* OPTbool */	pbool,
3737da2899SCharles.Forsyth 	/* OPTfont */	pfont,
3837da2899SCharles.Forsyth 	/* OPTfrac */	pfrac,
3937da2899SCharles.Forsyth 	/* OPTnnfrac */	pnnfrac,
4037da2899SCharles.Forsyth 	/* OPTctag */	pctag,
4137da2899SCharles.Forsyth 	/* OPTtabs */	ptabs,
4237da2899SCharles.Forsyth 	/* OPTcolr */	pcolr,
4337da2899SCharles.Forsyth 	/* OPTimag */	pimag,
4437da2899SCharles.Forsyth 	/* OPTsize */	psize,
4537da2899SCharles.Forsyth 	/* OPTnndist */	pnndist,
4637da2899SCharles.Forsyth 	/* OPTact */	pact,
4737da2899SCharles.Forsyth 	/* OPTignore */	pignore,
4837da2899SCharles.Forsyth 	/* OPTsticky */	psticky,
4937da2899SCharles.Forsyth 	/* OPTlist */ plist,
50f94b359dSforsyth 	/* OPTflags */	pstab,
5137da2899SCharles.Forsyth };
5237da2899SCharles.Forsyth 
5337da2899SCharles.Forsyth char*
tkskip(char * s,char * bl)5437da2899SCharles.Forsyth tkskip(char *s, char *bl)
5537da2899SCharles.Forsyth {
5637da2899SCharles.Forsyth 	char *p;
5737da2899SCharles.Forsyth 
5837da2899SCharles.Forsyth 	while(*s) {
5937da2899SCharles.Forsyth 		for(p = bl; *p; p++)
6037da2899SCharles.Forsyth 			if(*p == *s)
6137da2899SCharles.Forsyth 				break;
6237da2899SCharles.Forsyth 		if(*p == '\0')
6337da2899SCharles.Forsyth 			return s;
6437da2899SCharles.Forsyth 		s++;
6537da2899SCharles.Forsyth 	}
6637da2899SCharles.Forsyth 	return s;
6737da2899SCharles.Forsyth }
6837da2899SCharles.Forsyth 
6937da2899SCharles.Forsyth /* XXX - Tad: error propagation? */
7037da2899SCharles.Forsyth char*
tkword(TkTop * t,char * str,char * buf,char * ebuf,int * gotarg)7137da2899SCharles.Forsyth tkword(TkTop *t, char *str, char *buf, char *ebuf, int *gotarg)
7237da2899SCharles.Forsyth {
7337da2899SCharles.Forsyth 	int c, lev, tmp;
7437da2899SCharles.Forsyth 	char *val, *e, *p, *cmd;
7537da2899SCharles.Forsyth 	if (gotarg == nil)
7637da2899SCharles.Forsyth 		gotarg = &tmp;
7737da2899SCharles.Forsyth 
7837da2899SCharles.Forsyth 	/*
7937da2899SCharles.Forsyth 	 * ebuf is one beyond last byte in buf; leave room for nul byte in
8037da2899SCharles.Forsyth 	 * all cases.
8137da2899SCharles.Forsyth 	 */
8237da2899SCharles.Forsyth 	--ebuf;
8337da2899SCharles.Forsyth 
8437da2899SCharles.Forsyth 	str = tkskip(str, " \t");
8537da2899SCharles.Forsyth 	*gotarg = 1;
8637da2899SCharles.Forsyth 	lev = 1;
8737da2899SCharles.Forsyth 	switch(*str) {
8837da2899SCharles.Forsyth 	case '{':
8937da2899SCharles.Forsyth 		/* XXX - DBK: According to Ousterhout (p.37), while back=
9037da2899SCharles.Forsyth 		 * slashed braces don't count toward finding the matching
9137da2899SCharles.Forsyth 		 * closing braces, the backslashes should not be removed.
9237da2899SCharles.Forsyth 		 * Presumably this also applies to other backslashed
9337da2899SCharles.Forsyth 		 * characters: the backslash should not be removed.
9437da2899SCharles.Forsyth 		 */
9537da2899SCharles.Forsyth 		str++;
9637da2899SCharles.Forsyth 		while(*str && buf < ebuf) {
9737da2899SCharles.Forsyth 			c = *str++;
9837da2899SCharles.Forsyth 			if(c == '\\') {
9937da2899SCharles.Forsyth 				if(*str == '}' || *str == '{' || *str == '\\')
10037da2899SCharles.Forsyth 					c = *str++;
101c9ccdbd5Sforsyth 			} else if(c == '}') {
10237da2899SCharles.Forsyth 				lev--;
10337da2899SCharles.Forsyth 				if(lev == 0)
10437da2899SCharles.Forsyth 					break;
105c9ccdbd5Sforsyth 			} else if(c == '{')
10637da2899SCharles.Forsyth 				lev++;
10737da2899SCharles.Forsyth 			*buf++ = c;
10837da2899SCharles.Forsyth 		}
10937da2899SCharles.Forsyth 		break;
11037da2899SCharles.Forsyth 	case '[':
11137da2899SCharles.Forsyth 		/* XXX - DBK: According to Ousterhout (p. 33) command
11237da2899SCharles.Forsyth 		 * substitution may occur anywhere within a word, not
11337da2899SCharles.Forsyth 		 * only (as here) at the beginning.
11437da2899SCharles.Forsyth 		 */
11537da2899SCharles.Forsyth 		cmd = malloc(strlen(str));	/* not strlen+1 because the first character is skipped */
11637da2899SCharles.Forsyth 		if ( cmd == nil ) {
11737da2899SCharles.Forsyth 			buf[0] = '\0';	/* DBK - Why not an error message? */
11837da2899SCharles.Forsyth 			return str;
11937da2899SCharles.Forsyth 		}
12037da2899SCharles.Forsyth 		p = cmd;
12137da2899SCharles.Forsyth 		str++;
12237da2899SCharles.Forsyth 		while(*str) {
12337da2899SCharles.Forsyth 			c = *str++;
12437da2899SCharles.Forsyth 			if(c == '\\') {
12537da2899SCharles.Forsyth 				if(*str == ']' || *str == '[' || *str == '\\')
12637da2899SCharles.Forsyth 					c = *str++;
127c9ccdbd5Sforsyth 			} else if(c == ']') {
12837da2899SCharles.Forsyth 				lev--;
12937da2899SCharles.Forsyth 				if(lev == 0)
13037da2899SCharles.Forsyth 					break;
131c9ccdbd5Sforsyth 			} else if(c == '[')
13237da2899SCharles.Forsyth 				lev++;
13337da2899SCharles.Forsyth 			*p++ = c;
13437da2899SCharles.Forsyth 		}
13537da2899SCharles.Forsyth 		*p = '\0';
13637da2899SCharles.Forsyth 		val = nil;
13737da2899SCharles.Forsyth 		e = tkexec(t, cmd, &val);
13837da2899SCharles.Forsyth 		free(cmd);
13937da2899SCharles.Forsyth 		 /* XXX - Tad: is this appropriate behavior?
14037da2899SCharles.Forsyth 		  *	      Am I sure that the error doesn't need to be
14137da2899SCharles.Forsyth 		  *	      propagated back to the caller?
14237da2899SCharles.Forsyth 		  */
14337da2899SCharles.Forsyth 		if(e == nil && val != nil) {
14437da2899SCharles.Forsyth 			strncpy(buf, val, ebuf-buf);
14537da2899SCharles.Forsyth 			buf = ebuf;
14637da2899SCharles.Forsyth 			free(val);
14737da2899SCharles.Forsyth 		}
14837da2899SCharles.Forsyth 		break;
14937da2899SCharles.Forsyth 	case '\'':
15037da2899SCharles.Forsyth 		str++;
15137da2899SCharles.Forsyth 		while(*str && buf < ebuf)
15237da2899SCharles.Forsyth 			*buf++ = *str++;
15337da2899SCharles.Forsyth 		break;
15437da2899SCharles.Forsyth 	case '\0':
15537da2899SCharles.Forsyth 		*gotarg = 0;
15637da2899SCharles.Forsyth 		break;
15737da2899SCharles.Forsyth 	default:
15837da2899SCharles.Forsyth 		/* XXX - DBK: See comment above about command substitution.
15937da2899SCharles.Forsyth 		 * Also, any backslashed character should be replaced by
16037da2899SCharles.Forsyth 		 * itself (e.g. to put a space, tab, or [ into a word.
16137da2899SCharles.Forsyth 		 * We assume that the C compiler has already done the
16237da2899SCharles.Forsyth 		 * standard ANSI C substitutions.  (But should we?)
16337da2899SCharles.Forsyth 		 */
16437da2899SCharles.Forsyth 		while(*str && *str != ' ' && *str != '\t' && buf < ebuf)
16537da2899SCharles.Forsyth 			*buf++ = *str++;
16637da2899SCharles.Forsyth 	}
16737da2899SCharles.Forsyth 	*buf = '\0';
16837da2899SCharles.Forsyth 	return str;
16937da2899SCharles.Forsyth }
17037da2899SCharles.Forsyth 
17137da2899SCharles.Forsyth static TkOption*
Getopt(TkOption * o,char * buf)17237da2899SCharles.Forsyth Getopt(TkOption *o, char *buf)
17337da2899SCharles.Forsyth {
17437da2899SCharles.Forsyth 	while(o->o != nil) {
17537da2899SCharles.Forsyth 		if(strcmp(buf, o->o) == 0)
17637da2899SCharles.Forsyth 			return o;
17737da2899SCharles.Forsyth 		o++;
17837da2899SCharles.Forsyth 	}
17937da2899SCharles.Forsyth 	return nil;
18037da2899SCharles.Forsyth }
18137da2899SCharles.Forsyth 
18237da2899SCharles.Forsyth TkName*
tkmkname(char * name)18337da2899SCharles.Forsyth tkmkname(char *name)
18437da2899SCharles.Forsyth {
18537da2899SCharles.Forsyth 	TkName *n;
18637da2899SCharles.Forsyth 
18737da2899SCharles.Forsyth 	n = malloc(sizeof(struct TkName)+strlen(name));
18837da2899SCharles.Forsyth 	if(n == nil)
18937da2899SCharles.Forsyth 		return nil;
19037da2899SCharles.Forsyth 	strcpy(n->name, name);
19137da2899SCharles.Forsyth 	n->link = nil;
19237da2899SCharles.Forsyth 	n->obj = nil;
19337da2899SCharles.Forsyth 	return n;
19437da2899SCharles.Forsyth }
19537da2899SCharles.Forsyth 
19637da2899SCharles.Forsyth char*
tkparse(TkTop * t,char * str,TkOptab * ot,TkName ** nl)19737da2899SCharles.Forsyth tkparse(TkTop *t, char *str, TkOptab *ot, TkName **nl)
19837da2899SCharles.Forsyth {
19937da2899SCharles.Forsyth 	int l;
20037da2899SCharles.Forsyth 	TkOptab *ft;
20137da2899SCharles.Forsyth 	TkOption *o;
20237da2899SCharles.Forsyth 	TkName *f, *n;
20337da2899SCharles.Forsyth 	char *e, *buf, *ebuf;
20437da2899SCharles.Forsyth 
20537da2899SCharles.Forsyth 	l = strlen(str);
20637da2899SCharles.Forsyth 	if (l < Tkmaxitem)
20737da2899SCharles.Forsyth 		l = Tkmaxitem;
20837da2899SCharles.Forsyth 	buf = malloc(l + 1);
20937da2899SCharles.Forsyth 	if(buf == 0)
21037da2899SCharles.Forsyth 		return TkNomem;
21137da2899SCharles.Forsyth 	ebuf = buf + l + 1;
21237da2899SCharles.Forsyth 
21337da2899SCharles.Forsyth 	e = nil;
21437da2899SCharles.Forsyth 	while(e == nil) {
21537da2899SCharles.Forsyth 		str = tkword(t, str, buf, ebuf, nil);
21637da2899SCharles.Forsyth 		switch(*buf) {
21737da2899SCharles.Forsyth 		case '\0':
21837da2899SCharles.Forsyth 			goto done;
21937da2899SCharles.Forsyth 		case '-':
22037da2899SCharles.Forsyth 			if (buf[1] != '\0') {
22137da2899SCharles.Forsyth 				for(ft = ot; ft->ptr; ft++) {
22237da2899SCharles.Forsyth 					o = Getopt(ft->optab, buf+1);
22337da2899SCharles.Forsyth 					if(o != nil) {
22437da2899SCharles.Forsyth 						e = oparse[o->type](t, o, ft->ptr, &str, buf, ebuf);
22537da2899SCharles.Forsyth 						break;
22637da2899SCharles.Forsyth 					}
22737da2899SCharles.Forsyth 				}
22837da2899SCharles.Forsyth 				if(ft->ptr == nil){
22937da2899SCharles.Forsyth 					e = TkBadop;
23037da2899SCharles.Forsyth 					tkerr(t, buf);
23137da2899SCharles.Forsyth 				}
23237da2899SCharles.Forsyth 				break;
23337da2899SCharles.Forsyth 			}
23437da2899SCharles.Forsyth 			/* fall through if we've got a singleton '-' */
23537da2899SCharles.Forsyth 		default:
23637da2899SCharles.Forsyth 			if(nl == nil) {
23737da2899SCharles.Forsyth 				e = TkBadop;
23837da2899SCharles.Forsyth 				tkerr(t, buf);
23937da2899SCharles.Forsyth 				break;
24037da2899SCharles.Forsyth 			}
24137da2899SCharles.Forsyth 			n = tkmkname(buf);
24237da2899SCharles.Forsyth 			if(n == nil) {
24337da2899SCharles.Forsyth 				e = TkNomem;
24437da2899SCharles.Forsyth 				break;
24537da2899SCharles.Forsyth 			}
24637da2899SCharles.Forsyth 			if(*nl == nil)
24737da2899SCharles.Forsyth 				*nl = n;
24837da2899SCharles.Forsyth 			else {
24937da2899SCharles.Forsyth 				for(f = *nl; f->link; f = f->link)
25037da2899SCharles.Forsyth 					;
25137da2899SCharles.Forsyth 				f->link = n;
25237da2899SCharles.Forsyth 			}
25337da2899SCharles.Forsyth 		}
25437da2899SCharles.Forsyth 	}
25537da2899SCharles.Forsyth 
25637da2899SCharles.Forsyth 	if(e != nil && nl != nil)
25737da2899SCharles.Forsyth 		tkfreename(*nl);
25837da2899SCharles.Forsyth done:
25937da2899SCharles.Forsyth 	free(buf);
26037da2899SCharles.Forsyth 	return e;
26137da2899SCharles.Forsyth }
26237da2899SCharles.Forsyth 
26337da2899SCharles.Forsyth char*
tkconflist(TkOptab * ot,char ** val)26437da2899SCharles.Forsyth tkconflist(TkOptab *ot, char **val)
26537da2899SCharles.Forsyth {
26637da2899SCharles.Forsyth 	TkOption *o;
26737da2899SCharles.Forsyth 	char *f, *e;
26837da2899SCharles.Forsyth 
26937da2899SCharles.Forsyth 	f = "-%s";
27037da2899SCharles.Forsyth 	while(ot->ptr != nil) {
27137da2899SCharles.Forsyth 		o = ot->optab;
27237da2899SCharles.Forsyth 		while(o->o != nil) {
27337da2899SCharles.Forsyth 			e = tkvalue(val, f, o->o);
27437da2899SCharles.Forsyth 			if(e != nil)
27537da2899SCharles.Forsyth 				return e;
27637da2899SCharles.Forsyth 			f = " -%s";
27737da2899SCharles.Forsyth 			o++;
27837da2899SCharles.Forsyth 		}
27937da2899SCharles.Forsyth 		ot++;
28037da2899SCharles.Forsyth 	}
28137da2899SCharles.Forsyth 	return nil;
28237da2899SCharles.Forsyth }
28337da2899SCharles.Forsyth 
28437da2899SCharles.Forsyth char*
tkgencget(TkOptab * ft,char * arg,char ** val,TkTop * t)28537da2899SCharles.Forsyth tkgencget(TkOptab *ft, char *arg, char **val, TkTop *t)
28637da2899SCharles.Forsyth {
28737da2899SCharles.Forsyth 	Tk *w;
28837da2899SCharles.Forsyth 	char *c;
28937da2899SCharles.Forsyth 	Point g;
29037da2899SCharles.Forsyth 	TkEnv *e;
29137da2899SCharles.Forsyth 	TkStab *s;
29237da2899SCharles.Forsyth 	TkOption *o;
29337da2899SCharles.Forsyth 	int wh, con, i, n, flag, *v;
294f94b359dSforsyth 	char *r, *buf, *fmt, *out;
29537da2899SCharles.Forsyth 
29637da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
29737da2899SCharles.Forsyth 	if(buf == nil)
29837da2899SCharles.Forsyth 		return TkNomem;
29937da2899SCharles.Forsyth 
30037da2899SCharles.Forsyth 	tkitem(buf, arg);
30137da2899SCharles.Forsyth 	r = buf;
30237da2899SCharles.Forsyth 	if(*r == '-')
30337da2899SCharles.Forsyth 		r++;
30437da2899SCharles.Forsyth 	o = nil;
30537da2899SCharles.Forsyth 	while(ft->ptr) {
30637da2899SCharles.Forsyth 		o = Getopt(ft->optab, r);
30737da2899SCharles.Forsyth 		if(o != nil)
30837da2899SCharles.Forsyth 			break;
30937da2899SCharles.Forsyth 		ft++;
31037da2899SCharles.Forsyth 	}
31137da2899SCharles.Forsyth 	if(o == nil) {
31237da2899SCharles.Forsyth 		tkerr(t, r);
31337da2899SCharles.Forsyth 		free(buf);
31437da2899SCharles.Forsyth 		return TkBadop;
31537da2899SCharles.Forsyth 	}
31637da2899SCharles.Forsyth 
31737da2899SCharles.Forsyth 	switch(o->type) {
31837da2899SCharles.Forsyth 	default:
31937da2899SCharles.Forsyth 		tkerr(t, r);
32037da2899SCharles.Forsyth 		free(buf);
32137da2899SCharles.Forsyth 		return TkBadop;
32237da2899SCharles.Forsyth 	case OPTignore:
32337da2899SCharles.Forsyth 		return nil;
32437da2899SCharles.Forsyth 	case OPTact:
32537da2899SCharles.Forsyth 		w = ft->ptr;
32637da2899SCharles.Forsyth 		g = tkposn(w);
32737da2899SCharles.Forsyth 		n = g.y;
32837da2899SCharles.Forsyth 		if(o->aux == 0)
32937da2899SCharles.Forsyth 			n = g.x;
33037da2899SCharles.Forsyth 		free(buf);
33137da2899SCharles.Forsyth 		return tkvalue(val, "%d", n);
33237da2899SCharles.Forsyth 	case OPTdist:
33337da2899SCharles.Forsyth 	case OPTnndist:
33437da2899SCharles.Forsyth 		free(buf);
33537da2899SCharles.Forsyth 		return tkvalue(val, "%d", OPTION(ft->ptr, int, o->offset));
33637da2899SCharles.Forsyth 	case OPTsize:
33737da2899SCharles.Forsyth 		w = ft->ptr;
33837da2899SCharles.Forsyth 		if(strcmp(r, "width") == 0)
33937da2899SCharles.Forsyth 			wh = w->req.width;
34037da2899SCharles.Forsyth 		else
34137da2899SCharles.Forsyth 			wh = w->req.height;
34237da2899SCharles.Forsyth 		free(buf);
34337da2899SCharles.Forsyth 		return tkvalue(val, "%d", wh);
34437da2899SCharles.Forsyth 	case OPTtext:
34537da2899SCharles.Forsyth 		c = OPTION(ft->ptr, char*, o->offset);
34637da2899SCharles.Forsyth 		if(c == nil)
34737da2899SCharles.Forsyth 			c = "";
34837da2899SCharles.Forsyth 		free(buf);
34937da2899SCharles.Forsyth 		return tkvalue(val, "%s", c);
35037da2899SCharles.Forsyth 	case OPTwinp:
35137da2899SCharles.Forsyth 		w = OPTION(ft->ptr, Tk*, o->offset);
35237da2899SCharles.Forsyth 		if(w == nil || w->name == nil)
35337da2899SCharles.Forsyth 			c = "";
35437da2899SCharles.Forsyth 		else
35537da2899SCharles.Forsyth 			c = w->name->name;
35637da2899SCharles.Forsyth 		free(buf);
35737da2899SCharles.Forsyth 		return tkvalue(val, "%s", c);
35837da2899SCharles.Forsyth 	case OPTstab:
35937da2899SCharles.Forsyth 		s = o->aux;
36037da2899SCharles.Forsyth 		c = "";
36137da2899SCharles.Forsyth 		con = OPTION(ft->ptr, int, o->offset);
36237da2899SCharles.Forsyth 		while(s->val) {
36337da2899SCharles.Forsyth 			if(con == s->con) {
36437da2899SCharles.Forsyth 				c = s->val;
36537da2899SCharles.Forsyth 				break;
36637da2899SCharles.Forsyth 			}
36737da2899SCharles.Forsyth 			s++;
36837da2899SCharles.Forsyth 		}
36937da2899SCharles.Forsyth 		free(buf);
37037da2899SCharles.Forsyth 		return tkvalue(val, "%s", c);
37137da2899SCharles.Forsyth 	case OPTflag:
37237da2899SCharles.Forsyth 		con = OPTION(ft->ptr, int, o->offset);
37337da2899SCharles.Forsyth 		flag = 0;
37437da2899SCharles.Forsyth 		for (s = o->aux; s->val != nil; s++)
37537da2899SCharles.Forsyth 			flag |= s->con;
37637da2899SCharles.Forsyth 		c = "";
37737da2899SCharles.Forsyth 		for (s = o->aux; s->val != nil; s++) {
37837da2899SCharles.Forsyth 			if ((con & flag) == s->con) {
37937da2899SCharles.Forsyth 				c = s->val;
38037da2899SCharles.Forsyth 				break;
38137da2899SCharles.Forsyth 			}
38237da2899SCharles.Forsyth 		}
38337da2899SCharles.Forsyth 		free(buf);
38437da2899SCharles.Forsyth 		return tkvalue(val, "%s", c);
385f94b359dSforsyth 	case OPTflags:
386f94b359dSforsyth 		con = OPTION(ft->ptr, int, o->offset);
387f94b359dSforsyth 		out = mallocz(Tkmaxitem, 0);
388f94b359dSforsyth 		if(out == nil) {
389f94b359dSforsyth 			free(buf);
390f94b359dSforsyth 			return TkNomem;
391f94b359dSforsyth 		}
392f94b359dSforsyth 		c = out;
393f94b359dSforsyth 		for (s = o->aux; s->val != nil; s++) {
394*61d0ba9cSforsyth 			if (s->con == (s->con&-s->con) && (con & s->con) != 0)
395f94b359dSforsyth 				c = seprint(c, out+Tkmaxitem, " %s", s->val);	/* should this be quoted? */
396f94b359dSforsyth 		}
397f94b359dSforsyth 		free(buf);
398f94b359dSforsyth 		*c = 0;
399f94b359dSforsyth 		r = tkvalue(val, "%s", out);
400f94b359dSforsyth 		free(out);
401f94b359dSforsyth 		return r;
40237da2899SCharles.Forsyth 	case OPTfont:
40337da2899SCharles.Forsyth 		e = OPTION(ft->ptr, TkEnv*, o->offset);
40437da2899SCharles.Forsyth 		free(buf);
40537da2899SCharles.Forsyth 		if (e->font != nil)
40637da2899SCharles.Forsyth 			return tkvalue(val, "%s", e->font->name);
40737da2899SCharles.Forsyth 		return nil;
40837da2899SCharles.Forsyth 	case OPTcolr:
40937da2899SCharles.Forsyth 		e = OPTION(ft->ptr, TkEnv*, o->offset);
41037da2899SCharles.Forsyth 		i = AUXI(o->aux);
41137da2899SCharles.Forsyth 		free(buf);
41237da2899SCharles.Forsyth 		return tkvalue(val, "#%.8lux", e->colors[i]);
41337da2899SCharles.Forsyth 	case OPTfrac:
41437da2899SCharles.Forsyth 	case OPTnnfrac:
41537da2899SCharles.Forsyth 		v = &OPTION(ft->ptr, int, o->offset);
41637da2899SCharles.Forsyth 		n = (int)o->aux;
41737da2899SCharles.Forsyth 		if(n == 0)
41837da2899SCharles.Forsyth 			n = 1;
41937da2899SCharles.Forsyth 		fmt = "%s";
42037da2899SCharles.Forsyth 		for(i = 0; i < n; i++) {
42137da2899SCharles.Forsyth 			tkfprint(buf, *v++);
42237da2899SCharles.Forsyth 			r = tkvalue(val, fmt, buf);
42337da2899SCharles.Forsyth 			if(r != nil) {
42437da2899SCharles.Forsyth 				free(buf);
42537da2899SCharles.Forsyth 				return r;
42637da2899SCharles.Forsyth 			}
42737da2899SCharles.Forsyth 			fmt = " %s";
42837da2899SCharles.Forsyth 		}
42937da2899SCharles.Forsyth 		free(buf);
43037da2899SCharles.Forsyth 		return nil;
43137da2899SCharles.Forsyth 	case OPTbmap:
432f94b359dSforsyth 		//free(buf);
43337da2899SCharles.Forsyth 		return tkvalue(val, "%d", OPTION(ft->ptr, Image*, o->offset) != nil);
43437da2899SCharles.Forsyth 	case OPTimag:
435f94b359dSforsyth 		//free(buf);
43637da2899SCharles.Forsyth 		return tkvalue(val, "%d", OPTION(ft->ptr, TkImg*, o->offset) != nil);
43737da2899SCharles.Forsyth 	}
43837da2899SCharles.Forsyth }
43937da2899SCharles.Forsyth 
44037da2899SCharles.Forsyth static char*
pact(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)44137da2899SCharles.Forsyth pact(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
44237da2899SCharles.Forsyth {
44337da2899SCharles.Forsyth 	USED(buf);
44437da2899SCharles.Forsyth 	USED(ebuf);
44537da2899SCharles.Forsyth 	USED(str);
44637da2899SCharles.Forsyth 	USED(place);
44737da2899SCharles.Forsyth 	tkerr(t, o->o);
44837da2899SCharles.Forsyth 	return TkBadop;
44937da2899SCharles.Forsyth }
45037da2899SCharles.Forsyth 
45137da2899SCharles.Forsyth static char*
pignore(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)45237da2899SCharles.Forsyth pignore(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
45337da2899SCharles.Forsyth {
45437da2899SCharles.Forsyth 	char *p;
45537da2899SCharles.Forsyth 	USED(t);
45637da2899SCharles.Forsyth 	USED(o);
45737da2899SCharles.Forsyth 	USED(place);
45837da2899SCharles.Forsyth 
45937da2899SCharles.Forsyth 	p = tkword(t, *str, buf, ebuf, nil);
46037da2899SCharles.Forsyth 	if(*buf == '\0')
46137da2899SCharles.Forsyth 		return TkOparg;
46237da2899SCharles.Forsyth 	*str = p;
46337da2899SCharles.Forsyth 	return nil;
46437da2899SCharles.Forsyth }
46537da2899SCharles.Forsyth 
46637da2899SCharles.Forsyth static char*
pdist(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)46737da2899SCharles.Forsyth pdist(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
46837da2899SCharles.Forsyth {
46937da2899SCharles.Forsyth 	int d;
47037da2899SCharles.Forsyth 	char *e;
47137da2899SCharles.Forsyth 	TkEnv *env;
47237da2899SCharles.Forsyth 
47337da2899SCharles.Forsyth 	USED(buf);
47437da2899SCharles.Forsyth 	USED(ebuf);
47537da2899SCharles.Forsyth 
47637da2899SCharles.Forsyth 	/*
47737da2899SCharles.Forsyth 	 * this is a bit of a hack, as 0 is a valid option offset,
47837da2899SCharles.Forsyth 	 * but a nil aux is commonly used when 'w' and 'h' suffixes
47937da2899SCharles.Forsyth 	 * aren't appropriate.
48037da2899SCharles.Forsyth 	 * just make sure that no structure placed in TkOptab->ptr
48137da2899SCharles.Forsyth 	 * with an OPTdist element has a TkEnv as its first member.
48237da2899SCharles.Forsyth 	 */
48337da2899SCharles.Forsyth 
48437da2899SCharles.Forsyth 	if (o->aux == nil)
48537da2899SCharles.Forsyth 		env = nil;
48637da2899SCharles.Forsyth 	else
48737da2899SCharles.Forsyth 		env = OPTION(place, TkEnv*, AUXI(o->aux));
48837da2899SCharles.Forsyth 	e = tkfracword(t, str, &d, env);
48937da2899SCharles.Forsyth 	if(e != nil)
49037da2899SCharles.Forsyth 		return e;
49137da2899SCharles.Forsyth 	OPTION(place, int, o->offset) = TKF2I(d);
49237da2899SCharles.Forsyth 	return nil;
49337da2899SCharles.Forsyth }
49437da2899SCharles.Forsyth 
49537da2899SCharles.Forsyth static char*
pnndist(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)49637da2899SCharles.Forsyth pnndist(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
49737da2899SCharles.Forsyth {
49837da2899SCharles.Forsyth 	char* e;
49937da2899SCharles.Forsyth 	int oldv;
50037da2899SCharles.Forsyth 
50137da2899SCharles.Forsyth 	oldv = OPTION(place, int, o->offset);
50237da2899SCharles.Forsyth 	e = pdist(t, o, place, str, buf, ebuf);
50337da2899SCharles.Forsyth 	if(e == nil && OPTION(place, int, o->offset) < 0) {
50437da2899SCharles.Forsyth 		OPTION(place, int, o->offset) = oldv;
50537da2899SCharles.Forsyth 		return TkBadvl;
50637da2899SCharles.Forsyth 	}
50737da2899SCharles.Forsyth 	return e;
50837da2899SCharles.Forsyth }
50937da2899SCharles.Forsyth 
51037da2899SCharles.Forsyth static char*
psize(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)51137da2899SCharles.Forsyth psize(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
51237da2899SCharles.Forsyth {
51337da2899SCharles.Forsyth 	Tk *tk;
51437da2899SCharles.Forsyth 	char *e;
51537da2899SCharles.Forsyth 	int d, off;
51637da2899SCharles.Forsyth 
51737da2899SCharles.Forsyth 	USED(ebuf);
51837da2899SCharles.Forsyth 	e = tkfracword(t, str, &d, OPTION(place, TkEnv*, AUXI(o->aux)));
51937da2899SCharles.Forsyth 	if (e != nil)
52037da2899SCharles.Forsyth 		return e;
52137da2899SCharles.Forsyth 	if(d < 0)
52237da2899SCharles.Forsyth 		return TkBadvl;
52337da2899SCharles.Forsyth 
52437da2899SCharles.Forsyth 	tk = place;
52537da2899SCharles.Forsyth 	/*
52637da2899SCharles.Forsyth 	 * XXX there's no way of resetting Tksetwidth or Tksetheight.
52737da2899SCharles.Forsyth 	 * could perhaps allow it by setting width/height to {}
52837da2899SCharles.Forsyth 	 */
52937da2899SCharles.Forsyth 	if(strcmp(buf+1, "width") == 0) {
53037da2899SCharles.Forsyth 		tk->flag |= Tksetwidth;
53137da2899SCharles.Forsyth 		off = O(Tk, req.width);
53237da2899SCharles.Forsyth 	}
53337da2899SCharles.Forsyth 	else {
53437da2899SCharles.Forsyth 		tk->flag |= Tksetheight;
53537da2899SCharles.Forsyth 		off = O(Tk, req.height);
53637da2899SCharles.Forsyth 	}
53737da2899SCharles.Forsyth 	OPTION(place, int, off) = TKF2I(d);
53837da2899SCharles.Forsyth 	return nil;
53937da2899SCharles.Forsyth }
54037da2899SCharles.Forsyth 
541f94b359dSforsyth static TkStab*
lookstab(TkStab * s,char * word)542f94b359dSforsyth lookstab(TkStab *s, char *word)
543f94b359dSforsyth {
544f94b359dSforsyth 	for(; s->val != nil; s++)
545f94b359dSforsyth 		if(strcmp(s->val, word) == 0)
546f94b359dSforsyth 			return s;
547f94b359dSforsyth 	return nil;
548f94b359dSforsyth }
549f94b359dSforsyth 
55037da2899SCharles.Forsyth static char*
pstab(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)55137da2899SCharles.Forsyth pstab(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
55237da2899SCharles.Forsyth {
553f94b359dSforsyth 	char *p, *fields[8];
554f94b359dSforsyth 	int mask, val, nf;
55537da2899SCharles.Forsyth 	TkStab *s, *c;
55637da2899SCharles.Forsyth 
55737da2899SCharles.Forsyth 	p = tkword(t, *str, buf, ebuf, nil);
55837da2899SCharles.Forsyth 	if(*buf == '\0')
55937da2899SCharles.Forsyth 		return TkOparg;
56037da2899SCharles.Forsyth 
56137da2899SCharles.Forsyth 	if(o->type == OPTstab) {
562f94b359dSforsyth 		s = lookstab(o->aux, buf);
563f94b359dSforsyth 		if(s == nil)
564f94b359dSforsyth 			return TkBadvl;
565f94b359dSforsyth 		*str = p;
56637da2899SCharles.Forsyth 		OPTION(place, int, o->offset) = s->con;
56737da2899SCharles.Forsyth 		return nil;
56837da2899SCharles.Forsyth 	}
56937da2899SCharles.Forsyth 
570f94b359dSforsyth 	nf = getfields(buf, fields, nelem(fields), 1, " \t,");
571f94b359dSforsyth 	if(nf < 1 || nf > 1 && o->type != OPTflags)
572f94b359dSforsyth 		return TkBadvl;
573f94b359dSforsyth 
57437da2899SCharles.Forsyth 	mask = 0;
57537da2899SCharles.Forsyth 	for(c = o->aux; c->val; c++)
57637da2899SCharles.Forsyth 		mask |= c->con;
57737da2899SCharles.Forsyth 
578f94b359dSforsyth 	val = 0;
579f94b359dSforsyth 	while(--nf >= 0) {
580f94b359dSforsyth 		s = lookstab(o->aux, fields[nf]);
581f94b359dSforsyth 		if(s == nil)
582f94b359dSforsyth 			return TkBadvl;
583f94b359dSforsyth 		val |= s->con;
584f94b359dSforsyth 	}
585f94b359dSforsyth 	*str = p;
586f94b359dSforsyth 
58737da2899SCharles.Forsyth 	OPTION(place, int, o->offset) &= ~mask;
588f94b359dSforsyth 	OPTION(place, int, o->offset) |= val;
58937da2899SCharles.Forsyth 
59037da2899SCharles.Forsyth 	/*
59137da2899SCharles.Forsyth 	 * a hack, but otherwise we have to dirty the focus order
59237da2899SCharles.Forsyth 	 * every time any command is executed on a widget
59337da2899SCharles.Forsyth 	 */
594f94b359dSforsyth 	if(strcmp(o->o, "takefocus") == 0)
59537da2899SCharles.Forsyth 		tkdirtyfocusorder(t);
59637da2899SCharles.Forsyth 	return nil;
59737da2899SCharles.Forsyth }
59837da2899SCharles.Forsyth 
59937da2899SCharles.Forsyth enum {
60037da2899SCharles.Forsyth 	Stickyn = (1<<0),
60137da2899SCharles.Forsyth 	Stickye = (1<<1),
60237da2899SCharles.Forsyth 	Stickys = (1<<2),
60337da2899SCharles.Forsyth 	Stickyw = (1<<3)
60437da2899SCharles.Forsyth };
60537da2899SCharles.Forsyth 
60637da2899SCharles.Forsyth static int stickymap[16] =
60737da2899SCharles.Forsyth {
60837da2899SCharles.Forsyth 	0,
60937da2899SCharles.Forsyth 	Tknorth,
61037da2899SCharles.Forsyth 	Tkeast,
61137da2899SCharles.Forsyth 	Tknorth|Tkeast,
61237da2899SCharles.Forsyth 	Tksouth,
61337da2899SCharles.Forsyth 	Tkfilly,
61437da2899SCharles.Forsyth 	Tksouth|Tkeast,
61537da2899SCharles.Forsyth 	Tkeast|Tkfilly,
61637da2899SCharles.Forsyth 	Tkwest,
61737da2899SCharles.Forsyth 	Tknorth|Tkwest,
61837da2899SCharles.Forsyth 	Tkfillx,
61937da2899SCharles.Forsyth 	Tknorth|Tkfillx,
62037da2899SCharles.Forsyth 	Tksouth|Tkwest,
62137da2899SCharles.Forsyth 	Tkwest|Tkfilly,
62237da2899SCharles.Forsyth 	Tksouth|Tkfillx,
62337da2899SCharles.Forsyth 	Tkfillx|Tkfilly,
62437da2899SCharles.Forsyth };
62537da2899SCharles.Forsyth 
62637da2899SCharles.Forsyth static char*
psticky(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)62737da2899SCharles.Forsyth psticky(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
62837da2899SCharles.Forsyth {
62937da2899SCharles.Forsyth 	char *p, *s;
63037da2899SCharles.Forsyth 	int flag, sflag;
63137da2899SCharles.Forsyth 
63237da2899SCharles.Forsyth 	p = tkword(t, *str, buf, ebuf, nil);
63337da2899SCharles.Forsyth 	*str = p;
63437da2899SCharles.Forsyth 
63537da2899SCharles.Forsyth 	flag = 0;
63637da2899SCharles.Forsyth 	for (s = buf; *s; s++) {
63737da2899SCharles.Forsyth 		switch (*s) {
63837da2899SCharles.Forsyth 		case 'n':
63937da2899SCharles.Forsyth 			flag |= Stickyn;
64037da2899SCharles.Forsyth 			break;
64137da2899SCharles.Forsyth 		case 's':
64237da2899SCharles.Forsyth 			flag |= Stickys;
64337da2899SCharles.Forsyth 			break;
64437da2899SCharles.Forsyth 		case 'e':
64537da2899SCharles.Forsyth 			flag |= Stickye;
64637da2899SCharles.Forsyth 			break;
64737da2899SCharles.Forsyth 		case 'w':
64837da2899SCharles.Forsyth 			flag |= Stickyw;
64937da2899SCharles.Forsyth 			break;
65037da2899SCharles.Forsyth 		case ' ':
65137da2899SCharles.Forsyth 		case ',':
65237da2899SCharles.Forsyth 			break;
65337da2899SCharles.Forsyth 		default:
65437da2899SCharles.Forsyth 			return TkBadvl;
65537da2899SCharles.Forsyth 		}
65637da2899SCharles.Forsyth 	}
65737da2899SCharles.Forsyth 	sflag =  OPTION(place, int, o->offset) & ~(Tkanchor|Tkfill);
65837da2899SCharles.Forsyth 	OPTION(place, int, o->offset) = sflag | stickymap[flag];
65937da2899SCharles.Forsyth 	return nil;
66037da2899SCharles.Forsyth }
66137da2899SCharles.Forsyth 
66237da2899SCharles.Forsyth static char*
ptext(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)66337da2899SCharles.Forsyth ptext(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
66437da2899SCharles.Forsyth {
66537da2899SCharles.Forsyth 	char **p;
66637da2899SCharles.Forsyth 
66737da2899SCharles.Forsyth 	*str = tkword(t, *str, buf, ebuf, nil);
66837da2899SCharles.Forsyth 
66937da2899SCharles.Forsyth 	p = &OPTION(place, char*, o->offset);
67037da2899SCharles.Forsyth 	if(*p != nil)
67137da2899SCharles.Forsyth 		free(*p);
67237da2899SCharles.Forsyth 	if(buf[0] == '\0')
67337da2899SCharles.Forsyth 		*p = nil;
67437da2899SCharles.Forsyth 	else {
67537da2899SCharles.Forsyth 		*p = strdup(buf);
67637da2899SCharles.Forsyth 		if(*p == nil)
67737da2899SCharles.Forsyth 			return TkNomem;
67837da2899SCharles.Forsyth 	}
67937da2899SCharles.Forsyth 	return nil;
68037da2899SCharles.Forsyth }
68137da2899SCharles.Forsyth 
68237da2899SCharles.Forsyth static char*
pimag(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)68337da2899SCharles.Forsyth pimag(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
68437da2899SCharles.Forsyth {
68537da2899SCharles.Forsyth 	int locked;
68637da2899SCharles.Forsyth 	Display *d;
68737da2899SCharles.Forsyth 	TkImg **p, *i;
68837da2899SCharles.Forsyth 
68937da2899SCharles.Forsyth 	i = nil;
69037da2899SCharles.Forsyth 	p = &OPTION(place, TkImg*, o->offset);
69137da2899SCharles.Forsyth 	*str = tkword(t, *str, buf, ebuf, nil);
69237da2899SCharles.Forsyth 	if(*buf != '\0') {
69337da2899SCharles.Forsyth 		i = tkname2img(t, buf);
69437da2899SCharles.Forsyth 		if(i == nil)
69537da2899SCharles.Forsyth 			return TkBadvl;
69637da2899SCharles.Forsyth 		i->ref++;
69737da2899SCharles.Forsyth 	}
69837da2899SCharles.Forsyth 
69937da2899SCharles.Forsyth 	if(*p != nil) {
70037da2899SCharles.Forsyth 		d = t->display;
70137da2899SCharles.Forsyth 		locked = lockdisplay(d);
70237da2899SCharles.Forsyth 		tkimgput(*p);
70337da2899SCharles.Forsyth 		if(locked)
70437da2899SCharles.Forsyth 			unlockdisplay(d);
70537da2899SCharles.Forsyth 	}
70637da2899SCharles.Forsyth 	*p = i;
70737da2899SCharles.Forsyth 	return nil;
70837da2899SCharles.Forsyth }
70937da2899SCharles.Forsyth 
71037da2899SCharles.Forsyth static char*
pbmap(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)71137da2899SCharles.Forsyth pbmap(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
71237da2899SCharles.Forsyth {
71337da2899SCharles.Forsyth 	Display *d;
71437da2899SCharles.Forsyth 	Image *i, **p;
71537da2899SCharles.Forsyth 	int locked, fd;
71637da2899SCharles.Forsyth 	char *c;
71737da2899SCharles.Forsyth 
71837da2899SCharles.Forsyth 	p = &OPTION(place, Image*, o->offset);
71937da2899SCharles.Forsyth 
72037da2899SCharles.Forsyth 	d = t->display;
72137da2899SCharles.Forsyth 	*str = tkword(t, *str, buf, ebuf, nil);
72237da2899SCharles.Forsyth 	if(*buf == '\0' || *buf == '-') {
72337da2899SCharles.Forsyth 		if(*p != nil) {
72437da2899SCharles.Forsyth 			locked = lockdisplay(d);
72537da2899SCharles.Forsyth 			freeimage(*p);
72637da2899SCharles.Forsyth 			if(locked)
72737da2899SCharles.Forsyth 				unlockdisplay(d);
72837da2899SCharles.Forsyth 			*p = nil;
72937da2899SCharles.Forsyth 		}
73037da2899SCharles.Forsyth 		return nil;
73137da2899SCharles.Forsyth 	}
73237da2899SCharles.Forsyth 
73337da2899SCharles.Forsyth 	if(buf[0] == '@')
73437da2899SCharles.Forsyth 		i = display_open(d, buf+1);
735c9ccdbd5Sforsyth  else if(buf[0] == '<') {
73637da2899SCharles.Forsyth 		buf++;
73737da2899SCharles.Forsyth 		fd = strtoul(buf, &c, 0);
73837da2899SCharles.Forsyth 		if(c == buf) {
73937da2899SCharles.Forsyth 			return TkBadvl;
74037da2899SCharles.Forsyth 		}
74137da2899SCharles.Forsyth 		i = readimage(d, fd, 1);
74237da2899SCharles.Forsyth 	}
74337da2899SCharles.Forsyth 	else {
74437da2899SCharles.Forsyth 		char *file;
74537da2899SCharles.Forsyth 
74637da2899SCharles.Forsyth 		file = mallocz(Tkmaxitem, 0);
74737da2899SCharles.Forsyth 		if(file == nil)
74837da2899SCharles.Forsyth 			return TkNomem;
74937da2899SCharles.Forsyth 
75037da2899SCharles.Forsyth 		snprint(file, Tkmaxitem, "/icons/tk/%s", buf);
75137da2899SCharles.Forsyth 		i = display_open(d, file);
75237da2899SCharles.Forsyth 		free(file);
75337da2899SCharles.Forsyth 	}
75437da2899SCharles.Forsyth 	if(i == nil)
75537da2899SCharles.Forsyth 		return TkBadbm;
75637da2899SCharles.Forsyth 
75737da2899SCharles.Forsyth 	if(*p != nil) {
75837da2899SCharles.Forsyth 		locked = lockdisplay(d);
75937da2899SCharles.Forsyth 		freeimage(*p);
76037da2899SCharles.Forsyth 		if(locked)
76137da2899SCharles.Forsyth 			unlockdisplay(d);
76237da2899SCharles.Forsyth 	}
76337da2899SCharles.Forsyth 	*p = i;
76437da2899SCharles.Forsyth 	return nil;
76537da2899SCharles.Forsyth }
76637da2899SCharles.Forsyth 
76737da2899SCharles.Forsyth static char*
pfont(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)76837da2899SCharles.Forsyth pfont(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
76937da2899SCharles.Forsyth {
77037da2899SCharles.Forsyth 	TkEnv *e;
77137da2899SCharles.Forsyth 	Display *d;
77237da2899SCharles.Forsyth 	int locked;
77337da2899SCharles.Forsyth 	Font *font;
77437da2899SCharles.Forsyth 
77537da2899SCharles.Forsyth 	*str = tkword(t, *str, buf, ebuf, nil);
77637da2899SCharles.Forsyth 	if(*buf == '\0')
77737da2899SCharles.Forsyth 		return TkOparg;
77837da2899SCharles.Forsyth 
77937da2899SCharles.Forsyth 	d = t->display;
78037da2899SCharles.Forsyth 	font = font_open(d, buf);
78137da2899SCharles.Forsyth 	if(font == nil)
78237da2899SCharles.Forsyth 		return TkBadft;
78337da2899SCharles.Forsyth 
78437da2899SCharles.Forsyth 	e = tkdupenv(&OPTION(place, TkEnv*, o->offset));
78537da2899SCharles.Forsyth 	if(e == nil) {
78637da2899SCharles.Forsyth 		freefont(font);		/* XXX lockdisplay around this? */
78737da2899SCharles.Forsyth 		return TkNomem;
78837da2899SCharles.Forsyth 	}
78937da2899SCharles.Forsyth 	if(e->font)
79037da2899SCharles.Forsyth 		font_close(e->font);
79137da2899SCharles.Forsyth 	e->font = font;
79237da2899SCharles.Forsyth 
79337da2899SCharles.Forsyth 	locked = lockdisplay(d);
79437da2899SCharles.Forsyth 	e->wzero = stringwidth(font, "0");
79537da2899SCharles.Forsyth 	if ( e->wzero <= 0 )
79637da2899SCharles.Forsyth 		e->wzero = e->font->height / 2;
79737da2899SCharles.Forsyth 	if(locked)
79837da2899SCharles.Forsyth 		unlockdisplay(d);
79937da2899SCharles.Forsyth 
80037da2899SCharles.Forsyth 	return nil;
80137da2899SCharles.Forsyth }
80237da2899SCharles.Forsyth 
80337da2899SCharles.Forsyth static int
hex(int c)80437da2899SCharles.Forsyth hex(int c)
80537da2899SCharles.Forsyth {
80637da2899SCharles.Forsyth 	if(c >= 'a')
80737da2899SCharles.Forsyth 		c -= 'a'-'A';
80837da2899SCharles.Forsyth 	if(c >= 'A')
80937da2899SCharles.Forsyth 		c = 10 + (c - 'A');
81037da2899SCharles.Forsyth 	else
81137da2899SCharles.Forsyth 		c -= '0';
81237da2899SCharles.Forsyth 	return c;
81337da2899SCharles.Forsyth }
81437da2899SCharles.Forsyth 
81537da2899SCharles.Forsyth static ulong
changecol(TkEnv * e,int setcol,int col,ulong rgba)81637da2899SCharles.Forsyth changecol(TkEnv *e, int setcol, int col, ulong rgba)
81737da2899SCharles.Forsyth {
81837da2899SCharles.Forsyth 	if (setcol) {
81937da2899SCharles.Forsyth 		e->set |= (1<<col);
82037da2899SCharles.Forsyth 	} else {
82137da2899SCharles.Forsyth 		rgba = 0;
82237da2899SCharles.Forsyth 		e->set &= ~(1<<col);
82337da2899SCharles.Forsyth 	}
82437da2899SCharles.Forsyth 	e->colors[col] = rgba;
82537da2899SCharles.Forsyth 	return rgba;
82637da2899SCharles.Forsyth }
82737da2899SCharles.Forsyth 
82837da2899SCharles.Forsyth char*
tkparsecolor(char * buf,ulong * rgba)82937da2899SCharles.Forsyth tkparsecolor(char *buf, ulong *rgba)
83037da2899SCharles.Forsyth {
83137da2899SCharles.Forsyth 	char *p, *q, *e;
83237da2899SCharles.Forsyth 	int R, G, B, A;
83337da2899SCharles.Forsyth 	int i, alpha, len, alen;
83437da2899SCharles.Forsyth 	/*
83537da2899SCharles.Forsyth 	 * look for alpha modifier in *#AA or *0.5 format
83637da2899SCharles.Forsyth 	 */
83737da2899SCharles.Forsyth 	len = strlen(buf);
83837da2899SCharles.Forsyth 	p = strchr(buf, '*');
83937da2899SCharles.Forsyth 	if(p != nil) {
84037da2899SCharles.Forsyth 		alen = len - (p - buf);
84137da2899SCharles.Forsyth 		if(p[1] == '#') {
84237da2899SCharles.Forsyth 			if(alen != 4)
84337da2899SCharles.Forsyth 				return TkBadvl;
84437da2899SCharles.Forsyth 			alpha = (hex(p[2])<<4) | (hex(p[3]));
84537da2899SCharles.Forsyth 		} else {
84637da2899SCharles.Forsyth 			q = p+1;
84737da2899SCharles.Forsyth 			e = tkfrac(&q, &alpha, nil);
84837da2899SCharles.Forsyth 			if (e != nil)
84937da2899SCharles.Forsyth 				return e;
85037da2899SCharles.Forsyth 			alpha = TKF2I(alpha * 0xff);
85137da2899SCharles.Forsyth 		}
85237da2899SCharles.Forsyth 		*p = '\0';
85337da2899SCharles.Forsyth 		len -= alen;
85437da2899SCharles.Forsyth 	} else
85537da2899SCharles.Forsyth 		alpha = 0xff;
85637da2899SCharles.Forsyth 
85737da2899SCharles.Forsyth 	if (*buf == '#') {
85837da2899SCharles.Forsyth 		switch(len) {
85937da2899SCharles.Forsyth 		case 4:			/* #RGB */
86037da2899SCharles.Forsyth 			R = hex(buf[1]);
86137da2899SCharles.Forsyth 			G = hex(buf[2]);
86237da2899SCharles.Forsyth 			B = hex(buf[3]);
86337da2899SCharles.Forsyth 			*rgba = (R<<28) | (G<<20) | (B<<12) | 0xff;
86437da2899SCharles.Forsyth 			break;
86537da2899SCharles.Forsyth 		case 7:			/* #RRGGBB */
86637da2899SCharles.Forsyth 			R = (hex(buf[1])<<4)|(hex(buf[2]));
86737da2899SCharles.Forsyth 			G = (hex(buf[3])<<4)|(hex(buf[4]));
86837da2899SCharles.Forsyth 			B = (hex(buf[5])<<4)|(hex(buf[6]));
86937da2899SCharles.Forsyth 			*rgba = (R<<24) | (G<<16) | (B<<8) | 0xff;
87037da2899SCharles.Forsyth 			break;
87137da2899SCharles.Forsyth 		case 9:			/* #RRGGBBAA */
87237da2899SCharles.Forsyth 			R = (hex(buf[1])<<4)|(hex(buf[2]));
87337da2899SCharles.Forsyth 			G = (hex(buf[3])<<4)|(hex(buf[4]));
87437da2899SCharles.Forsyth 			B = (hex(buf[5])<<4)|(hex(buf[6]));
87537da2899SCharles.Forsyth 			A = (hex(buf[7])<<4)|(hex(buf[8]));
87637da2899SCharles.Forsyth 			*rgba = (R<<24) | (G<<16) | (B<<8) | A;
87737da2899SCharles.Forsyth 			break;
87837da2899SCharles.Forsyth 		default:
87937da2899SCharles.Forsyth 			return TkBadvl;
88037da2899SCharles.Forsyth 		}
88137da2899SCharles.Forsyth 	} else {
88237da2899SCharles.Forsyth 		for(i = 0; tkcolortab[i].val != nil; i++)
88337da2899SCharles.Forsyth 			if (!strcmp(tkcolortab[i].val, buf))
88437da2899SCharles.Forsyth 				break;
88537da2899SCharles.Forsyth 		if (tkcolortab[i].val == nil)
88637da2899SCharles.Forsyth 			return TkBadvl;
88737da2899SCharles.Forsyth 		*rgba = tkcolortab[i].con;
88837da2899SCharles.Forsyth 	}
88937da2899SCharles.Forsyth 	if (alpha != 0xff) {
89037da2899SCharles.Forsyth 		tkrgbavals(*rgba, &R, &G, &B, &A);
89137da2899SCharles.Forsyth 		A = (A * alpha) / 255;
89237da2899SCharles.Forsyth 		*rgba = tkrgba(R, G, B, A);
89337da2899SCharles.Forsyth 	}
89437da2899SCharles.Forsyth 	return nil;
89537da2899SCharles.Forsyth }
89637da2899SCharles.Forsyth 
89737da2899SCharles.Forsyth static char*
pcolr(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)89837da2899SCharles.Forsyth pcolr(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
89937da2899SCharles.Forsyth {
90037da2899SCharles.Forsyth 	TkEnv *env;
90137da2899SCharles.Forsyth 	char *e;
90237da2899SCharles.Forsyth 	ulong rgba, dark, light;
90337da2899SCharles.Forsyth 	int color, setcol;
90437da2899SCharles.Forsyth 
90537da2899SCharles.Forsyth 	*str = tkword(t, *str, buf, ebuf, nil);
90637da2899SCharles.Forsyth 	rgba = 0;
90737da2899SCharles.Forsyth 	if(*buf == '\0') {
90837da2899SCharles.Forsyth 		setcol = 0;
90937da2899SCharles.Forsyth 	} else {
91037da2899SCharles.Forsyth 		setcol = 1;
91137da2899SCharles.Forsyth 		e = tkparsecolor(buf, &rgba);
91237da2899SCharles.Forsyth 		if(e != nil)
91337da2899SCharles.Forsyth 			return e;
91437da2899SCharles.Forsyth 	}
91537da2899SCharles.Forsyth 
91637da2899SCharles.Forsyth 	env = tkdupenv(&OPTION(place, TkEnv*, o->offset));
91737da2899SCharles.Forsyth 	if(env == nil)
91837da2899SCharles.Forsyth 		return TkNomem;
91937da2899SCharles.Forsyth 
92037da2899SCharles.Forsyth 	color = AUXI(o->aux);
92137da2899SCharles.Forsyth 	rgba = changecol(env, setcol, color, rgba);
92237da2899SCharles.Forsyth 	if(color == TkCbackgnd || color == TkCselectbgnd || color == TkCactivebgnd) {
92337da2899SCharles.Forsyth 		if (setcol) {
92437da2899SCharles.Forsyth 			light = tkrgbashade(rgba, TkLightshade);
92537da2899SCharles.Forsyth 			dark = tkrgbashade(rgba, TkDarkshade);
92637da2899SCharles.Forsyth 		} else
92737da2899SCharles.Forsyth 			light = dark = 0;
92837da2899SCharles.Forsyth 		changecol(env, setcol, color+1, light);
92937da2899SCharles.Forsyth 		changecol(env, setcol, color+2, dark);
93037da2899SCharles.Forsyth 	}
93137da2899SCharles.Forsyth 	return nil;
93237da2899SCharles.Forsyth }
93337da2899SCharles.Forsyth 
93437da2899SCharles.Forsyth static char*
pbool(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)93537da2899SCharles.Forsyth pbool(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
93637da2899SCharles.Forsyth {
93737da2899SCharles.Forsyth 	USED(buf);
93837da2899SCharles.Forsyth 	USED(ebuf);
93937da2899SCharles.Forsyth 	USED(str);
94037da2899SCharles.Forsyth 	USED(t);
94137da2899SCharles.Forsyth 	OPTION(place, int, o->offset) = 1;
94237da2899SCharles.Forsyth 	return nil;
94337da2899SCharles.Forsyth }
94437da2899SCharles.Forsyth 
94537da2899SCharles.Forsyth static char*
pwinp(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)94637da2899SCharles.Forsyth pwinp(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
94737da2899SCharles.Forsyth {
94837da2899SCharles.Forsyth 	Tk *f;
94937da2899SCharles.Forsyth 	char *p;
95037da2899SCharles.Forsyth 
95137da2899SCharles.Forsyth 	p = tkword(t, *str, buf, ebuf, nil);
95237da2899SCharles.Forsyth 	if(*buf == '\0')
95337da2899SCharles.Forsyth 		return TkOparg;
95437da2899SCharles.Forsyth 	*str = p;
95537da2899SCharles.Forsyth 
95637da2899SCharles.Forsyth 	f = tklook(t, buf, 0);
95737da2899SCharles.Forsyth 	if(f == nil){
95837da2899SCharles.Forsyth 		tkerr(t, buf);
95937da2899SCharles.Forsyth 		return TkBadwp;
96037da2899SCharles.Forsyth 	}
96137da2899SCharles.Forsyth 
96237da2899SCharles.Forsyth 	OPTION(place, Tk*, o->offset) = f;
96337da2899SCharles.Forsyth 	return nil;
96437da2899SCharles.Forsyth }
96537da2899SCharles.Forsyth 
96637da2899SCharles.Forsyth static char*
pctag(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)96737da2899SCharles.Forsyth pctag(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
96837da2899SCharles.Forsyth {
96937da2899SCharles.Forsyth 	char *p;
97037da2899SCharles.Forsyth 	TkName *n, *l;
97137da2899SCharles.Forsyth 
97237da2899SCharles.Forsyth 	*str = tkword(t, *str, buf, ebuf, nil);
97337da2899SCharles.Forsyth 
97437da2899SCharles.Forsyth 	l = nil;
97537da2899SCharles.Forsyth 	p = buf;
97637da2899SCharles.Forsyth 	while(*p) {
97737da2899SCharles.Forsyth 		p = tkskip(p, " \t");
97837da2899SCharles.Forsyth 		buf = p;
97937da2899SCharles.Forsyth 		while(*p && *p != ' ' && *p != '\t')
98037da2899SCharles.Forsyth 			p++;
98137da2899SCharles.Forsyth 		if(*p != '\0')
98237da2899SCharles.Forsyth 			*p++ = '\0';
98337da2899SCharles.Forsyth 
98437da2899SCharles.Forsyth 		if(p == buf || buf[0] >= '0' && buf[0] <= '9') {
98537da2899SCharles.Forsyth 			tkfreename(l);
98637da2899SCharles.Forsyth 			return TkBadtg;
98737da2899SCharles.Forsyth 		}
98837da2899SCharles.Forsyth 		n = tkmkname(buf);
98937da2899SCharles.Forsyth 		if(n == nil) {
99037da2899SCharles.Forsyth 			tkfreename(l);
99137da2899SCharles.Forsyth 			return TkNomem;
99237da2899SCharles.Forsyth 		}
99337da2899SCharles.Forsyth 		n->link = l;
99437da2899SCharles.Forsyth 		l = n;
99537da2899SCharles.Forsyth 	}
99637da2899SCharles.Forsyth 	tkfreename(OPTION(place, TkName*, o->offset));
99737da2899SCharles.Forsyth 	OPTION(place, TkName*, o->offset) = l;
99837da2899SCharles.Forsyth 	return nil;
99937da2899SCharles.Forsyth }
100037da2899SCharles.Forsyth 
100137da2899SCharles.Forsyth static char*
pfrac(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)100237da2899SCharles.Forsyth pfrac(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
100337da2899SCharles.Forsyth {
100437da2899SCharles.Forsyth 	char *p, *e;
100537da2899SCharles.Forsyth 	int i, n, d, *v;
100637da2899SCharles.Forsyth 
100737da2899SCharles.Forsyth 	*str = tkword(t, *str, buf, ebuf, nil);
100837da2899SCharles.Forsyth 
100937da2899SCharles.Forsyth 	v = &OPTION(place, int, o->offset);
101037da2899SCharles.Forsyth 	n = (int)o->aux;
101137da2899SCharles.Forsyth 	if(n == 0)
101237da2899SCharles.Forsyth 		n = 1;
101337da2899SCharles.Forsyth 	p = buf;
101437da2899SCharles.Forsyth 	for(i = 0; i < n; i++) {
101537da2899SCharles.Forsyth 		p = tkskip(p, " \t");
101637da2899SCharles.Forsyth 		if(*p == '\0')
101737da2899SCharles.Forsyth 			return TkOparg;
101837da2899SCharles.Forsyth 		e = tkfracword(t, &p, &d, nil);
101937da2899SCharles.Forsyth 		if (e != nil)
102037da2899SCharles.Forsyth 			return e;
102137da2899SCharles.Forsyth 		*v++ = d;
102237da2899SCharles.Forsyth 	}
102337da2899SCharles.Forsyth 	return nil;
102437da2899SCharles.Forsyth }
102537da2899SCharles.Forsyth 
102637da2899SCharles.Forsyth /*
102737da2899SCharles.Forsyth  * N.B. nnfrac only accepts aux==nil (can't deal with several items)
102837da2899SCharles.Forsyth  */
102937da2899SCharles.Forsyth static char*
pnnfrac(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)103037da2899SCharles.Forsyth pnnfrac(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
103137da2899SCharles.Forsyth {
103237da2899SCharles.Forsyth 	int oldv;
103337da2899SCharles.Forsyth 	char *e;
103437da2899SCharles.Forsyth 
103537da2899SCharles.Forsyth 	oldv = OPTION(place, int, o->offset);
103637da2899SCharles.Forsyth 
103737da2899SCharles.Forsyth 	e = pfrac(t, o, place, str, buf, ebuf);
103837da2899SCharles.Forsyth 	if(e == nil && OPTION(place, int, o->offset) < 0) {
103937da2899SCharles.Forsyth 		OPTION(place, int, o->offset) = oldv;
104037da2899SCharles.Forsyth 		return TkBadvl;
104137da2899SCharles.Forsyth 	}
104237da2899SCharles.Forsyth 	return e;
104337da2899SCharles.Forsyth 
104437da2899SCharles.Forsyth }
104537da2899SCharles.Forsyth 
104637da2899SCharles.Forsyth typedef struct Tabspec {
104737da2899SCharles.Forsyth 	int	dist;
104837da2899SCharles.Forsyth 	int	just;
104937da2899SCharles.Forsyth 	TkEnv	*env;
105037da2899SCharles.Forsyth } Tabspec;
105137da2899SCharles.Forsyth 
105237da2899SCharles.Forsyth static char*
ptabs(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)105337da2899SCharles.Forsyth ptabs(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
105437da2899SCharles.Forsyth {
105537da2899SCharles.Forsyth 	char *e, *p, *eibuf;
105637da2899SCharles.Forsyth 	TkOption opd, opj;
105737da2899SCharles.Forsyth 	Tabspec tspec;
105837da2899SCharles.Forsyth 	TkTtabstop *tabfirst, *tab, *tabprev;
105937da2899SCharles.Forsyth 	char *ibuf;
106037da2899SCharles.Forsyth 
106137da2899SCharles.Forsyth 	ibuf = mallocz(Tkmaxitem, 0);
106237da2899SCharles.Forsyth 	if(ibuf == nil)
106337da2899SCharles.Forsyth 		return TkNomem;
106437da2899SCharles.Forsyth 	eibuf = ibuf + Tkmaxitem;
106537da2899SCharles.Forsyth 	tspec.env = OPTION(place, TkEnv*, AUXI(o->aux));
106637da2899SCharles.Forsyth 	opd.offset = O(Tabspec, dist);
106737da2899SCharles.Forsyth 	opd.aux = IAUX(O(Tabspec, env));
106837da2899SCharles.Forsyth 	opj.offset = O(Tabspec, dist);
106937da2899SCharles.Forsyth 	opj.aux = tktabjust;
107037da2899SCharles.Forsyth 	tabprev = nil;
107137da2899SCharles.Forsyth 	tabfirst = nil;
107237da2899SCharles.Forsyth 
107337da2899SCharles.Forsyth 	p = tkword(t, *str, buf, ebuf, nil);
107437da2899SCharles.Forsyth 	if(*buf == '\0') {
107537da2899SCharles.Forsyth 		free(ibuf);
107637da2899SCharles.Forsyth 		return TkOparg;
107737da2899SCharles.Forsyth 	}
107837da2899SCharles.Forsyth 	*str = p;
107937da2899SCharles.Forsyth 
108037da2899SCharles.Forsyth 	p = buf;
108137da2899SCharles.Forsyth 	while(*p != '\0') {
108237da2899SCharles.Forsyth 		e = pdist(t, &opd, &tspec, &p, ibuf, eibuf);
108337da2899SCharles.Forsyth 		if(e != nil) {
108437da2899SCharles.Forsyth 			free(ibuf);
108537da2899SCharles.Forsyth 			return e;
108637da2899SCharles.Forsyth 		}
108737da2899SCharles.Forsyth 
108837da2899SCharles.Forsyth 		e = pstab(t, &opj, &tspec, &p, ibuf, eibuf);
108937da2899SCharles.Forsyth 		if(e != nil)
109037da2899SCharles.Forsyth 			tspec.just = Tkleft;
109137da2899SCharles.Forsyth 
109237da2899SCharles.Forsyth 		tab = malloc(sizeof(TkTtabstop));
109337da2899SCharles.Forsyth 		if(tab == nil) {
109437da2899SCharles.Forsyth 			free(ibuf);
109537da2899SCharles.Forsyth 			return TkNomem;
109637da2899SCharles.Forsyth 		}
109737da2899SCharles.Forsyth 
109837da2899SCharles.Forsyth 		tab->pos = tspec.dist;
109937da2899SCharles.Forsyth 		tab->justify = tspec.just;
110037da2899SCharles.Forsyth 		tab->next = nil;
110137da2899SCharles.Forsyth 		if(tabfirst == nil)
110237da2899SCharles.Forsyth 			tabfirst = tab;
110337da2899SCharles.Forsyth 		else
110437da2899SCharles.Forsyth 			tabprev->next = tab;
110537da2899SCharles.Forsyth 		tabprev = tab;
110637da2899SCharles.Forsyth 	}
110737da2899SCharles.Forsyth 	free(ibuf);
110837da2899SCharles.Forsyth 
110937da2899SCharles.Forsyth 	tab = OPTION(place, TkTtabstop*, o->offset);
111037da2899SCharles.Forsyth 	if(tab != nil)
111137da2899SCharles.Forsyth 		free(tab);
111237da2899SCharles.Forsyth 	OPTION(place, TkTtabstop*, o->offset) = tabfirst;
111337da2899SCharles.Forsyth 	return nil;
111437da2899SCharles.Forsyth }
111537da2899SCharles.Forsyth 
111637da2899SCharles.Forsyth char*
tkxyparse(Tk * tk,char ** parg,Point * p)111737da2899SCharles.Forsyth tkxyparse(Tk* tk, char **parg, Point *p)
111837da2899SCharles.Forsyth {
111937da2899SCharles.Forsyth 	char *buf;
112037da2899SCharles.Forsyth 
112137da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
112237da2899SCharles.Forsyth 	if(buf == nil)
112337da2899SCharles.Forsyth 		return TkNomem;
112437da2899SCharles.Forsyth 
112537da2899SCharles.Forsyth 	*parg = tkword(tk->env->top, *parg, buf, buf+Tkmaxitem, nil);
112637da2899SCharles.Forsyth 	if(*buf == '\0') {
112737da2899SCharles.Forsyth 		free(buf);
112837da2899SCharles.Forsyth 		return TkOparg;
112937da2899SCharles.Forsyth 	}
113037da2899SCharles.Forsyth 	p->x = atoi(buf);
113137da2899SCharles.Forsyth 
113237da2899SCharles.Forsyth 	*parg = tkword(tk->env->top, *parg, buf, buf+Tkmaxitem, nil);
113337da2899SCharles.Forsyth 	if(*buf == '\0') {
113437da2899SCharles.Forsyth 		free(buf);
113537da2899SCharles.Forsyth 		return TkOparg;
113637da2899SCharles.Forsyth 	}
113737da2899SCharles.Forsyth 	p->y = atoi(buf);
113837da2899SCharles.Forsyth 
113937da2899SCharles.Forsyth 	free(buf);
114037da2899SCharles.Forsyth 	return nil;
114137da2899SCharles.Forsyth }
114237da2899SCharles.Forsyth 
114337da2899SCharles.Forsyth static char*
plist(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)114437da2899SCharles.Forsyth plist(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
114537da2899SCharles.Forsyth {
114637da2899SCharles.Forsyth 	char *w, ***p, *wbuf, *ewbuf, **v, **nv;
114737da2899SCharles.Forsyth 	int n, m, i, found;
114837da2899SCharles.Forsyth 
114937da2899SCharles.Forsyth 	*str = tkword(t, *str, buf, ebuf, nil);
115037da2899SCharles.Forsyth 	n = strlen(buf) + 1;
115137da2899SCharles.Forsyth 	wbuf = mallocz(n, 0);
115237da2899SCharles.Forsyth 	if (wbuf == nil)
115337da2899SCharles.Forsyth 		return TkNomem;		/* XXX should we free old values too? */
115437da2899SCharles.Forsyth 	ewbuf = &wbuf[n];
115537da2899SCharles.Forsyth 
115637da2899SCharles.Forsyth 	p = &OPTION(place, char**, o->offset);
115737da2899SCharles.Forsyth 	if (*p != nil){
115837da2899SCharles.Forsyth 		for (v = *p; *v; v++)
115937da2899SCharles.Forsyth 			free(*v);
116037da2899SCharles.Forsyth 		free(*p);
116137da2899SCharles.Forsyth 	}
116237da2899SCharles.Forsyth 	n = 0;
116337da2899SCharles.Forsyth 	m = 4;
116437da2899SCharles.Forsyth 	w = buf;
116537da2899SCharles.Forsyth 	v = malloc(m * sizeof(char*));
116637da2899SCharles.Forsyth 	if (v == nil)
116737da2899SCharles.Forsyth 		goto Error;
116837da2899SCharles.Forsyth 	for (;;) {
116937da2899SCharles.Forsyth 		w = tkword(t, w, wbuf, ewbuf, &found);
117037da2899SCharles.Forsyth 		if (!found)
117137da2899SCharles.Forsyth 			break;
117237da2899SCharles.Forsyth 		if (n == m - 1) {
117337da2899SCharles.Forsyth 			m += m/2;
117437da2899SCharles.Forsyth 			nv = realloc(v, m * sizeof(char*));
117537da2899SCharles.Forsyth 			if (nv == nil)
117637da2899SCharles.Forsyth 				goto Error;
117737da2899SCharles.Forsyth 			v = nv;
117837da2899SCharles.Forsyth 		}
117937da2899SCharles.Forsyth 		v[n] = strdup(wbuf);
118037da2899SCharles.Forsyth 		if (v[n] == nil)
118137da2899SCharles.Forsyth 			goto Error;
118237da2899SCharles.Forsyth 		n++;
118337da2899SCharles.Forsyth 	}
118437da2899SCharles.Forsyth 	v[n++] = nil;
118537da2899SCharles.Forsyth 	*p = realloc(v, n * sizeof(char*));
118637da2899SCharles.Forsyth 	free(wbuf);
118737da2899SCharles.Forsyth 	return nil;
118837da2899SCharles.Forsyth Error:
118937da2899SCharles.Forsyth 	free(buf);
119037da2899SCharles.Forsyth 	for (i = 0; i < n; i++)
119137da2899SCharles.Forsyth 		free(v[i]);
119237da2899SCharles.Forsyth 	free(v);
119337da2899SCharles.Forsyth 	*p = nil;
119437da2899SCharles.Forsyth 	return TkNomem;
119537da2899SCharles.Forsyth }
1196