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