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