1/* 2 * zutil.c - misc utilities 3 * 4 * This file is part of zsh, the Z shell. 5 * 6 * Copyright (c) 1999 Sven Wischnowsky 7 * All rights reserved. 8 * 9 * Permission is hereby granted, without written agreement and without 10 * license or royalty fees, to use, copy, modify, and distribute this 11 * software and to distribute modified versions of this software for any 12 * purpose, provided that the above copyright notice and the following 13 * two paragraphs appear in all copies of this software. 14 * 15 * In no event shall Sven Wischnowsky or the Zsh Development Group be liable 16 * to any party for direct, indirect, special, incidental, or consequential 17 * damages arising out of the use of this software and its documentation, 18 * even if Sven Wischnowsky and the Zsh Development Group have been advised of 19 * the possibility of such damage. 20 * 21 * Sven Wischnowsky and the Zsh Development Group specifically disclaim any 22 * warranties, including, but not limited to, the implied warranties of 23 * merchantability and fitness for a particular purpose. The software 24 * provided hereunder is on an "as is" basis, and Sven Wischnowsky and the 25 * Zsh Development Group have no obligation to provide maintenance, 26 * support, updates, enhancements, or modifications. 27 * 28 */ 29 30#include "zutil.mdh" 31#include "zutil.pro" 32 33/* Style stuff. */ 34 35typedef struct stypat *Stypat; 36typedef struct style *Style; 37 38/* A pattern and the styles for it. */ 39 40struct style { 41 struct hashnode node; 42 Stypat pats; /* patterns */ 43}; 44 45struct stypat { 46 Stypat next; 47 char *pat; /* pattern string */ 48 Patprog prog; /* compiled pattern */ 49 int weight; /* how specific is the pattern? */ 50 Eprog eval; /* eval-on-retrieve? */ 51 char **vals; 52}; 53 54/* Hash table of styles and associated functions. */ 55 56static HashTable zstyletab; 57 58/* Memory stuff. */ 59 60static void 61freestylepatnode(Stypat p) 62{ 63 zsfree(p->pat); 64 freepatprog(p->prog); 65 if (p->vals) 66 freearray(p->vals); 67 if (p->eval) 68 freeeprog(p->eval); 69 zfree(p, sizeof(*p)); 70} 71 72static void 73freestylenode(HashNode hn) 74{ 75 Style s = (Style) hn; 76 Stypat p, pn; 77 78 p = s->pats; 79 while (p) { 80 pn = p->next; 81 freestylepatnode(p); 82 p = pn; 83 } 84 85 zsfree(s->node.nam); 86 zfree(s, sizeof(struct style)); 87} 88 89/* 90 * Free the information for one of the patterns associated with 91 * a style. 92 * 93 * If the style s is passed, prev is the previous pattern in the list, 94 * found when scanning. We use this to update the list of patterns. 95 * If this results in their being no remaining patterns, the style 96 * itself is removed from the list of styles. This isn't optimised, 97 * since it's not a very frequent operation; we simply scan down the list 98 * to find the previous entry. 99 */ 100static void 101freestypat(Stypat p, Style s, Stypat prev) 102{ 103 if (s) { 104 if (prev) 105 prev->next = p->next; 106 else 107 s->pats = p->next; 108 } 109 110 freestylepatnode(p); 111 112 if (s && !s->pats) { 113 /* No patterns left, free style */ 114 zstyletab->removenode(zstyletab, s->node.nam); 115 zsfree(s->node.nam); 116 zfree(s, sizeof(*s)); 117 } 118} 119 120/* Pattern to match context when printing nodes */ 121 122static Patprog zstyle_contprog; 123 124/* 125 * Print a node. Print flags as shown. 126 */ 127enum { 128 ZSLIST_NONE, 129 ZSLIST_BASIC, 130 ZSLIST_SYNTAX, 131}; 132 133static void 134printstylenode(HashNode hn, int printflags) 135{ 136 Style s = (Style)hn; 137 Stypat p; 138 char **v; 139 140 if (printflags == ZSLIST_BASIC) { 141 quotedzputs(s->node.nam, stdout); 142 putchar('\n'); 143 } 144 145 for (p = s->pats; p; p = p->next) { 146 if (zstyle_contprog && !pattry(zstyle_contprog, p->pat)) 147 continue; 148 if (printflags == ZSLIST_BASIC) 149 printf("%s %s", (p->eval ? "(eval)" : " "), p->pat); 150 else { 151 printf("zstyle %s", (p->eval ? "-e " : "")); 152 quotedzputs(p->pat, stdout); 153 printf(" %s", s->node.nam); 154 } 155 for (v = p->vals; *v; v++) { 156 putchar(' '); 157 quotedzputs(*v, stdout); 158 } 159 putchar('\n'); 160 } 161} 162 163/* 164 * Scan the list for a particular pattern, maybe adding matches to 165 * the link list (heap memory). Value to be added as 166 * shown in enum 167 */ 168static LinkList zstyle_list; 169static char *zstyle_patname; 170 171enum { 172 ZSPAT_NAME, /* Add style names for matched pattern to list */ 173 ZSPAT_PAT, /* Add all patterns to list, doesn't use patname */ 174 ZSPAT_REMOVE, /* Remove matched pattern, doesn't use list */ 175}; 176 177static void 178scanpatstyles(HashNode hn, int spatflags) 179{ 180 Style s = (Style)hn; 181 Stypat p, q; 182 LinkNode n; 183 184 for (q = NULL, p = s->pats; p; q = p, p = p->next) { 185 switch (spatflags) { 186 case ZSPAT_NAME: 187 if (!strcmp(p->pat, zstyle_patname)) { 188 addlinknode(zstyle_list, s->node.nam); 189 return; 190 } 191 break; 192 193 case ZSPAT_PAT: 194 /* Check pattern isn't already there */ 195 for (n = firstnode(zstyle_list); n; incnode(n)) 196 if (!strcmp(p->pat, (char *) getdata(n))) 197 break; 198 if (!n) 199 addlinknode(zstyle_list, p->pat); 200 break; 201 202 case ZSPAT_REMOVE: 203 if (!strcmp(p->pat, zstyle_patname)) { 204 freestypat(p, s, q); 205 /* 206 * May remove link node itself; that's OK 207 * when scanning but we need to make sure 208 * we don't look at it any more. 209 */ 210 return; 211 } 212 break; 213 } 214 } 215} 216 217 218static HashTable 219newzstyletable(int size, char const *name) 220{ 221 HashTable ht; 222 ht = newhashtable(size, name, NULL); 223 224 ht->hash = hasher; 225 ht->emptytable = emptyhashtable; 226 ht->filltable = NULL; 227 ht->cmpnodes = strcmp; 228 ht->addnode = addhashnode; 229 /* DISABLED is not supported */ 230 ht->getnode = gethashnode2; 231 ht->getnode2 = gethashnode2; 232 ht->removenode = removehashnode; 233 ht->disablenode = NULL; 234 ht->enablenode = NULL; 235 ht->freenode = freestylenode; 236 ht->printnode = printstylenode; 237 238 return ht; 239} 240 241/* Store a value for a style. */ 242 243static int 244setstypat(Style s, char *pat, Patprog prog, char **vals, int eval) 245{ 246 int weight, tmp, first; 247 char *str; 248 Stypat p, q, qq; 249 Eprog eprog = NULL; 250 251 if (eval) { 252 int ef = errflag; 253 254 eprog = parse_string(zjoin(vals, ' ', 1), 0); 255 errflag = ef; 256 257 if (!eprog) 258 { 259 freepatprog(prog); 260 return 1; 261 } 262 263 eprog = dupeprog(eprog, 0); 264 } 265 for (p = s->pats; p; p = p->next) 266 if (!strcmp(pat, p->pat)) { 267 268 /* Exists -> replace. */ 269 270 if (p->vals) 271 freearray(p->vals); 272 if (p->eval) 273 freeeprog(p->eval); 274 p->vals = zarrdup(vals); 275 p->eval = eprog; 276 freepatprog(prog); 277 278 return 0; 279 } 280 281 /* New pattern. */ 282 283 p = (Stypat) zalloc(sizeof(*p)); 284 p->pat = ztrdup(pat); 285 p->prog = prog; 286 p->vals = zarrdup(vals); 287 p->eval = eprog; 288 p->next = NULL; 289 290 /* Calculate the weight. */ 291 292 for (weight = 0, tmp = 2, first = 1, str = pat; *str; str++) { 293 if (first && *str == '*' && (!str[1] || str[1] == ':')) { 294 /* Only `*' in this component. */ 295 tmp = 0; 296 continue; 297 } 298 first = 0; 299 300 if (*str == '(' || *str == '|' || *str == '*' || *str == '[' || 301 *str == '<' || *str == '?' || *str == '#' || *str == '^') 302 /* Is pattern. */ 303 tmp = 1; 304 305 if (*str == ':') { 306 /* Yet another component. */ 307 308 first = 1; 309 weight += tmp; 310 tmp = 2; 311 } 312 } 313 p->weight = (weight += tmp); 314 315 for (qq = NULL, q = s->pats; q && q->weight >= weight; 316 qq = q, q = q->next); 317 318 p->next = q; 319 if (qq) 320 qq->next = p; 321 else 322 s->pats = p; 323 324 return 0; 325} 326 327/* Add a new style. */ 328 329static Style 330addstyle(char *name) 331{ 332 Style s = (Style) zshcalloc(sizeof(*s)); 333 334 zstyletab->addnode(zstyletab, ztrdup(name), s); 335 336 return s; 337} 338 339static char ** 340evalstyle(Stypat p) 341{ 342 int ef = errflag; 343 char **ret, *str; 344 345 unsetparam("reply"); 346 execode(p->eval, 1, 0, "style"); 347 if (errflag) { 348 errflag = ef; 349 return NULL; 350 } 351 errflag = ef; 352 353 queue_signals(); 354 if ((ret = getaparam("reply"))) 355 ret = arrdup(ret); 356 else if ((str = getsparam("reply"))) { 357 ret = (char **) hcalloc(2 * sizeof(char *)); 358 ret[0] = dupstring(str); 359 } 360 unqueue_signals(); 361 unsetparam("reply"); 362 363 return ret; 364} 365 366/* Look up a style for a context pattern. This does the matching. */ 367 368static char ** 369lookupstyle(char *ctxt, char *style) 370{ 371 Style s; 372 Stypat p; 373 374 s = (Style)zstyletab->getnode2(zstyletab, style); 375 if (!s) 376 return NULL; 377 for (p = s->pats; p; p = p->next) 378 if (pattry(p->prog, ctxt)) 379 return (p->eval ? evalstyle(p) : p->vals); 380 381 return NULL; 382} 383 384static int 385bin_zstyle(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) 386{ 387 int min, max, n, add = 0, list = ZSLIST_NONE, eval = 0; 388 389 if (!args[0]) 390 list = ZSLIST_BASIC; 391 else if (args[0][0] == '-') { 392 char oc; 393 394 if ((oc = args[0][1]) && oc != '-') { 395 if (args[0][2]) { 396 zwarnnam(nam, "invalid argument: %s", args[0]); 397 return 1; 398 } 399 if (oc == 'L') { 400 list = ZSLIST_SYNTAX; 401 args++; 402 } else if (oc == 'e') { 403 eval = add = 1; 404 args++; 405 } 406 } else { 407 add = 1; 408 args++; 409 } 410 } else 411 add = 1; 412 413 if (add) { 414 Style s; 415 Patprog prog; 416 char *pat; 417 418 if (arrlen(args) < 2) { 419 zwarnnam(nam, "not enough arguments"); 420 return 1; 421 } 422 pat = dupstring(args[0]); 423 tokenize(pat); 424 425 if (!(prog = patcompile(pat, PAT_ZDUP, NULL))) { 426 zwarnnam(nam, "invalid pattern: %s", args[0]); 427 return 1; 428 } 429 if (!(s = (Style)zstyletab->getnode2(zstyletab, args[1]))) 430 s = addstyle(args[1]); 431 return setstypat(s, args[0], prog, args + 2, eval); 432 } 433 if (list) { 434 Style s; 435 char *context, *stylename; 436 437 switch (arrlen(args)) { 438 case 2: 439 context = args[0]; 440 stylename = args[1]; 441 break; 442 443 case 1: 444 context = args[0]; 445 stylename = NULL; 446 break; 447 448 case 0: 449 context = stylename = NULL; 450 break; 451 452 default: 453 zwarnnam(nam, "too many arguments"); 454 return 1; 455 } 456 if (context) { 457 tokenize(context); 458 zstyle_contprog = patcompile(context, PAT_STATIC, NULL); 459 460 if (!zstyle_contprog) 461 return 1; 462 } else 463 zstyle_contprog = NULL; 464 465 if (stylename) { 466 s = (Style)zstyletab->getnode2(zstyletab, stylename); 467 if (!s) 468 return 1; 469 zstyletab->printnode(&s->node, list); 470 } else { 471 scanhashtable(zstyletab, 1, 0, 0, 472 zstyletab->printnode, list); 473 } 474 475 return 0; 476 } 477 switch (args[0][1]) { 478 case 'd': min = 0; max = -1; break; 479 case 's': min = 3; max = 4; break; 480 case 'b': min = 3; max = 3; break; 481 case 'a': min = 3; max = 3; break; 482 case 't': min = 2; max = -1; break; 483 case 'T': min = 2; max = -1; break; 484 case 'm': min = 3; max = 3; break; 485 case 'g': min = 1; max = 3; break; 486 default: 487 zwarnnam(nam, "invalid option: %s", args[0]); 488 return 1; 489 } 490 n = arrlen(args) - 1; 491 if (n < min) { 492 zwarnnam(nam, "not enough arguments"); 493 return 1; 494 } else if (max >= 0 && n > max) { 495 zwarnnam(nam, "too many arguments"); 496 return 1; 497 } 498 switch (args[0][1]) { 499 case 'd': 500 { 501 Style s; 502 503 if (args[1]) { 504 if (args[2]) { 505 char *pat = args[1]; 506 507 for (args += 2; *args; args++) { 508 if ((s = (Style)zstyletab->getnode2(zstyletab, 509 *args))) { 510 Stypat p, q; 511 512 for (q = NULL, p = s->pats; p; 513 q = p, p = p->next) { 514 if (!strcmp(p->pat, pat)) { 515 freestypat(p, s, q); 516 break; 517 } 518 } 519 } 520 } 521 } else { 522 zstyle_patname = args[1]; 523 524 /* sorting not needed for deletion */ 525 scanhashtable(zstyletab, 0, 0, 0, scanpatstyles, 526 ZSPAT_REMOVE); 527 } 528 } else 529 zstyletab->emptytable(zstyletab); 530 } 531 break; 532 case 's': 533 { 534 char **vals, *ret; 535 int val; 536 537 if ((vals = lookupstyle(args[1], args[2])) && vals[0]) { 538 ret = sepjoin(vals, (args[4] ? args[4] : " "), 0); 539 val = 0; 540 } else { 541 ret = ztrdup(""); 542 val = 1; 543 } 544 setsparam(args[3], ret); 545 546 return val; 547 } 548 break; 549 case 'b': 550 { 551 char **vals, *ret; 552 int val; 553 554 if ((vals = lookupstyle(args[1], args[2])) && 555 vals[0] && !vals[1] && 556 (!strcmp(vals[0], "yes") || 557 !strcmp(vals[0], "true") || 558 !strcmp(vals[0], "on") || 559 !strcmp(vals[0], "1"))) { 560 ret = "yes"; 561 val = 0; 562 } else { 563 ret = "no"; 564 val = 1; 565 } 566 setsparam(args[3], ztrdup(ret)); 567 568 return val; 569 } 570 break; 571 case 'a': 572 { 573 char **vals, **ret; 574 int val; 575 576 if ((vals = lookupstyle(args[1], args[2]))) { 577 ret = zarrdup(vals); 578 val = 0; 579 } else { 580 char *dummy = NULL; 581 582 ret = zarrdup(&dummy); 583 val = 1; 584 } 585 setaparam(args[3], ret); 586 587 return val; 588 } 589 break; 590 case 't': 591 case 'T': 592 { 593 char **vals; 594 595 if ((vals = lookupstyle(args[1], args[2])) && vals[0]) { 596 if (args[3]) { 597 char **ap = args + 3, **p; 598 599 while (*ap) { 600 p = vals; 601 while (*p) 602 if (!strcmp(*ap, *p++)) 603 return 0; 604 ap++; 605 } 606 return 1; 607 } else 608 return !(!strcmp(vals[0], "true") || 609 !strcmp(vals[0], "yes") || 610 !strcmp(vals[0], "on") || 611 !strcmp(vals[0], "1")); 612 } 613 return (args[0][1] == 't' ? (vals ? 1 : 2) : 0); 614 } 615 break; 616 case 'm': 617 { 618 char **vals; 619 Patprog prog; 620 621 tokenize(args[3]); 622 623 if ((vals = lookupstyle(args[1], args[2])) && 624 (prog = patcompile(args[3], PAT_STATIC, NULL))) { 625 while (*vals) 626 if (pattry(prog, *vals++)) 627 return 0; 628 } 629 return 1; 630 } 631 break; 632 case 'g': 633 { 634 int ret = 1; 635 Style s; 636 Stypat p; 637 638 zstyle_list = newlinklist(); 639 640 if (args[2]) { 641 if (args[3]) { 642 if ((s = (Style)zstyletab->getnode2(zstyletab, args[3]))) { 643 for (p = s->pats; p; p = p->next) { 644 if (!strcmp(args[2], p->pat)) { 645 char **v = p->vals; 646 647 while (*v) 648 addlinknode(zstyle_list, *v++); 649 650 ret = 0; 651 break; 652 } 653 } 654 } 655 } else { 656 zstyle_patname = args[2]; 657 scanhashtable(zstyletab, 1, 0, 0, scanpatstyles, 658 ZSPAT_NAME); 659 ret = 0; 660 } 661 } else { 662 scanhashtable(zstyletab, 1, 0, 0, scanpatstyles, 663 ZSPAT_PAT); 664 ret = 0; 665 } 666 set_list_array(args[1], zstyle_list); 667 668 return ret; 669 } 670 } 671 return 0; 672} 673 674/* Format stuff. */ 675 676/* 677 * One chunk of text, to allow recursive handling of ternary 678 * expressions in zformat -f output. 679 * instr The input string. 680 * specs The format specifiers, specs[c] is the string from c:string 681 * outp *outp is the start of the output string 682 * ousedp (*outp)[*ousedp] is where to write next 683 * olenp *olenp is the size allocated for *outp 684 * endchar Terminator character in addition to `\0' (may be '\0') 685 * skip If 1, don't output, just parse. 686 */ 687static char *zformat_substring(char* instr, char **specs, char **outp, 688 int *ousedp, int *olenp, int endchar, int skip) 689{ 690 char *s; 691 692 for (s = instr; *s && *s != endchar; s++) { 693 if (*s == '%') { 694 int right, min = -1, max = -1, outl, testit; 695 char *spec, *start = s; 696 697 if ((right = (*++s == '-'))) 698 s++; 699 700 if (idigit(*s)) { 701 for (min = 0; idigit(*s); s++) 702 min = (min * 10) + (int) STOUC(*s) - '0'; 703 } 704 705 /* Ternary expressions */ 706 testit = (STOUC(*s) == '('); 707 if (testit && s[1] == '-') 708 { 709 /* Allow %(-1... etc. */ 710 right = 1; 711 s++; 712 } 713 if ((*s == '.' || testit) && idigit(s[1])) { 714 for (max = 0, s++; idigit(*s); s++) 715 max = (max * 10) + (int) STOUC(*s) - '0'; 716 } 717 else if (testit) 718 s++; 719 720 if (testit && STOUC(*s)) { 721 int actval, testval, endcharl; 722 723 /* 724 * One one number is useful for ternary expressions. 725 * Remember to put the sign back. 726 */ 727 testval = (min >= 0) ? min : (max >= 0) ? max : 0; 728 if (right) 729 testval *= -1; 730 731 if (specs[STOUC(*s)]) 732 actval = (int)mathevali(specs[STOUC(*s)]); 733 else 734 actval = 0; 735 /* zero means values are equal, i.e. true */ 736 actval -= testval; 737 738 /* careful about premature end of string */ 739 if (!(endcharl = *++s)) 740 return NULL; 741 742 /* 743 * Either skip true text and output false text, or 744 * vice versa... unless we are already skipping. 745 */ 746 if (!(s = zformat_substring(s+1, specs, outp, ousedp, 747 olenp, endcharl, skip || actval))) 748 return NULL; 749 if (!(s = zformat_substring(s+1, specs, outp, ousedp, 750 olenp, ')', skip || !actval))) 751 return NULL; 752 } else if (skip) { 753 continue; 754 } else if ((spec = specs[STOUC(*s)])) { 755 int len; 756 757 if ((len = strlen(spec)) > max && max >= 0) 758 len = max; 759 outl = (min >= 0 ? (min > len ? min : len) : len); 760 761 if (*ousedp + outl >= *olenp) { 762 int nlen = *olenp + outl + 128; 763 char *tmp = (char *) zhalloc(nlen); 764 765 memcpy(tmp, *outp, *olenp); 766 *olenp = nlen; 767 *outp = tmp; 768 } 769 if (len >= outl) { 770 memcpy(*outp + *ousedp, spec, outl); 771 *ousedp += outl; 772 } else { 773 int diff = outl - len; 774 775 if (right) { 776 while (diff--) 777 (*outp)[(*ousedp)++] = ' '; 778 memcpy(*outp + *ousedp, spec, len); 779 *ousedp += len; 780 } else { 781 memcpy(*outp + *ousedp, spec, len); 782 *ousedp += len; 783 while (diff--) 784 (*outp)[(*ousedp)++] = ' '; 785 } 786 } 787 } else { 788 int len = s - start + 1; 789 790 if (*ousedp + len >= *olenp) { 791 int nlen = *olenp + len + 128; 792 char *tmp = (char *) zhalloc(nlen); 793 794 memcpy(tmp, *outp, *olenp); 795 *olenp = nlen; 796 *outp = tmp; 797 } 798 memcpy(*outp + *ousedp, start, len); 799 *ousedp += len; 800 } 801 } else { 802 if (skip) 803 continue; 804 if (*ousedp + 1 >= *olenp) { 805 char *tmp = (char *) zhalloc((*olenp) << 1); 806 807 memcpy(tmp, *outp, *olenp); 808 *olenp <<= 1; 809 *outp = tmp; 810 } 811 (*outp)[(*ousedp)++] = *s; 812 } 813 } 814 815 return s; 816} 817 818static int 819bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) 820{ 821 char opt; 822 823 if (args[0][0] != '-' || !(opt = args[0][1]) || args[0][2]) { 824 zwarnnam(nam, "invalid argument: %s", args[0]); 825 return 1; 826 } 827 args++; 828 829 switch (opt) { 830 case 'f': 831 { 832 char **ap, *specs[256], *out; 833 int olen, oused = 0; 834 835 memset(specs, 0, 256 * sizeof(char *)); 836 837 specs['%'] = "%"; 838 specs[')'] = ")"; 839 for (ap = args + 2; *ap; ap++) { 840 if (!ap[0][0] || ap[0][0] == '-' || ap[0][0] == '.' || 841 idigit(ap[0][0]) || ap[0][1] != ':') { 842 zwarnnam(nam, "invalid argument: %s", *ap); 843 return 1; 844 } 845 specs[STOUC(ap[0][0])] = ap[0] + 2; 846 } 847 out = (char *) zhalloc(olen = 128); 848 849 zformat_substring(args[1], specs, &out, &oused, &olen, '\0', 0); 850 out[oused] = '\0'; 851 852 setsparam(args[0], ztrdup(out)); 853 return 0; 854 } 855 break; 856 case 'a': 857 { 858 char **ap, *cp; 859 int nbc = 0, colon = 0, pre = 0, suf = 0; 860 861 for (ap = args + 2; *ap; ap++) { 862 for (nbc = 0, cp = *ap; *cp && *cp != ':'; cp++) 863 if (*cp == '\\' && cp[1]) 864 cp++, nbc++; 865 if (*cp == ':' && cp[1]) { 866 int d; 867 868 colon++; 869 if ((d = cp - *ap - nbc) > pre) 870 pre = d; 871 if ((d = strlen(cp + 1)) > suf) 872 suf = d; 873 } 874 } 875 { 876 int sl = strlen(args[1]); 877 VARARR(char, buf, pre + suf + sl + 1); 878 char **ret, **rp, *copy, *cpp, oldc; 879 880 ret = (char **) zalloc((arrlen(args + 2) + 1) * 881 sizeof(char *)); 882 883 memcpy(buf + pre, args[1], sl); 884 suf = pre + sl; 885 886 for (rp = ret, ap = args + 2; *ap; ap++) { 887 copy = dupstring(*ap); 888 for (cp = cpp = copy; *cp && *cp != ':'; cp++) { 889 if (*cp == '\\' && cp[1]) 890 cp++; 891 *cpp++ = *cp; 892 } 893 oldc = *cpp; 894 *cpp = '\0'; 895 if (((cpp == cp && oldc == ':') || *cp == ':') && cp[1]) { 896 memset(buf, ' ', pre); 897 memcpy(buf, copy, (cpp - copy)); 898 strcpy(buf + suf, cp + 1); 899 *rp++ = ztrdup(buf); 900 } else 901 *rp++ = ztrdup(copy); 902 } 903 *rp = NULL; 904 905 setaparam(args[0], ret); 906 return 0; 907 } 908 } 909 break; 910 } 911 zwarnnam(nam, "invalid option: -%c", opt); 912 return 1; 913} 914 915/* Zregexparse stuff. */ 916 917typedef struct { 918 char **match; 919 char **mbegin; 920 char **mend; 921} MatchData; 922 923static void 924savematch(MatchData *m) 925{ 926 char **a; 927 928 queue_signals(); 929 a = getaparam("match"); 930 m->match = a ? zarrdup(a) : NULL; 931 a = getaparam("mbegin"); 932 m->mbegin = a ? zarrdup(a) : NULL; 933 a = getaparam("mend"); 934 m->mend = a ? zarrdup(a) : NULL; 935 unqueue_signals(); 936} 937 938static void 939restorematch(MatchData *m) 940{ 941 if (m->match) 942 setaparam("match", m->match); 943 else 944 unsetparam("match"); 945 if (m->mbegin) 946 setaparam("mbegin", m->mbegin); 947 else 948 unsetparam("mbegin"); 949 if (m->mend) 950 setaparam("mend", m->mend); 951 else 952 unsetparam("mend"); 953} 954 955static void 956freematch(MatchData *m) 957{ 958 if (m->match) 959 freearray(m->match); 960 if (m->mbegin) 961 freearray(m->mbegin); 962 if (m->mend) 963 freearray(m->mend); 964} 965 966typedef struct { 967 int cutoff; 968 char *pattern; 969 Patprog patprog; 970 char *guard; 971 char *action; 972 LinkList branches; 973} RParseState; 974 975typedef struct { 976 RParseState *state; 977 LinkList actions; 978} RParseBranch; 979 980typedef struct { 981 LinkList nullacts; 982 LinkList in; 983 LinkList out; 984} RParseResult; 985 986static char **rparseargs; 987static LinkList rparsestates; 988 989static int rparsealt(RParseResult *result, jmp_buf *perr); 990 991static void 992connectstates(LinkList out, LinkList in) 993{ 994 LinkNode outnode, innode, ln; 995 996 for (outnode = firstnode(out); outnode; outnode = nextnode(outnode)) { 997 RParseBranch *outbranch = getdata(outnode); 998 999 for (innode = firstnode(in); innode; innode = nextnode(innode)) { 1000 RParseBranch *inbranch = getdata(innode); 1001 RParseBranch *br = hcalloc(sizeof(*br)); 1002 1003 br->state = inbranch->state; 1004 br->actions = newlinklist(); 1005 for (ln = firstnode(outbranch->actions); ln; ln = nextnode(ln)) 1006 addlinknode(br->actions, getdata(ln)); 1007 for (ln = firstnode(inbranch->actions); ln; ln = nextnode(ln)) 1008 addlinknode(br->actions, getdata(ln)); 1009 addlinknode(outbranch->state->branches, br); 1010 } 1011 } 1012} 1013 1014static int 1015rparseelt(RParseResult *result, jmp_buf *perr) 1016{ 1017 int l; 1018 char *s = *rparseargs; 1019 1020 if (!s) 1021 return 1; 1022 1023 switch (s[0]) { 1024 case '/': { 1025 RParseState *st; 1026 RParseBranch *br; 1027 char *pattern, *lookahead; 1028 int patternlen, lookaheadlen = 0; 1029 1030 l = strlen(s); 1031 if (!((2 <= l && s[l - 1] == '/') || 1032 (3 <= l && s[l - 2] == '/' && (s[l - 1] == '+' || 1033 s[l - 1] == '-')))) 1034 return 1; 1035 st = hcalloc(sizeof(*st)); 1036 st->branches = newlinklist(); 1037 st->cutoff = s[l - 1]; 1038 if (s[l - 1] == '/') { 1039 pattern = s + 1; 1040 patternlen = l - 2; 1041 } else { 1042 pattern = s + 1; 1043 patternlen = l - 3; 1044 } 1045 rparseargs++; 1046 if ((s = *rparseargs) && s[0] == '%' && 1047 2 <= (l = strlen(s)) && s[l - 1] == '%') { 1048 rparseargs++; 1049 lookahead = s + 1; 1050 lookaheadlen = l - 2; 1051 } else { 1052 lookahead = NULL; 1053 } 1054 if (patternlen == 2 && !strncmp(pattern, "[]", 2)) 1055 st->pattern = NULL; 1056 else { 1057 char *cp; 1058 int l = patternlen + 12; /* (#b)((#B)...)...* */ 1059 if(lookahead) 1060 l += lookaheadlen + 4; /* (#B)... */ 1061 cp = st->pattern = hcalloc(l); 1062 strcpy(cp, "(#b)((#B)"); 1063 cp += 9; 1064 strcpy(cp, pattern); 1065 cp += patternlen; 1066 strcpy(cp, ")"); 1067 cp += 1; 1068 if (lookahead) { 1069 strcpy(cp, "(#B)"); 1070 cp += 4; 1071 strcpy(cp, lookahead); 1072 cp += lookaheadlen; 1073 } 1074 strcpy(cp, "*"); 1075 } 1076 st->patprog = NULL; 1077 if ((s = *rparseargs) && *s == '-') { 1078 rparseargs++; 1079 l = strlen(s); 1080 st->guard = hcalloc(l); 1081 memcpy(st->guard, s + 1, l - 1); 1082 st->guard[l - 1] = '\0'; 1083 } else 1084 st->guard = NULL; 1085 if ((s = *rparseargs) && *s == ':') { 1086 rparseargs++; 1087 l = strlen(s); 1088 st->action = hcalloc(l); 1089 memcpy(st->action, s + 1, l - 1); 1090 st->action[l - 1] = '\0'; 1091 } else 1092 st->action = NULL; 1093 result->nullacts = NULL; 1094 result->in = newlinklist(); 1095 br = hcalloc(sizeof(*br)); 1096 br->state = st; 1097 br->actions = newlinklist(); 1098 addlinknode(result->in, br); 1099 result->out = newlinklist(); 1100 br = hcalloc(sizeof(*br)); 1101 br->state = st; 1102 br->actions = newlinklist(); 1103 addlinknode(result->out, br); 1104 break; 1105 } 1106 case '(': 1107 if (s[1]) 1108 return 1; 1109 rparseargs++; 1110 if (rparsealt(result, perr)) 1111 longjmp(*perr, 2); 1112 s = *rparseargs; 1113 if (!s || s[0] != ')' || s[1] != '\0') 1114 longjmp(*perr, 2); 1115 rparseargs++; 1116 break; 1117 default: 1118 return 1; 1119 } 1120 1121 return 0; 1122} 1123 1124static int 1125rparseclo(RParseResult *result, jmp_buf *perr) 1126{ 1127 if (rparseelt(result, perr)) 1128 return 1; 1129 1130 if (*rparseargs && !strcmp(*rparseargs, "#")) { 1131 rparseargs++; 1132 while (*rparseargs && !strcmp(*rparseargs, "#")) 1133 rparseargs++; 1134 1135 connectstates(result->out, result->in); 1136 result->nullacts = newlinklist(); 1137 } 1138 return 0; 1139} 1140 1141static void 1142prependactions(LinkList acts, LinkList branches) 1143{ 1144 LinkNode aln, bln; 1145 1146 for (bln = firstnode(branches); bln; bln = nextnode(bln)) { 1147 RParseBranch *br = getdata(bln); 1148 1149 for (aln = lastnode(acts); aln != (LinkNode)acts; aln = prevnode(aln)) 1150 pushnode(br->actions, getdata(aln)); 1151 } 1152} 1153 1154static void 1155appendactions(LinkList acts, LinkList branches) 1156{ 1157 LinkNode aln, bln; 1158 for (bln = firstnode(branches); bln; bln = nextnode(bln)) { 1159 RParseBranch *br = getdata(bln); 1160 1161 for (aln = firstnode(acts); aln; aln = nextnode(aln)) 1162 addlinknode(br->actions, getdata(aln)); 1163 } 1164} 1165 1166static int 1167rparseseq(RParseResult *result, jmp_buf *perr) 1168{ 1169 int l; 1170 char *s; 1171 RParseResult sub; 1172 1173 result->nullacts = newlinklist(); 1174 result->in = newlinklist(); 1175 result->out = newlinklist(); 1176 1177 while (1) { 1178 if ((s = *rparseargs) && s[0] == '{' && s[(l = strlen(s)) - 1] == '}') { 1179 char *action = hcalloc(l - 1); 1180 LinkNode ln; 1181 1182 rparseargs++; 1183 memcpy(action, s + 1, l - 2); 1184 action[l - 2] = '\0'; 1185 if (result->nullacts) 1186 addlinknode(result->nullacts, action); 1187 for (ln = firstnode(result->out); ln; ln = nextnode(ln)) { 1188 RParseBranch *br = getdata(ln); 1189 addlinknode(br->actions, action); 1190 } 1191 } 1192 else if (!rparseclo(&sub, perr)) { 1193 connectstates(result->out, sub.in); 1194 1195 if (result->nullacts) { 1196 prependactions(result->nullacts, sub.in); 1197 insertlinklist(sub.in, lastnode(result->in), result->in); 1198 } 1199 if (sub.nullacts) { 1200 appendactions(sub.nullacts, result->out); 1201 insertlinklist(sub.out, lastnode(result->out), result->out); 1202 } else 1203 result->out = sub.out; 1204 1205 if (result->nullacts && sub.nullacts) 1206 insertlinklist(sub.nullacts, lastnode(result->nullacts), 1207 result->nullacts); 1208 else 1209 result->nullacts = NULL; 1210 } 1211 else 1212 break; 1213 } 1214 return 0; 1215} 1216 1217static int 1218rparsealt(RParseResult *result, jmp_buf *perr) 1219{ 1220 RParseResult sub; 1221 1222 if (rparseseq(result, perr)) 1223 return 1; 1224 1225 while (*rparseargs && !strcmp(*rparseargs, "|")) { 1226 rparseargs++; 1227 if (rparseseq(&sub, perr)) 1228 longjmp(*perr, 2); 1229 if (!result->nullacts && sub.nullacts) 1230 result->nullacts = sub.nullacts; 1231 1232 insertlinklist(sub.in, lastnode(result->in), result->in); 1233 insertlinklist(sub.out, lastnode(result->out), result->out); 1234 } 1235 return 0; 1236} 1237 1238static int 1239rmatch(RParseResult *sm, char *subj, char *var1, char *var2, int comp) 1240{ 1241 LinkNode ln, lnn; 1242 LinkList nexts; 1243 LinkList nextslist; 1244 RParseBranch *br; 1245 RParseState *st = NULL; 1246 int point1 = 0, point2 = 0; 1247 1248 setiparam(var1, point1); 1249 setiparam(var2, point2); 1250 1251 if (!comp && !*subj && sm->nullacts) { 1252 for (ln = firstnode(sm->nullacts); ln; ln = nextnode(ln)) { 1253 char *action = getdata(ln); 1254 1255 if (action) 1256 execstring(action, 1, 0, "zregexparse-action"); 1257 } 1258 return 0; 1259 } 1260 1261 nextslist = newlinklist(); 1262 nexts = sm->in; 1263 addlinknode(nextslist, nexts); 1264 do { 1265 MatchData match1, match2; 1266 1267 savematch(&match1); 1268 1269 for (ln = firstnode(nexts); ln; ln = nextnode(ln)) { 1270 int i; 1271 RParseState *next; 1272 1273 br = getdata(ln); 1274 next = br->state; 1275 if (next->pattern && !next->patprog) { 1276 tokenize(next->pattern); 1277 if (!(next->patprog = patcompile(next->pattern, 0, NULL))) 1278 return 3; 1279 } 1280 if (next->pattern && pattry(next->patprog, subj) && 1281 (!next->guard || (execstring(next->guard, 1, 0, 1282 "zregexparse-guard"), !lastval))) { 1283 LinkNode aln; 1284 char **mend; 1285 int len; 1286 1287 queue_signals(); 1288 mend = getaparam("mend"); 1289 len = atoi(mend[0]); 1290 unqueue_signals(); 1291 1292 for (i = len; i; i--) 1293 if (*subj++ == Meta) 1294 subj++; 1295 1296 savematch(&match2); 1297 restorematch(&match1); 1298 1299 for (aln = firstnode(br->actions); aln; aln = nextnode(aln)) { 1300 char *action = getdata(aln); 1301 1302 if (action) 1303 execstring(action, 1, 0, "zregexparse-action"); 1304 } 1305 restorematch(&match2); 1306 1307 point2 += len; 1308 setiparam(var2, point2); 1309 st = br->state; 1310 nexts = st->branches; 1311 if (next->cutoff == '-' || (next->cutoff == '/' && len)) { 1312 nextslist = newlinklist(); 1313 point1 = point2; 1314 setiparam(var1, point1); 1315 } 1316 addlinknode(nextslist, nexts); 1317 break; 1318 } 1319 } 1320 if (!ln) 1321 freematch(&match1); 1322 } while (ln); 1323 1324 if (!comp && !*subj) 1325 for (ln = firstnode(sm->out); ln; ln = nextnode(ln)) { 1326 br = getdata(ln); 1327 if (br->state == st) { 1328 for (ln = firstnode(br->actions); ln; ln = nextnode(ln)) { 1329 char *action = getdata(ln); 1330 1331 if (action) 1332 execstring(action, 1, 0, "zregexparse-action"); 1333 } 1334 return 0; 1335 } 1336 } 1337 1338 for (lnn = firstnode(nextslist); lnn; lnn = nextnode(lnn)) { 1339 nexts = getdata(lnn); 1340 for (ln = firstnode(nexts); ln; ln = nextnode(ln)) { 1341 br = getdata(ln); 1342 if (br->state->action) 1343 execstring(br->state->action, 1, 0, "zregexparse-action"); 1344 } 1345 } 1346 return empty(nexts) ? 2 : 1; 1347} 1348 1349/* 1350 usage: zregexparse [-c] var1 var2 string regex... 1351 status: 1352 0: matched 1353 1: unmatched (all next state candidates are failed) 1354 2: unmatched (there is no next state candidates) 1355 3: regex parse error 1356*/ 1357 1358static int 1359bin_zregexparse(char *nam, char **args, Options ops, UNUSED(int func)) 1360{ 1361 int oldextendedglob = opts[EXTENDEDGLOB]; 1362 char *var1 = args[0]; 1363 char *var2 = args[1]; 1364 char *subj = args[2]; 1365 int ret; 1366 jmp_buf rparseerr; 1367 RParseResult result; 1368 1369 opts[EXTENDEDGLOB] = 1; 1370 1371 rparseargs = args + 3; 1372 1373 pushheap(); 1374 rparsestates = newlinklist(); 1375 if (setjmp(rparseerr) || rparsealt(&result, &rparseerr) || *rparseargs) { 1376 if (*rparseargs) 1377 zwarnnam(nam, "invalid regex : %s", *rparseargs); 1378 else 1379 zwarnnam(nam, "not enough regex arguments"); 1380 ret = 3; 1381 } else 1382 ret = 0; 1383 1384 if (!ret) 1385 ret = rmatch(&result, subj, var1, var2, OPT_ISSET(ops,'c')); 1386 popheap(); 1387 1388 opts[EXTENDEDGLOB] = oldextendedglob; 1389 return ret; 1390} 1391 1392typedef struct zoptdesc *Zoptdesc; 1393typedef struct zoptarr *Zoptarr; 1394typedef struct zoptval *Zoptval; 1395 1396struct zoptdesc { 1397 Zoptdesc next; 1398 char *name; 1399 int flags; 1400 Zoptarr arr; 1401 Zoptval vals, last; 1402}; 1403 1404#define ZOF_ARG 1 1405#define ZOF_OPT 2 1406#define ZOF_MULT 4 1407#define ZOF_SAME 8 1408#define ZOF_MAP 16 1409#define ZOF_CYC 32 1410 1411struct zoptarr { 1412 Zoptarr next; 1413 char *name; 1414 Zoptval vals, last; 1415 int num; 1416}; 1417 1418struct zoptval { 1419 Zoptval next, onext; 1420 char *name; 1421 char *arg; 1422 char *str; 1423}; 1424 1425static Zoptdesc opt_descs; 1426static Zoptarr opt_arrs; 1427 1428static Zoptdesc 1429get_opt_desc(char *name) 1430{ 1431 Zoptdesc p; 1432 1433 for (p = opt_descs; p; p = p->next) 1434 if (!strcmp(name, p->name)) 1435 return p; 1436 1437 return NULL; 1438} 1439 1440static Zoptdesc 1441lookup_opt(char *str) 1442{ 1443 Zoptdesc p; 1444 1445 for (p = opt_descs; p; p = p->next) { 1446 if ((p->flags & ZOF_ARG) ? strpfx(p->name, str) : !strcmp(p->name, str)) 1447 return p; 1448 } 1449 return NULL; 1450} 1451 1452static Zoptarr 1453get_opt_arr(char *name) 1454{ 1455 Zoptarr p; 1456 1457 for (p = opt_arrs; p; p = p->next) 1458 if (!strcmp(name, p->name)) 1459 return p; 1460 1461 return NULL; 1462} 1463 1464static Zoptdesc 1465map_opt_desc(Zoptdesc start) 1466{ 1467 Zoptdesc map = NULL; 1468 1469 if (!start || !(start->flags & ZOF_MAP)) 1470 return start; 1471 1472 map = get_opt_desc(start->arr->name); 1473 1474 if (!map) 1475 return start; 1476 1477 if (map == start) { 1478 start->flags &= ~ZOF_MAP; /* optimize */ 1479 return start; 1480 } 1481 1482 if (map->flags & ZOF_CYC) 1483 return NULL; 1484 1485 start->flags |= ZOF_CYC; 1486 map = map_opt_desc(map); 1487 start->flags &= ~ZOF_CYC; 1488 1489 return map; 1490} 1491 1492static void 1493add_opt_val(Zoptdesc d, char *arg) 1494{ 1495 Zoptval v = NULL; 1496 char *n = dyncat("-", d->name); 1497 int new = 0; 1498 1499 Zoptdesc map = map_opt_desc(d); 1500 if (map) 1501 d = map; 1502 1503 if (!(d->flags & ZOF_MULT)) 1504 v = d->vals; 1505 if (!v) { 1506 v = (Zoptval) zhalloc(sizeof(*v)); 1507 v->next = v->onext = NULL; 1508 v->name = n; 1509 new = 1; 1510 } 1511 v->arg = arg; 1512 if ((d->flags & ZOF_ARG) && !(d->flags & (ZOF_OPT | ZOF_SAME))) { 1513 v->str = NULL; 1514 if (d->arr) 1515 d->arr->num += (arg ? 2 : 1); 1516 } else if (arg) { 1517 char *s = (char *) zhalloc(strlen(d->name) + strlen(arg) + 2); 1518 1519 *s = '-'; 1520 strcpy(s + 1, d->name); 1521 strcat(s, arg); 1522 v->str = s; 1523 if (d->arr) 1524 d->arr->num += 1; 1525 } else { 1526 v->str = NULL; 1527 if (d->arr) 1528 d->arr->num += 1; 1529 } 1530 if (new) { 1531 if (d->arr) { 1532 if (d->arr->last) 1533 d->arr->last->next = v; 1534 else 1535 d->arr->vals = v; 1536 d->arr->last = v; 1537 } 1538 if (d->last) 1539 d->last->onext = v; 1540 else 1541 d->vals = v; 1542 d->last = v; 1543 } 1544} 1545 1546static int 1547bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) 1548{ 1549 char *o, *p, *n, **pp, **aval, **ap, *assoc = NULL, **cp, **np; 1550 int del = 0, flags = 0, extract = 0, keep = 0; 1551 Zoptdesc sopts[256], d; 1552 Zoptarr a, defarr = NULL; 1553 Zoptval v; 1554 1555 opt_descs = NULL; 1556 opt_arrs = NULL; 1557 memset(sopts, 0, 256 * sizeof(Zoptdesc)); 1558 1559 while ((o = *args++)) { 1560 if (*o == '-') { 1561 switch (o[1]) { 1562 case '\0': 1563 o = NULL; 1564 break; 1565 case '-': 1566 if (o[2]) 1567 args--; 1568 /* else unreachable, default parsing removes "--" */ 1569 o = NULL; 1570 break; 1571 case 'D': 1572 if (o[2]) { 1573 args--; 1574 o = NULL; 1575 break; 1576 } 1577 del = 1; 1578 break; 1579 case 'E': 1580 if (o[2]) { 1581 args--; 1582 o = NULL; 1583 break; 1584 } 1585 extract = 1; 1586 break; 1587 case 'K': 1588 if (o[2]) { 1589 args--; 1590 o = NULL; 1591 break; 1592 } 1593 keep = 1; 1594 break; 1595 case 'M': 1596 if (o[2]) { 1597 args--; 1598 o = NULL; 1599 break; 1600 } 1601 flags |= ZOF_MAP; 1602 break; 1603 case 'a': 1604 if (defarr) { 1605 zwarnnam(nam, "default array given more than once"); 1606 return 1; 1607 } 1608 if (o[2]) 1609 n = o + 2; 1610 else if (*args) 1611 n = *args++; 1612 else { 1613 zwarnnam(nam, "missing array name"); 1614 return 1; 1615 } 1616 defarr = (Zoptarr) zhalloc(sizeof(*defarr)); 1617 defarr->name = n; 1618 defarr->num = 0; 1619 defarr->vals = defarr->last = NULL; 1620 defarr->next = NULL; 1621 opt_arrs = defarr; 1622 break; 1623 case 'A': 1624 if (assoc) { 1625 zwarnnam(nam, "associative array given more than once"); 1626 return 1; 1627 } 1628 if (o[2]) 1629 assoc = o + 2; 1630 else if (*args) 1631 assoc = *args++; 1632 else { 1633 zwarnnam(nam, "missing array name"); 1634 return 1; 1635 } 1636 break; 1637 default: 1638 /* Anything else is an option description */ 1639 args--; 1640 o = NULL; 1641 break; 1642 } 1643 if (!o) { 1644 o = ""; 1645 break; 1646 } 1647 } else { 1648 args--; 1649 break; 1650 } 1651 } 1652 if (!o) { 1653 zwarnnam(nam, "missing option descriptions"); 1654 return 1; 1655 } 1656 while ((o = dupstring(*args++))) { 1657 int f = 0; 1658 if (!*o) { 1659 zwarnnam(nam, "invalid option description: %s", o); 1660 return 1; 1661 } 1662 for (p = o; *p; p++) { 1663 if (*p == '\\' && p[1]) 1664 p++; 1665 else if (*p == '+') { 1666 f |= ZOF_MULT; 1667 *p = '\0'; 1668 p++; 1669 break; 1670 } else if (*p == ':' || *p == '=') 1671 break; 1672 } 1673 if (*p == ':') { 1674 f |= ZOF_ARG; 1675 *p = '\0'; 1676 if (*++p == ':') { 1677 p++; 1678 f |= ZOF_OPT; 1679 } 1680 if (*p == '-') { 1681 p++; 1682 f |= ZOF_SAME; 1683 } 1684 } 1685 a = NULL; 1686 if (*p == '=') { 1687 *p++ = '\0'; 1688 f |= flags; 1689 if (!(a = get_opt_arr(p))) { 1690 a = (Zoptarr) zhalloc(sizeof(*a)); 1691 a->name = p; 1692 a->num = 0; 1693 a->vals = a->last = NULL; 1694 a->next = opt_arrs; 1695 opt_arrs = a; 1696 } 1697 } else if (*p) { 1698 zwarnnam(nam, "invalid option description: %s", args[-1]); 1699 return 1; 1700 } else if (!(a = defarr) && !assoc) { 1701 zwarnnam(nam, "no default array defined: %s", args[-1]); 1702 return 1; 1703 } 1704 for (p = n = o; *p; p++) { 1705 if (*p == '\\' && p[1]) 1706 p++; 1707 *n++ = *p; 1708 } 1709 if (get_opt_desc(o)) { 1710 zwarnnam(nam, "option defined more than once: %s", o); 1711 return 1; 1712 } 1713 d = (Zoptdesc) zhalloc(sizeof(*d)); 1714 d->name = o; 1715 d->flags = f; 1716 d->arr = a; 1717 d->next = opt_descs; 1718 d->vals = d->last = NULL; 1719 opt_descs = d; 1720 if (!o[1]) 1721 sopts[STOUC(*o)] = d; 1722 if ((flags & ZOF_MAP) && !map_opt_desc(d)) { 1723 zwarnnam(nam, "cyclic option mapping: %s", args[-1]); 1724 return 1; 1725 } 1726 } 1727 np = cp = pp = ((extract && del) ? arrdup(pparams) : pparams); 1728 for (; (o = *pp); pp++) { 1729 if (*o != '-') { 1730 if (extract) { 1731 if (del) 1732 *cp++ = o; 1733 continue; 1734 } else 1735 break; 1736 } 1737 if (!o[1] || (o[1] == '-' && !o[2])) { 1738 if (del && extract) 1739 *cp++ = o; 1740 pp++; 1741 break; 1742 } 1743 if (!(d = lookup_opt(o + 1))) { 1744 while (*++o) { 1745 if (!(d = sopts[STOUC(*o)])) { 1746 o = NULL; 1747 break; 1748 } 1749 if (d->flags & ZOF_ARG) { 1750 if (o[1]) { 1751 add_opt_val(d, o + 1); 1752 break; 1753 } else if (!(d->flags & ZOF_OPT)) { 1754 if (!pp[1]) { 1755 zwarnnam(nam, "missing argument for option: %s", 1756 d->name); 1757 return 1; 1758 } 1759 add_opt_val(d, *++pp); 1760 } else 1761 add_opt_val(d, NULL); 1762 } else 1763 add_opt_val(d, NULL); 1764 } 1765 if (!o) { 1766 if (extract) { 1767 if (del) 1768 *cp++ = *pp; 1769 continue; 1770 } else 1771 break; 1772 } 1773 } else { 1774 if (d->flags & ZOF_ARG) { 1775 char *e = o + strlen(d->name) + 1; 1776 1777 if (*e) 1778 add_opt_val(d, e); 1779 else if (!(d->flags & ZOF_OPT)) { 1780 if (!pp[1]) { 1781 zwarnnam(nam, "missing argument for option: %s", 1782 d->name); 1783 return 1; 1784 } 1785 add_opt_val(d, *++pp); 1786 } else 1787 add_opt_val(d, NULL); 1788 } else 1789 add_opt_val(d, NULL); 1790 } 1791 } 1792 1793 if (flags & ZOF_MAP) { 1794 for (d = opt_descs; d; d = d->next) 1795 if (d->arr && !d->vals && (d->flags & ZOF_MAP)) { 1796 if (d->arr->num == 0 && get_opt_desc(d->arr->name)) 1797 d->arr->num = -1; /* this is not a real array */ 1798 } 1799 } 1800 if (extract && del) 1801 while (*pp) 1802 *cp++ = *pp++; 1803 1804 for (a = opt_arrs; a; a = a->next) { 1805 if (a->num >= 0 && (!keep || a->num)) { 1806 aval = (char **) zalloc((a->num + 1) * sizeof(char *)); 1807 for (ap = aval, v = a->vals; v; ap++, v = v->next) { 1808 if (v->str) 1809 *ap = ztrdup(v->str); 1810 else { 1811 *ap = ztrdup(v->name); 1812 if (v->arg) 1813 *++ap = ztrdup(v->arg); 1814 } 1815 } 1816 *ap = NULL; 1817 setaparam(a->name, aval); 1818 } 1819 } 1820 if (assoc) { 1821 int num; 1822 1823 for (num = 0, d = opt_descs; d; d = d->next) 1824 if (d->vals) 1825 num++; 1826 1827 if (!keep || num) { 1828 aval = (char **) zalloc(((num * 2) + 1) * sizeof(char *)); 1829 for (ap = aval, d = opt_descs; d; d = d->next) { 1830 if (d->vals) { 1831 *ap++ = n = (char *) zalloc(strlen(d->name) + 2); 1832 *n = '-'; 1833 strcpy(n + 1, d->name); 1834 1835 for (num = 1, v = d->vals; v; v = v->onext) { 1836 num += (v->arg ? strlen(v->arg) : 0); 1837 if (v->next) 1838 num++; 1839 } 1840 *ap++ = n = (char *) zalloc(num); 1841 for (v = d->vals; v; v = v->onext) { 1842 if (v->arg) { 1843 strcpy(n, v->arg); 1844 n += strlen(v->arg); 1845 } 1846 *n = ' '; 1847 } 1848 *n = '\0'; 1849 } 1850 } 1851 *ap = NULL; 1852 sethparam(assoc, aval); 1853 } 1854 } 1855 if (del) { 1856 if (extract) { 1857 *cp = NULL; 1858 freearray(pparams); 1859 pparams = zarrdup(np); 1860 } else { 1861 pp = zarrdup(pp); 1862 freearray(pparams); 1863 pparams = pp; 1864 } 1865 } 1866 return 0; 1867} 1868 1869static struct builtin bintab[] = { 1870 BUILTIN("zformat", 0, bin_zformat, 3, -1, 0, NULL, NULL), 1871 BUILTIN("zparseopts", 0, bin_zparseopts, 1, -1, 0, NULL, NULL), 1872 BUILTIN("zregexparse", 0, bin_zregexparse, 3, -1, 0, "c", NULL), 1873 BUILTIN("zstyle", 0, bin_zstyle, 0, -1, 0, NULL, NULL), 1874}; 1875 1876static struct features module_features = { 1877 bintab, sizeof(bintab)/sizeof(*bintab), 1878 NULL, 0, 1879 NULL, 0, 1880 NULL, 0, 1881 0 1882}; 1883 1884/**/ 1885int 1886setup_(UNUSED(Module m)) 1887{ 1888 zstyletab = newzstyletable(17, "zstyletab"); 1889 1890 return 0; 1891} 1892 1893/**/ 1894int 1895features_(Module m, char ***features) 1896{ 1897 *features = featuresarray(m, &module_features); 1898 return 0; 1899} 1900 1901/**/ 1902int 1903enables_(Module m, int **enables) 1904{ 1905 return handlefeatures(m, &module_features, enables); 1906} 1907 1908/**/ 1909int 1910boot_(Module m) 1911{ 1912 return 0; 1913} 1914 1915/**/ 1916int 1917cleanup_(Module m) 1918{ 1919 return setfeatureenables(m, &module_features, NULL); 1920} 1921 1922/**/ 1923int 1924finish_(UNUSED(Module m)) 1925{ 1926 deletehashtable(zstyletab); 1927 1928 return 0; 1929} 1930