1 #include "lib9.h"
2 #include "kernel.h"
3 #include "draw.h"
4 #include "tk.h"
5
6 #define O(t, e) ((long)(&((t*)0)->e))
7
8 static char* pdist(TkTop*, TkOption*, void*, char**, char*, char*);
9 static char* pstab(TkTop*, TkOption*, void*, char**, char*, char*);
10 static char* ptext(TkTop*, TkOption*, void*, char**, char*, char*);
11 static char* pwinp(TkTop*, TkOption*, void*, char**, char*, char*);
12 static char* pbmap(TkTop*, TkOption*, void*, char**, char*, char*);
13 static char* pbool(TkTop*, TkOption*, void*, char**, char*, char*);
14 static char* pfont(TkTop*, TkOption*, void*, char**, char*, char*);
15 static char* pfrac(TkTop*, TkOption*, void*, char**, char*, char*);
16 static char* pnnfrac(TkTop*, TkOption*, void*, char**, char*, char*);
17 static char* pctag(TkTop*, TkOption*, void*, char**, char*, char*);
18 static char* ptabs(TkTop*, TkOption*, void*, char**, char*, char*);
19 static char* pcolr(TkTop*, TkOption*, void*, char**, char*, char*);
20 static char* pimag(TkTop*, TkOption*, void*, char**, char*, char*);
21 static char* psize(TkTop*, TkOption*, void*, char**, char*, char*);
22 static char* pnndist(TkTop*, TkOption*, void*, char**, char*, char*);
23 static char* pact(TkTop*, TkOption*, void*, char**, char*, char*);
24 static char* pignore(TkTop*, TkOption*, void*, char**, char*, char*);
25 static char* psticky(TkTop*, TkOption*, void*, char**, char*, char*);
26 static char* plist(TkTop*, TkOption*, void*, char**, char*, char*);
27
28 static char* (*oparse[])(TkTop*, TkOption*, void*, char**, char*, char*) =
29 {
30 /* OPTdist */ pdist,
31 /* OPTstab */ pstab,
32 /* OPTtext */ ptext,
33 /* OPTwinp */ pwinp,
34 /* OPTflag */ pstab,
35 /* OPTbmap */ pbmap,
36 /* OPTbool */ pbool,
37 /* OPTfont */ pfont,
38 /* OPTfrac */ pfrac,
39 /* OPTnnfrac */ pnnfrac,
40 /* OPTctag */ pctag,
41 /* OPTtabs */ ptabs,
42 /* OPTcolr */ pcolr,
43 /* OPTimag */ pimag,
44 /* OPTsize */ psize,
45 /* OPTnndist */ pnndist,
46 /* OPTact */ pact,
47 /* OPTignore */ pignore,
48 /* OPTsticky */ psticky,
49 /* OPTlist */ plist,
50 /* OPTflags */ pstab,
51 };
52
53 char*
tkskip(char * s,char * bl)54 tkskip(char *s, char *bl)
55 {
56 char *p;
57
58 while(*s) {
59 for(p = bl; *p; p++)
60 if(*p == *s)
61 break;
62 if(*p == '\0')
63 return s;
64 s++;
65 }
66 return s;
67 }
68
69 /* XXX - Tad: error propagation? */
70 char*
tkword(TkTop * t,char * str,char * buf,char * ebuf,int * gotarg)71 tkword(TkTop *t, char *str, char *buf, char *ebuf, int *gotarg)
72 {
73 int c, lev, tmp;
74 char *val, *e, *p, *cmd;
75 if (gotarg == nil)
76 gotarg = &tmp;
77
78 /*
79 * ebuf is one beyond last byte in buf; leave room for nul byte in
80 * all cases.
81 */
82 --ebuf;
83
84 str = tkskip(str, " \t");
85 *gotarg = 1;
86 lev = 1;
87 switch(*str) {
88 case '{':
89 /* XXX - DBK: According to Ousterhout (p.37), while back=
90 * slashed braces don't count toward finding the matching
91 * closing braces, the backslashes should not be removed.
92 * Presumably this also applies to other backslashed
93 * characters: the backslash should not be removed.
94 */
95 str++;
96 while(*str && buf < ebuf) {
97 c = *str++;
98 if(c == '\\') {
99 if(*str == '}' || *str == '{' || *str == '\\')
100 c = *str++;
101 } else if(c == '}') {
102 lev--;
103 if(lev == 0)
104 break;
105 } else if(c == '{')
106 lev++;
107 *buf++ = c;
108 }
109 break;
110 case '[':
111 /* XXX - DBK: According to Ousterhout (p. 33) command
112 * substitution may occur anywhere within a word, not
113 * only (as here) at the beginning.
114 */
115 cmd = malloc(strlen(str)); /* not strlen+1 because the first character is skipped */
116 if ( cmd == nil ) {
117 buf[0] = '\0'; /* DBK - Why not an error message? */
118 return str;
119 }
120 p = cmd;
121 str++;
122 while(*str) {
123 c = *str++;
124 if(c == '\\') {
125 if(*str == ']' || *str == '[' || *str == '\\')
126 c = *str++;
127 } else if(c == ']') {
128 lev--;
129 if(lev == 0)
130 break;
131 } else if(c == '[')
132 lev++;
133 *p++ = c;
134 }
135 *p = '\0';
136 val = nil;
137 e = tkexec(t, cmd, &val);
138 free(cmd);
139 /* XXX - Tad: is this appropriate behavior?
140 * Am I sure that the error doesn't need to be
141 * propagated back to the caller?
142 */
143 if(e == nil && val != nil) {
144 strncpy(buf, val, ebuf-buf);
145 buf = ebuf;
146 free(val);
147 }
148 break;
149 case '\'':
150 str++;
151 while(*str && buf < ebuf)
152 *buf++ = *str++;
153 break;
154 case '\0':
155 *gotarg = 0;
156 break;
157 default:
158 /* XXX - DBK: See comment above about command substitution.
159 * Also, any backslashed character should be replaced by
160 * itself (e.g. to put a space, tab, or [ into a word.
161 * We assume that the C compiler has already done the
162 * standard ANSI C substitutions. (But should we?)
163 */
164 while(*str && *str != ' ' && *str != '\t' && buf < ebuf)
165 *buf++ = *str++;
166 }
167 *buf = '\0';
168 return str;
169 }
170
171 static TkOption*
Getopt(TkOption * o,char * buf)172 Getopt(TkOption *o, char *buf)
173 {
174 while(o->o != nil) {
175 if(strcmp(buf, o->o) == 0)
176 return o;
177 o++;
178 }
179 return nil;
180 }
181
182 TkName*
tkmkname(char * name)183 tkmkname(char *name)
184 {
185 TkName *n;
186
187 n = malloc(sizeof(struct TkName)+strlen(name));
188 if(n == nil)
189 return nil;
190 strcpy(n->name, name);
191 n->link = nil;
192 n->obj = nil;
193 return n;
194 }
195
196 char*
tkparse(TkTop * t,char * str,TkOptab * ot,TkName ** nl)197 tkparse(TkTop *t, char *str, TkOptab *ot, TkName **nl)
198 {
199 int l;
200 TkOptab *ft;
201 TkOption *o;
202 TkName *f, *n;
203 char *e, *buf, *ebuf;
204
205 l = strlen(str);
206 if (l < Tkmaxitem)
207 l = Tkmaxitem;
208 buf = malloc(l + 1);
209 if(buf == 0)
210 return TkNomem;
211 ebuf = buf + l + 1;
212
213 e = nil;
214 while(e == nil) {
215 str = tkword(t, str, buf, ebuf, nil);
216 switch(*buf) {
217 case '\0':
218 goto done;
219 case '-':
220 if (buf[1] != '\0') {
221 for(ft = ot; ft->ptr; ft++) {
222 o = Getopt(ft->optab, buf+1);
223 if(o != nil) {
224 e = oparse[o->type](t, o, ft->ptr, &str, buf, ebuf);
225 break;
226 }
227 }
228 if(ft->ptr == nil){
229 e = TkBadop;
230 tkerr(t, buf);
231 }
232 break;
233 }
234 /* fall through if we've got a singleton '-' */
235 default:
236 if(nl == nil) {
237 e = TkBadop;
238 tkerr(t, buf);
239 break;
240 }
241 n = tkmkname(buf);
242 if(n == nil) {
243 e = TkNomem;
244 break;
245 }
246 if(*nl == nil)
247 *nl = n;
248 else {
249 for(f = *nl; f->link; f = f->link)
250 ;
251 f->link = n;
252 }
253 }
254 }
255
256 if(e != nil && nl != nil)
257 tkfreename(*nl);
258 done:
259 free(buf);
260 return e;
261 }
262
263 char*
tkconflist(TkOptab * ot,char ** val)264 tkconflist(TkOptab *ot, char **val)
265 {
266 TkOption *o;
267 char *f, *e;
268
269 f = "-%s";
270 while(ot->ptr != nil) {
271 o = ot->optab;
272 while(o->o != nil) {
273 e = tkvalue(val, f, o->o);
274 if(e != nil)
275 return e;
276 f = " -%s";
277 o++;
278 }
279 ot++;
280 }
281 return nil;
282 }
283
284 char*
tkgencget(TkOptab * ft,char * arg,char ** val,TkTop * t)285 tkgencget(TkOptab *ft, char *arg, char **val, TkTop *t)
286 {
287 Tk *w;
288 char *c;
289 Point g;
290 TkEnv *e;
291 TkStab *s;
292 TkOption *o;
293 int wh, con, i, n, flag, *v;
294 char *r, *buf, *fmt, *out;
295
296 buf = mallocz(Tkmaxitem, 0);
297 if(buf == nil)
298 return TkNomem;
299
300 tkitem(buf, arg);
301 r = buf;
302 if(*r == '-')
303 r++;
304 o = nil;
305 while(ft->ptr) {
306 o = Getopt(ft->optab, r);
307 if(o != nil)
308 break;
309 ft++;
310 }
311 if(o == nil) {
312 tkerr(t, r);
313 free(buf);
314 return TkBadop;
315 }
316
317 switch(o->type) {
318 default:
319 tkerr(t, r);
320 free(buf);
321 return TkBadop;
322 case OPTignore:
323 return nil;
324 case OPTact:
325 w = ft->ptr;
326 g = tkposn(w);
327 n = g.y;
328 if(o->aux == 0)
329 n = g.x;
330 free(buf);
331 return tkvalue(val, "%d", n);
332 case OPTdist:
333 case OPTnndist:
334 free(buf);
335 return tkvalue(val, "%d", OPTION(ft->ptr, int, o->offset));
336 case OPTsize:
337 w = ft->ptr;
338 if(strcmp(r, "width") == 0)
339 wh = w->req.width;
340 else
341 wh = w->req.height;
342 free(buf);
343 return tkvalue(val, "%d", wh);
344 case OPTtext:
345 c = OPTION(ft->ptr, char*, o->offset);
346 if(c == nil)
347 c = "";
348 free(buf);
349 return tkvalue(val, "%s", c);
350 case OPTwinp:
351 w = OPTION(ft->ptr, Tk*, o->offset);
352 if(w == nil || w->name == nil)
353 c = "";
354 else
355 c = w->name->name;
356 free(buf);
357 return tkvalue(val, "%s", c);
358 case OPTstab:
359 s = o->aux;
360 c = "";
361 con = OPTION(ft->ptr, int, o->offset);
362 while(s->val) {
363 if(con == s->con) {
364 c = s->val;
365 break;
366 }
367 s++;
368 }
369 free(buf);
370 return tkvalue(val, "%s", c);
371 case OPTflag:
372 con = OPTION(ft->ptr, int, o->offset);
373 flag = 0;
374 for (s = o->aux; s->val != nil; s++)
375 flag |= s->con;
376 c = "";
377 for (s = o->aux; s->val != nil; s++) {
378 if ((con & flag) == s->con) {
379 c = s->val;
380 break;
381 }
382 }
383 free(buf);
384 return tkvalue(val, "%s", c);
385 case OPTflags:
386 con = OPTION(ft->ptr, int, o->offset);
387 out = mallocz(Tkmaxitem, 0);
388 if(out == nil) {
389 free(buf);
390 return TkNomem;
391 }
392 c = out;
393 for (s = o->aux; s->val != nil; s++) {
394 if (s->con == (s->con&-s->con) && (con & s->con) != 0)
395 c = seprint(c, out+Tkmaxitem, " %s", s->val); /* should this be quoted? */
396 }
397 free(buf);
398 *c = 0;
399 r = tkvalue(val, "%s", out);
400 free(out);
401 return r;
402 case OPTfont:
403 e = OPTION(ft->ptr, TkEnv*, o->offset);
404 free(buf);
405 if (e->font != nil)
406 return tkvalue(val, "%s", e->font->name);
407 return nil;
408 case OPTcolr:
409 e = OPTION(ft->ptr, TkEnv*, o->offset);
410 i = AUXI(o->aux);
411 free(buf);
412 return tkvalue(val, "#%.8lux", e->colors[i]);
413 case OPTfrac:
414 case OPTnnfrac:
415 v = &OPTION(ft->ptr, int, o->offset);
416 n = (int)o->aux;
417 if(n == 0)
418 n = 1;
419 fmt = "%s";
420 for(i = 0; i < n; i++) {
421 tkfprint(buf, *v++);
422 r = tkvalue(val, fmt, buf);
423 if(r != nil) {
424 free(buf);
425 return r;
426 }
427 fmt = " %s";
428 }
429 free(buf);
430 return nil;
431 case OPTbmap:
432 //free(buf);
433 return tkvalue(val, "%d", OPTION(ft->ptr, Image*, o->offset) != nil);
434 case OPTimag:
435 //free(buf);
436 return tkvalue(val, "%d", OPTION(ft->ptr, TkImg*, o->offset) != nil);
437 }
438 }
439
440 static char*
pact(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)441 pact(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
442 {
443 USED(buf);
444 USED(ebuf);
445 USED(str);
446 USED(place);
447 tkerr(t, o->o);
448 return TkBadop;
449 }
450
451 static char*
pignore(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)452 pignore(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
453 {
454 char *p;
455 USED(t);
456 USED(o);
457 USED(place);
458
459 p = tkword(t, *str, buf, ebuf, nil);
460 if(*buf == '\0')
461 return TkOparg;
462 *str = p;
463 return nil;
464 }
465
466 static char*
pdist(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)467 pdist(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
468 {
469 int d;
470 char *e;
471 TkEnv *env;
472
473 USED(buf);
474 USED(ebuf);
475
476 /*
477 * this is a bit of a hack, as 0 is a valid option offset,
478 * but a nil aux is commonly used when 'w' and 'h' suffixes
479 * aren't appropriate.
480 * just make sure that no structure placed in TkOptab->ptr
481 * with an OPTdist element has a TkEnv as its first member.
482 */
483
484 if (o->aux == nil)
485 env = nil;
486 else
487 env = OPTION(place, TkEnv*, AUXI(o->aux));
488 e = tkfracword(t, str, &d, env);
489 if(e != nil)
490 return e;
491 OPTION(place, int, o->offset) = TKF2I(d);
492 return nil;
493 }
494
495 static char*
pnndist(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)496 pnndist(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
497 {
498 char* e;
499 int oldv;
500
501 oldv = OPTION(place, int, o->offset);
502 e = pdist(t, o, place, str, buf, ebuf);
503 if(e == nil && OPTION(place, int, o->offset) < 0) {
504 OPTION(place, int, o->offset) = oldv;
505 return TkBadvl;
506 }
507 return e;
508 }
509
510 static char*
psize(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)511 psize(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
512 {
513 Tk *tk;
514 char *e;
515 int d, off;
516
517 USED(ebuf);
518 e = tkfracword(t, str, &d, OPTION(place, TkEnv*, AUXI(o->aux)));
519 if (e != nil)
520 return e;
521 if(d < 0)
522 return TkBadvl;
523
524 tk = place;
525 /*
526 * XXX there's no way of resetting Tksetwidth or Tksetheight.
527 * could perhaps allow it by setting width/height to {}
528 */
529 if(strcmp(buf+1, "width") == 0) {
530 tk->flag |= Tksetwidth;
531 off = O(Tk, req.width);
532 }
533 else {
534 tk->flag |= Tksetheight;
535 off = O(Tk, req.height);
536 }
537 OPTION(place, int, off) = TKF2I(d);
538 return nil;
539 }
540
541 static TkStab*
lookstab(TkStab * s,char * word)542 lookstab(TkStab *s, char *word)
543 {
544 for(; s->val != nil; s++)
545 if(strcmp(s->val, word) == 0)
546 return s;
547 return nil;
548 }
549
550 static char*
pstab(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)551 pstab(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
552 {
553 char *p, *fields[8];
554 int mask, val, nf;
555 TkStab *s, *c;
556
557 p = tkword(t, *str, buf, ebuf, nil);
558 if(*buf == '\0')
559 return TkOparg;
560
561 if(o->type == OPTstab) {
562 s = lookstab(o->aux, buf);
563 if(s == nil)
564 return TkBadvl;
565 *str = p;
566 OPTION(place, int, o->offset) = s->con;
567 return nil;
568 }
569
570 nf = getfields(buf, fields, nelem(fields), 1, " \t,");
571 if(nf < 1 || nf > 1 && o->type != OPTflags)
572 return TkBadvl;
573
574 mask = 0;
575 for(c = o->aux; c->val; c++)
576 mask |= c->con;
577
578 val = 0;
579 while(--nf >= 0) {
580 s = lookstab(o->aux, fields[nf]);
581 if(s == nil)
582 return TkBadvl;
583 val |= s->con;
584 }
585 *str = p;
586
587 OPTION(place, int, o->offset) &= ~mask;
588 OPTION(place, int, o->offset) |= val;
589
590 /*
591 * a hack, but otherwise we have to dirty the focus order
592 * every time any command is executed on a widget
593 */
594 if(strcmp(o->o, "takefocus") == 0)
595 tkdirtyfocusorder(t);
596 return nil;
597 }
598
599 enum {
600 Stickyn = (1<<0),
601 Stickye = (1<<1),
602 Stickys = (1<<2),
603 Stickyw = (1<<3)
604 };
605
606 static int stickymap[16] =
607 {
608 0,
609 Tknorth,
610 Tkeast,
611 Tknorth|Tkeast,
612 Tksouth,
613 Tkfilly,
614 Tksouth|Tkeast,
615 Tkeast|Tkfilly,
616 Tkwest,
617 Tknorth|Tkwest,
618 Tkfillx,
619 Tknorth|Tkfillx,
620 Tksouth|Tkwest,
621 Tkwest|Tkfilly,
622 Tksouth|Tkfillx,
623 Tkfillx|Tkfilly,
624 };
625
626 static char*
psticky(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)627 psticky(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
628 {
629 char *p, *s;
630 int flag, sflag;
631
632 p = tkword(t, *str, buf, ebuf, nil);
633 *str = p;
634
635 flag = 0;
636 for (s = buf; *s; s++) {
637 switch (*s) {
638 case 'n':
639 flag |= Stickyn;
640 break;
641 case 's':
642 flag |= Stickys;
643 break;
644 case 'e':
645 flag |= Stickye;
646 break;
647 case 'w':
648 flag |= Stickyw;
649 break;
650 case ' ':
651 case ',':
652 break;
653 default:
654 return TkBadvl;
655 }
656 }
657 sflag = OPTION(place, int, o->offset) & ~(Tkanchor|Tkfill);
658 OPTION(place, int, o->offset) = sflag | stickymap[flag];
659 return nil;
660 }
661
662 static char*
ptext(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)663 ptext(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
664 {
665 char **p;
666
667 *str = tkword(t, *str, buf, ebuf, nil);
668
669 p = &OPTION(place, char*, o->offset);
670 if(*p != nil)
671 free(*p);
672 if(buf[0] == '\0')
673 *p = nil;
674 else {
675 *p = strdup(buf);
676 if(*p == nil)
677 return TkNomem;
678 }
679 return nil;
680 }
681
682 static char*
pimag(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)683 pimag(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
684 {
685 int locked;
686 Display *d;
687 TkImg **p, *i;
688
689 i = nil;
690 p = &OPTION(place, TkImg*, o->offset);
691 *str = tkword(t, *str, buf, ebuf, nil);
692 if(*buf != '\0') {
693 i = tkname2img(t, buf);
694 if(i == nil)
695 return TkBadvl;
696 i->ref++;
697 }
698
699 if(*p != nil) {
700 d = t->display;
701 locked = lockdisplay(d);
702 tkimgput(*p);
703 if(locked)
704 unlockdisplay(d);
705 }
706 *p = i;
707 return nil;
708 }
709
710 static char*
pbmap(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)711 pbmap(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
712 {
713 Display *d;
714 Image *i, **p;
715 int locked, fd;
716 char *c;
717
718 p = &OPTION(place, Image*, o->offset);
719
720 d = t->display;
721 *str = tkword(t, *str, buf, ebuf, nil);
722 if(*buf == '\0' || *buf == '-') {
723 if(*p != nil) {
724 locked = lockdisplay(d);
725 freeimage(*p);
726 if(locked)
727 unlockdisplay(d);
728 *p = nil;
729 }
730 return nil;
731 }
732
733 if(buf[0] == '@')
734 i = display_open(d, buf+1);
735 else if(buf[0] == '<') {
736 buf++;
737 fd = strtoul(buf, &c, 0);
738 if(c == buf) {
739 return TkBadvl;
740 }
741 i = readimage(d, fd, 1);
742 }
743 else {
744 char *file;
745
746 file = mallocz(Tkmaxitem, 0);
747 if(file == nil)
748 return TkNomem;
749
750 snprint(file, Tkmaxitem, "/icons/tk/%s", buf);
751 i = display_open(d, file);
752 free(file);
753 }
754 if(i == nil)
755 return TkBadbm;
756
757 if(*p != nil) {
758 locked = lockdisplay(d);
759 freeimage(*p);
760 if(locked)
761 unlockdisplay(d);
762 }
763 *p = i;
764 return nil;
765 }
766
767 static char*
pfont(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)768 pfont(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
769 {
770 TkEnv *e;
771 Display *d;
772 int locked;
773 Font *font;
774
775 *str = tkword(t, *str, buf, ebuf, nil);
776 if(*buf == '\0')
777 return TkOparg;
778
779 d = t->display;
780 font = font_open(d, buf);
781 if(font == nil)
782 return TkBadft;
783
784 e = tkdupenv(&OPTION(place, TkEnv*, o->offset));
785 if(e == nil) {
786 freefont(font); /* XXX lockdisplay around this? */
787 return TkNomem;
788 }
789 if(e->font)
790 font_close(e->font);
791 e->font = font;
792
793 locked = lockdisplay(d);
794 e->wzero = stringwidth(font, "0");
795 if ( e->wzero <= 0 )
796 e->wzero = e->font->height / 2;
797 if(locked)
798 unlockdisplay(d);
799
800 return nil;
801 }
802
803 static int
hex(int c)804 hex(int c)
805 {
806 if(c >= 'a')
807 c -= 'a'-'A';
808 if(c >= 'A')
809 c = 10 + (c - 'A');
810 else
811 c -= '0';
812 return c;
813 }
814
815 static ulong
changecol(TkEnv * e,int setcol,int col,ulong rgba)816 changecol(TkEnv *e, int setcol, int col, ulong rgba)
817 {
818 if (setcol) {
819 e->set |= (1<<col);
820 } else {
821 rgba = 0;
822 e->set &= ~(1<<col);
823 }
824 e->colors[col] = rgba;
825 return rgba;
826 }
827
828 char*
tkparsecolor(char * buf,ulong * rgba)829 tkparsecolor(char *buf, ulong *rgba)
830 {
831 char *p, *q, *e;
832 int R, G, B, A;
833 int i, alpha, len, alen;
834 /*
835 * look for alpha modifier in *#AA or *0.5 format
836 */
837 len = strlen(buf);
838 p = strchr(buf, '*');
839 if(p != nil) {
840 alen = len - (p - buf);
841 if(p[1] == '#') {
842 if(alen != 4)
843 return TkBadvl;
844 alpha = (hex(p[2])<<4) | (hex(p[3]));
845 } else {
846 q = p+1;
847 e = tkfrac(&q, &alpha, nil);
848 if (e != nil)
849 return e;
850 alpha = TKF2I(alpha * 0xff);
851 }
852 *p = '\0';
853 len -= alen;
854 } else
855 alpha = 0xff;
856
857 if (*buf == '#') {
858 switch(len) {
859 case 4: /* #RGB */
860 R = hex(buf[1]);
861 G = hex(buf[2]);
862 B = hex(buf[3]);
863 *rgba = (R<<28) | (G<<20) | (B<<12) | 0xff;
864 break;
865 case 7: /* #RRGGBB */
866 R = (hex(buf[1])<<4)|(hex(buf[2]));
867 G = (hex(buf[3])<<4)|(hex(buf[4]));
868 B = (hex(buf[5])<<4)|(hex(buf[6]));
869 *rgba = (R<<24) | (G<<16) | (B<<8) | 0xff;
870 break;
871 case 9: /* #RRGGBBAA */
872 R = (hex(buf[1])<<4)|(hex(buf[2]));
873 G = (hex(buf[3])<<4)|(hex(buf[4]));
874 B = (hex(buf[5])<<4)|(hex(buf[6]));
875 A = (hex(buf[7])<<4)|(hex(buf[8]));
876 *rgba = (R<<24) | (G<<16) | (B<<8) | A;
877 break;
878 default:
879 return TkBadvl;
880 }
881 } else {
882 for(i = 0; tkcolortab[i].val != nil; i++)
883 if (!strcmp(tkcolortab[i].val, buf))
884 break;
885 if (tkcolortab[i].val == nil)
886 return TkBadvl;
887 *rgba = tkcolortab[i].con;
888 }
889 if (alpha != 0xff) {
890 tkrgbavals(*rgba, &R, &G, &B, &A);
891 A = (A * alpha) / 255;
892 *rgba = tkrgba(R, G, B, A);
893 }
894 return nil;
895 }
896
897 static char*
pcolr(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)898 pcolr(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
899 {
900 TkEnv *env;
901 char *e;
902 ulong rgba, dark, light;
903 int color, setcol;
904
905 *str = tkword(t, *str, buf, ebuf, nil);
906 rgba = 0;
907 if(*buf == '\0') {
908 setcol = 0;
909 } else {
910 setcol = 1;
911 e = tkparsecolor(buf, &rgba);
912 if(e != nil)
913 return e;
914 }
915
916 env = tkdupenv(&OPTION(place, TkEnv*, o->offset));
917 if(env == nil)
918 return TkNomem;
919
920 color = AUXI(o->aux);
921 rgba = changecol(env, setcol, color, rgba);
922 if(color == TkCbackgnd || color == TkCselectbgnd || color == TkCactivebgnd) {
923 if (setcol) {
924 light = tkrgbashade(rgba, TkLightshade);
925 dark = tkrgbashade(rgba, TkDarkshade);
926 } else
927 light = dark = 0;
928 changecol(env, setcol, color+1, light);
929 changecol(env, setcol, color+2, dark);
930 }
931 return nil;
932 }
933
934 static char*
pbool(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)935 pbool(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
936 {
937 USED(buf);
938 USED(ebuf);
939 USED(str);
940 USED(t);
941 OPTION(place, int, o->offset) = 1;
942 return nil;
943 }
944
945 static char*
pwinp(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)946 pwinp(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
947 {
948 Tk *f;
949 char *p;
950
951 p = tkword(t, *str, buf, ebuf, nil);
952 if(*buf == '\0')
953 return TkOparg;
954 *str = p;
955
956 f = tklook(t, buf, 0);
957 if(f == nil){
958 tkerr(t, buf);
959 return TkBadwp;
960 }
961
962 OPTION(place, Tk*, o->offset) = f;
963 return nil;
964 }
965
966 static char*
pctag(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)967 pctag(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
968 {
969 char *p;
970 TkName *n, *l;
971
972 *str = tkword(t, *str, buf, ebuf, nil);
973
974 l = nil;
975 p = buf;
976 while(*p) {
977 p = tkskip(p, " \t");
978 buf = p;
979 while(*p && *p != ' ' && *p != '\t')
980 p++;
981 if(*p != '\0')
982 *p++ = '\0';
983
984 if(p == buf || buf[0] >= '0' && buf[0] <= '9') {
985 tkfreename(l);
986 return TkBadtg;
987 }
988 n = tkmkname(buf);
989 if(n == nil) {
990 tkfreename(l);
991 return TkNomem;
992 }
993 n->link = l;
994 l = n;
995 }
996 tkfreename(OPTION(place, TkName*, o->offset));
997 OPTION(place, TkName*, o->offset) = l;
998 return nil;
999 }
1000
1001 static char*
pfrac(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)1002 pfrac(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
1003 {
1004 char *p, *e;
1005 int i, n, d, *v;
1006
1007 *str = tkword(t, *str, buf, ebuf, nil);
1008
1009 v = &OPTION(place, int, o->offset);
1010 n = (int)o->aux;
1011 if(n == 0)
1012 n = 1;
1013 p = buf;
1014 for(i = 0; i < n; i++) {
1015 p = tkskip(p, " \t");
1016 if(*p == '\0')
1017 return TkOparg;
1018 e = tkfracword(t, &p, &d, nil);
1019 if (e != nil)
1020 return e;
1021 *v++ = d;
1022 }
1023 return nil;
1024 }
1025
1026 /*
1027 * N.B. nnfrac only accepts aux==nil (can't deal with several items)
1028 */
1029 static char*
pnnfrac(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)1030 pnnfrac(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
1031 {
1032 int oldv;
1033 char *e;
1034
1035 oldv = OPTION(place, int, o->offset);
1036
1037 e = pfrac(t, o, place, str, buf, ebuf);
1038 if(e == nil && OPTION(place, int, o->offset) < 0) {
1039 OPTION(place, int, o->offset) = oldv;
1040 return TkBadvl;
1041 }
1042 return e;
1043
1044 }
1045
1046 typedef struct Tabspec {
1047 int dist;
1048 int just;
1049 TkEnv *env;
1050 } Tabspec;
1051
1052 static char*
ptabs(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)1053 ptabs(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
1054 {
1055 char *e, *p, *eibuf;
1056 TkOption opd, opj;
1057 Tabspec tspec;
1058 TkTtabstop *tabfirst, *tab, *tabprev;
1059 char *ibuf;
1060
1061 ibuf = mallocz(Tkmaxitem, 0);
1062 if(ibuf == nil)
1063 return TkNomem;
1064 eibuf = ibuf + Tkmaxitem;
1065 tspec.env = OPTION(place, TkEnv*, AUXI(o->aux));
1066 opd.offset = O(Tabspec, dist);
1067 opd.aux = IAUX(O(Tabspec, env));
1068 opj.offset = O(Tabspec, dist);
1069 opj.aux = tktabjust;
1070 tabprev = nil;
1071 tabfirst = nil;
1072
1073 p = tkword(t, *str, buf, ebuf, nil);
1074 if(*buf == '\0') {
1075 free(ibuf);
1076 return TkOparg;
1077 }
1078 *str = p;
1079
1080 p = buf;
1081 while(*p != '\0') {
1082 e = pdist(t, &opd, &tspec, &p, ibuf, eibuf);
1083 if(e != nil) {
1084 free(ibuf);
1085 return e;
1086 }
1087
1088 e = pstab(t, &opj, &tspec, &p, ibuf, eibuf);
1089 if(e != nil)
1090 tspec.just = Tkleft;
1091
1092 tab = malloc(sizeof(TkTtabstop));
1093 if(tab == nil) {
1094 free(ibuf);
1095 return TkNomem;
1096 }
1097
1098 tab->pos = tspec.dist;
1099 tab->justify = tspec.just;
1100 tab->next = nil;
1101 if(tabfirst == nil)
1102 tabfirst = tab;
1103 else
1104 tabprev->next = tab;
1105 tabprev = tab;
1106 }
1107 free(ibuf);
1108
1109 tab = OPTION(place, TkTtabstop*, o->offset);
1110 if(tab != nil)
1111 free(tab);
1112 OPTION(place, TkTtabstop*, o->offset) = tabfirst;
1113 return nil;
1114 }
1115
1116 char*
tkxyparse(Tk * tk,char ** parg,Point * p)1117 tkxyparse(Tk* tk, char **parg, Point *p)
1118 {
1119 char *buf;
1120
1121 buf = mallocz(Tkmaxitem, 0);
1122 if(buf == nil)
1123 return TkNomem;
1124
1125 *parg = tkword(tk->env->top, *parg, buf, buf+Tkmaxitem, nil);
1126 if(*buf == '\0') {
1127 free(buf);
1128 return TkOparg;
1129 }
1130 p->x = atoi(buf);
1131
1132 *parg = tkword(tk->env->top, *parg, buf, buf+Tkmaxitem, nil);
1133 if(*buf == '\0') {
1134 free(buf);
1135 return TkOparg;
1136 }
1137 p->y = atoi(buf);
1138
1139 free(buf);
1140 return nil;
1141 }
1142
1143 static char*
plist(TkTop * t,TkOption * o,void * place,char ** str,char * buf,char * ebuf)1144 plist(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
1145 {
1146 char *w, ***p, *wbuf, *ewbuf, **v, **nv;
1147 int n, m, i, found;
1148
1149 *str = tkword(t, *str, buf, ebuf, nil);
1150 n = strlen(buf) + 1;
1151 wbuf = mallocz(n, 0);
1152 if (wbuf == nil)
1153 return TkNomem; /* XXX should we free old values too? */
1154 ewbuf = &wbuf[n];
1155
1156 p = &OPTION(place, char**, o->offset);
1157 if (*p != nil){
1158 for (v = *p; *v; v++)
1159 free(*v);
1160 free(*p);
1161 }
1162 n = 0;
1163 m = 4;
1164 w = buf;
1165 v = malloc(m * sizeof(char*));
1166 if (v == nil)
1167 goto Error;
1168 for (;;) {
1169 w = tkword(t, w, wbuf, ewbuf, &found);
1170 if (!found)
1171 break;
1172 if (n == m - 1) {
1173 m += m/2;
1174 nv = realloc(v, m * sizeof(char*));
1175 if (nv == nil)
1176 goto Error;
1177 v = nv;
1178 }
1179 v[n] = strdup(wbuf);
1180 if (v[n] == nil)
1181 goto Error;
1182 n++;
1183 }
1184 v[n++] = nil;
1185 *p = realloc(v, n * sizeof(char*));
1186 free(wbuf);
1187 return nil;
1188 Error:
1189 free(buf);
1190 for (i = 0; i < n; i++)
1191 free(v[i]);
1192 free(v);
1193 *p = nil;
1194 return TkNomem;
1195 }
1196