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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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 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 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* 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* 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* 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* 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* 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* 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* 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* 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* 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* 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