1/* 2 * utils.c - miscellaneous utilities 3 * 4 * This file is part of zsh, the Z shell. 5 * 6 * Copyright (c) 1992-1997 Paul Falstad 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 Paul Falstad 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 Paul Falstad and the Zsh Development Group have been advised of 19 * the possibility of such damage. 20 * 21 * Paul Falstad 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 Paul Falstad and the 25 * Zsh Development Group have no obligation to provide maintenance, 26 * support, updates, enhancements, or modifications. 27 * 28 */ 29 30#include "zsh.mdh" 31#include "utils.pro" 32 33/* name of script being sourced */ 34 35/**/ 36mod_export char *scriptname; /* is sometimes a function name */ 37 38/* filename of script or other file containing code source e.g. autoload */ 39 40/**/ 41mod_export char *scriptfilename; 42 43/* != 0 if we are in a new style completion function */ 44 45/**/ 46mod_export int incompfunc; 47 48#ifdef MULTIBYTE_SUPPORT 49struct widechar_array { 50 wchar_t *chars; 51 size_t len; 52}; 53typedef struct widechar_array *Widechar_array; 54 55/* 56 * The wordchars variable turned into a wide character array. 57 * This is much more convenient for testing. 58 */ 59struct widechar_array wordchars_wide; 60 61/* 62 * The same for the separators (IFS) array. 63 */ 64struct widechar_array ifs_wide; 65 66/* Function to set one of the above from the multibyte array */ 67 68static void 69set_widearray(char *mb_array, Widechar_array wca) 70{ 71 if (wca->chars) { 72 free(wca->chars); 73 wca->chars = NULL; 74 } 75 wca->len = 0; 76 77 if (!isset(MULTIBYTE)) 78 return; 79 80 if (mb_array) { 81 VARARR(wchar_t, tmpwcs, strlen(mb_array)); 82 wchar_t *wcptr = tmpwcs; 83 wint_t wci; 84 85 mb_metacharinit(); 86 while (*mb_array) { 87 int mblen = mb_metacharlenconv(mb_array, &wci); 88 89 if (!mblen) 90 break; 91 /* No good unless all characters are convertible */ 92 if (wci == WEOF) 93 return; 94 *wcptr++ = (wchar_t)wci; 95#ifdef DEBUG 96 /* 97 * This generates a warning from the compiler (and is 98 * indeed useless) if chars are unsigned. It's 99 * extreme paranoia anyway. 100 */ 101 if (wcptr[-1] < 0) 102 fprintf(stderr, "BUG: Bad cast to wchar_t\n"); 103#endif 104 mb_array += mblen; 105 } 106 107 wca->len = wcptr - tmpwcs; 108 wca->chars = (wchar_t *)zalloc(wca->len * sizeof(wchar_t)); 109 wmemcpy(wca->chars, tmpwcs, wca->len); 110 } 111} 112#endif 113 114 115/* Print an error */ 116 117static void 118zwarning(const char *cmd, const char *fmt, va_list ap) 119{ 120 if (isatty(2)) 121 zleentry(ZLE_CMD_TRASH); 122 123 if (cmd) { 124 if (unset(SHINSTDIN) || locallevel) { 125 nicezputs(scriptname ? scriptname : argzero, stderr); 126 fputc((unsigned char)':', stderr); 127 } 128 nicezputs(cmd, stderr); 129 fputc((unsigned char)':', stderr); 130 } else { 131 /* 132 * scriptname is set when sourcing scripts, so that we get the 133 * correct name instead of the generic name of whatever 134 * program/script is running. It's also set in shell functions, 135 * so test locallevel, too. 136 */ 137 nicezputs((isset(SHINSTDIN) && !locallevel) ? "zsh" : 138 scriptname ? scriptname : argzero, stderr); 139 fputc((unsigned char)':', stderr); 140 } 141 142 zerrmsg(stderr, fmt, ap); 143} 144 145 146/**/ 147mod_export void 148zerr(VA_ALIST1(const char *fmt)) 149VA_DCL 150{ 151 va_list ap; 152 VA_DEF_ARG(const char *fmt); 153 154 if (errflag || noerrs) { 155 if (noerrs < 2) 156 errflag = 1; 157 return; 158 } 159 160 VA_START(ap, fmt); 161 VA_GET_ARG(ap, fmt, const char *); 162 zwarning(NULL, fmt, ap); 163 va_end(ap); 164 errflag = 1; 165} 166 167/**/ 168mod_export void 169zerrnam(VA_ALIST2(const char *cmd, const char *fmt)) 170VA_DCL 171{ 172 va_list ap; 173 VA_DEF_ARG(const char *cmd); 174 VA_DEF_ARG(const char *fmt); 175 176 if (errflag || noerrs) 177 return; 178 179 VA_START(ap, fmt); 180 VA_GET_ARG(ap, cmd, const char *); 181 VA_GET_ARG(ap, fmt, const char *); 182 zwarning(cmd, fmt, ap); 183 va_end(ap); 184 errflag = 1; 185} 186 187/**/ 188mod_export void 189zwarn(VA_ALIST1(const char *fmt)) 190VA_DCL 191{ 192 va_list ap; 193 VA_DEF_ARG(const char *fmt); 194 195 if (errflag || noerrs) 196 return; 197 198 VA_START(ap, fmt); 199 VA_GET_ARG(ap, fmt, const char *); 200 zwarning(NULL, fmt, ap); 201 va_end(ap); 202} 203 204/**/ 205mod_export void 206zwarnnam(VA_ALIST2(const char *cmd, const char *fmt)) 207VA_DCL 208{ 209 va_list ap; 210 VA_DEF_ARG(const char *cmd); 211 VA_DEF_ARG(const char *fmt); 212 213 if (errflag || noerrs) 214 return; 215 216 VA_START(ap, fmt); 217 VA_GET_ARG(ap, cmd, const char *); 218 VA_GET_ARG(ap, fmt, const char *); 219 zwarning(cmd, fmt, ap); 220 va_end(ap); 221} 222 223 224#ifdef DEBUG 225 226/**/ 227mod_export void 228dputs(VA_ALIST1(const char *message)) 229VA_DCL 230{ 231 char *filename; 232 FILE *file; 233 va_list ap; 234 VA_DEF_ARG(const char *message); 235 236 VA_START(ap, message); 237 VA_GET_ARG(ap, message, const char *); 238 if ((filename = getsparam("ZSH_DEBUG_LOG")) != NULL && 239 (file = fopen(filename, "a")) != NULL) { 240 zerrmsg(file, message, ap); 241 fclose(file); 242 } else 243 zerrmsg(stderr, message, ap); 244 va_end(ap); 245} 246 247#endif /* DEBUG */ 248 249#ifdef __CYGWIN__ 250/* 251 * This works around an occasional problem with dllwrap on Cygwin, seen 252 * on at least two installations. It fails to find the last symbol 253 * exported in alphabetical order (in our case zwarnnam). Until this is 254 * properly categorised and fixed we add a dummy symbol at the end. 255 */ 256mod_export void 257zz_plural_z_alpha(void) 258{ 259} 260#endif 261 262/**/ 263void 264zerrmsg(FILE *file, const char *fmt, va_list ap) 265{ 266 const char *str; 267 int num; 268#ifdef DEBUG 269 long lnum; 270#endif 271#ifdef HAVE_STRERROR_R 272#define ERRBUFSIZE (80) 273 int olderrno; 274 char errbuf[ERRBUFSIZE]; 275#endif 276 char *errmsg; 277 278 if ((unset(SHINSTDIN) || locallevel) && lineno) { 279#if defined(ZLONG_IS_LONG_LONG) && defined(PRINTF_HAS_LLD) 280 fprintf(file, "%lld: ", lineno); 281#else 282 fprintf(file, "%ld: ", (long)lineno); 283#endif 284 } else 285 fputc((unsigned char)' ', file); 286 287 while (*fmt) 288 if (*fmt == '%') { 289 fmt++; 290 switch (*fmt++) { 291 case 's': 292 str = va_arg(ap, const char *); 293 nicezputs(str, file); 294 break; 295 case 'l': { 296 char *s; 297 str = va_arg(ap, const char *); 298 num = va_arg(ap, int); 299 num = metalen(str, num); 300 s = zhalloc(num + 1); 301 memcpy(s, str, num); 302 s[num] = '\0'; 303 nicezputs(s, file); 304 break; 305 } 306#ifdef DEBUG 307 case 'L': 308 lnum = va_arg(ap, long); 309 fprintf(file, "%ld", lnum); 310 break; 311#endif 312 case 'd': 313 num = va_arg(ap, int); 314 fprintf(file, "%d", num); 315 break; 316 case '%': 317 putc('%', file); 318 break; 319 case 'c': 320 num = va_arg(ap, int); 321#ifdef MULTIBYTE_SUPPORT 322 mb_metacharinit(); 323 zputs(wcs_nicechar(num, NULL, NULL), file); 324#else 325 zputs(nicechar(num), file); 326#endif 327 break; 328 case 'e': 329 /* print the corresponding message for this errno */ 330 num = va_arg(ap, int); 331 if (num == EINTR) { 332 fputs("interrupt\n", file); 333 errflag = 1; 334 return; 335 } 336 errmsg = strerror(num); 337 /* If the message is not about I/O problems, it looks better * 338 * if we uncapitalize the first letter of the message */ 339 if (num == EIO) 340 fputs(errmsg, file); 341 else { 342 fputc(tulower(errmsg[0]), file); 343 fputs(errmsg + 1, file); 344 } 345 break; 346 } 347 } else { 348 putc(*fmt == Meta ? *++fmt ^ 32 : *fmt, file); 349 fmt++; 350 } 351 putc('\n', file); 352 fflush(file); 353} 354 355/* Output a single character, for the termcap routines. * 356 * This is used instead of putchar since it can be a macro. */ 357 358/**/ 359mod_export int 360putraw(int c) 361{ 362 putc(c, stdout); 363 return 0; 364} 365 366/* Output a single character, for the termcap routines. */ 367 368/**/ 369mod_export int 370putshout(int c) 371{ 372 putc(c, shout); 373 return 0; 374} 375 376/* 377 * Turn a character into a visible representation thereof. The visible 378 * string is put together in a static buffer, and this function returns 379 * a pointer to it. Printable characters stand for themselves, DEL is 380 * represented as "^?", newline and tab are represented as "\n" and 381 * "\t", and normal control characters are represented in "^C" form. 382 * Characters with bit 7 set, if unprintable, are represented as "\M-" 383 * followed by the visible representation of the character with bit 7 384 * stripped off. Tokens are interpreted, rather than being treated as 385 * literal characters. 386 * 387 * Note that the returned string is metafied, so that it must be 388 * treated like any other zsh internal string (and not, for example, 389 * output directly). 390 * 391 * This function is used even if MULTIBYTE_SUPPORT is defined: we 392 * use it as a fallback in case we couldn't identify a wide character 393 * in a multibyte string. 394 */ 395 396/**/ 397mod_export char * 398nicechar(int c) 399{ 400 static char buf[6]; 401 char *s = buf; 402 c &= 0xff; 403 if (isprint(c)) 404 goto done; 405 if (c & 0x80) { 406 if (isset(PRINTEIGHTBIT)) 407 goto done; 408 *s++ = '\\'; 409 *s++ = 'M'; 410 *s++ = '-'; 411 c &= 0x7f; 412 if(isprint(c)) 413 goto done; 414 } 415 if (c == 0x7f) { 416 *s++ = '^'; 417 c = '?'; 418 } else if (c == '\n') { 419 *s++ = '\\'; 420 c = 'n'; 421 } else if (c == '\t') { 422 *s++ = '\\'; 423 c = 't'; 424 } else if (c < 0x20) { 425 *s++ = '^'; 426 c += 0x40; 427 } 428 done: 429 /* 430 * The resulting string is still metafied, so check if 431 * we are returning a character in the range that needs metafication. 432 * This can't happen if the character is printed "nicely", so 433 * this results in a maximum of two bytes total (plus the null). 434 */ 435 if (imeta(c)) { 436 *s++ = Meta; 437 *s++ = c ^ 32; 438 } else 439 *s++ = c; 440 *s = 0; 441 return buf; 442} 443 444/**/ 445#ifdef MULTIBYTE_SUPPORT 446static mbstate_t mb_shiftstate; 447 448/* 449 * Initialise multibyte state: called before a sequence of 450 * wcs_nicechar() or mb_metacharlenconv(). 451 */ 452 453/**/ 454mod_export void 455mb_metacharinit(void) 456{ 457 memset(&mb_shiftstate, 0, sizeof(mb_shiftstate)); 458} 459 460/* 461 * The number of bytes we need to allocate for a "nice" representation 462 * of a multibyte character. 463 * 464 * We double MB_CUR_MAX to take account of the fact that 465 * we may need to metafy. In fact the representation probably 466 * doesn't allow every character to be in the meta range, but 467 * we don't need to be too pedantic. 468 * 469 * The 12 is for the output of a UCS-4 code; we don't actually 470 * need this at the same time as MB_CUR_MAX, but again it's 471 * not worth calculating more exactly. 472 */ 473#define NICECHAR_MAX (12 + 2*MB_CUR_MAX) 474/* 475 * Input a wide character. Output a printable representation, 476 * which is a metafied multibyte string. With widthp return 477 * the printing width. 478 * 479 * swide, if non-NULL, is used to help the completion code, which needs 480 * to know the printing width of the each part of the representation. 481 * *swide is set to the part of the returned string where the wide 482 * character starts. Any string up to that point is ASCII characters, 483 * so the width of it is (*swide - <return_value>). Anything left is 484 * a single wide character corresponding to the remaining width. 485 * Either the initial ASCII part or the wide character part may be empty 486 * (but not both). (Note the complication that the wide character 487 * part may contain metafied characters.) 488 * 489 * The caller needs to call mb_metacharinit() before the first call, to 490 * set up the multibyte shift state for a range of characters. 491 */ 492 493/**/ 494mod_export char * 495wcs_nicechar(wchar_t c, size_t *widthp, char **swidep) 496{ 497 static char *buf; 498 static int bufalloc = 0, newalloc; 499 char *s, *mbptr; 500 int ret = 0; 501 VARARR(char, mbstr, MB_CUR_MAX); 502 503 /* 504 * We want buf to persist beyond the return. MB_CUR_MAX and hence 505 * NICECHAR_MAX may not be constant, so we have to allocate this at 506 * run time. (We could probably get away with just allocating a 507 * large buffer, in practice.) For efficiency, only reallocate if 508 * we really need to, since this function will be called frequently. 509 */ 510 newalloc = NICECHAR_MAX; 511 if (bufalloc != newalloc) 512 { 513 bufalloc = newalloc; 514 buf = (char *)zrealloc(buf, bufalloc); 515 } 516 517 s = buf; 518 if (!iswprint(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) { 519 if (c == 0x7f) { 520 *s++ = '^'; 521 c = '?'; 522 } else if (c == L'\n') { 523 *s++ = '\\'; 524 c = 'n'; 525 } else if (c == L'\t') { 526 *s++ = '\\'; 527 c = 't'; 528 } else if (c < 0x20) { 529 *s++ = '^'; 530 c += 0x40; 531 } else if (c >= 0x80) { 532 ret = -1; 533 } 534 } 535 536 if (ret != -1) 537 ret = wcrtomb(mbstr, c, &mb_shiftstate); 538 539 if (ret == -1) { 540 memset(&mb_shiftstate, 0, sizeof(mb_shiftstate)); 541 /* 542 * Can't or don't want to convert character: use UCS-2 or 543 * UCS-4 code in print escape format. 544 * 545 * This comparison fails and generates a compiler warning 546 * if wchar_t is 16 bits, but the code is still correct. 547 */ 548 if (c >= 0x10000) { 549 sprintf(buf, "\\U%.8x", (unsigned int)c); 550 if (widthp) 551 *widthp = 10; 552 } else if (c >= 0x100) { 553 sprintf(buf, "\\u%.4x", (unsigned int)c); 554 if (widthp) 555 *widthp = 6; 556 } else { 557 strcpy(buf, nicechar((int)c)); 558 /* 559 * There may be metafied characters from nicechar(), 560 * so compute width and end position independently. 561 */ 562 if (widthp) 563 *widthp = ztrlen(buf); 564 if (swidep) 565 *swidep = buf + strlen(buf); 566 return buf; 567 } 568 if (swidep) 569 *swidep = buf + *widthp; 570 return buf; 571 } 572 573 if (widthp) { 574 int wcw = WCWIDTH(c); 575 *widthp = (s - buf); 576 if (wcw >= 0) 577 *widthp += wcw; 578 else 579 (*widthp)++; 580 } 581 if (swidep) 582 *swidep = s; 583 for (mbptr = mbstr; ret; s++, mbptr++, ret--) { 584 DPUTS(s >= buf + NICECHAR_MAX, 585 "BUG: buffer too small in wcs_nicechar"); 586 if (imeta(*mbptr)) { 587 *s++ = Meta; 588 DPUTS(s >= buf + NICECHAR_MAX, 589 "BUG: buffer too small for metafied char in wcs_nicechar"); 590 *s = *mbptr ^ 32; 591 } else { 592 *s = *mbptr; 593 } 594 } 595 *s = 0; 596 return buf; 597} 598 599/**/ 600mod_export int 601zwcwidth(wint_t wc) 602{ 603 int wcw; 604 /* assume a single-byte character if not valid */ 605 if (wc == WEOF || unset(MULTIBYTE)) 606 return 1; 607 wcw = WCWIDTH(wc); 608 /* if not printable, assume width 1 */ 609 if (wcw < 0) 610 return 1; 611 return wcw; 612} 613 614/**/ 615#endif /* MULTIBYTE_SUPPORT */ 616 617/* 618 * Search the path for prog and return the file name. 619 * The returned value is unmetafied and in the unmeta storage 620 * area (N.B. should be duplicated if not used immediately and not 621 * equal to *namep). 622 * 623 * If namep is not NULL, *namep is set to the metafied programme 624 * name, which is in heap storage. 625 */ 626/**/ 627char * 628pathprog(char *prog, char **namep) 629{ 630 char **pp, ppmaxlen = 0, *buf, *funmeta; 631 struct stat st; 632 633 for (pp = path; *pp; pp++) 634 { 635 int len = strlen(*pp); 636 if (len > ppmaxlen) 637 ppmaxlen = len; 638 } 639 buf = zhalloc(ppmaxlen + strlen(prog) + 2); 640 for (pp = path; *pp; pp++) { 641 sprintf(buf, "%s/%s", *pp, prog); 642 funmeta = unmeta(buf); 643 if (access(funmeta, F_OK) == 0 && 644 stat(funmeta, &st) >= 0 && 645 !S_ISDIR(st.st_mode)) { 646 if (namep) 647 *namep = buf; 648 return funmeta; 649 } 650 } 651 652 return NULL; 653} 654 655/* get a symlink-free pathname for s relative to PWD */ 656 657/**/ 658char * 659findpwd(char *s) 660{ 661 char *t; 662 663 if (*s == '/') 664 return xsymlink(s); 665 s = tricat((pwd[1]) ? pwd : "", "/", s); 666 t = xsymlink(s); 667 zsfree(s); 668 return t; 669} 670 671/* Check whether a string contains the * 672 * name of the present directory. */ 673 674/**/ 675int 676ispwd(char *s) 677{ 678 struct stat sbuf, tbuf; 679 680 if (stat(unmeta(s), &sbuf) == 0 && stat(".", &tbuf) == 0) 681 if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino) 682 return 1; 683 return 0; 684} 685 686static char xbuf[PATH_MAX*2]; 687 688/**/ 689static char ** 690slashsplit(char *s) 691{ 692 char *t, **r, **q; 693 int t0; 694 695 if (!*s) 696 return (char **) zshcalloc(sizeof(char **)); 697 698 for (t = s, t0 = 0; *t; t++) 699 if (*t == '/') 700 t0++; 701 q = r = (char **) zalloc(sizeof(char **) * (t0 + 2)); 702 703 while ((t = strchr(s, '/'))) { 704 *q++ = ztrduppfx(s, t - s); 705 while (*t == '/') 706 t++; 707 if (!*t) { 708 *q = NULL; 709 return r; 710 } 711 s = t; 712 } 713 *q++ = ztrdup(s); 714 *q = NULL; 715 return r; 716} 717 718/* expands symlinks and .. or . expressions */ 719/* if flag = 0, only expand .. and . expressions */ 720 721/**/ 722static int 723xsymlinks(char *s) 724{ 725 char **pp, **opp; 726 char xbuf2[PATH_MAX*2], xbuf3[PATH_MAX*2]; 727 int t0, ret = 0; 728 729 opp = pp = slashsplit(s); 730 for (; *pp; pp++) { 731 if (!strcmp(*pp, ".")) { 732 zsfree(*pp); 733 continue; 734 } 735 if (!strcmp(*pp, "..")) { 736 char *p; 737 738 zsfree(*pp); 739 if (!strcmp(xbuf, "/")) 740 continue; 741 if (!*xbuf) 742 continue; 743 p = xbuf + strlen(xbuf); 744 while (*--p != '/'); 745 *p = '\0'; 746 continue; 747 } 748 sprintf(xbuf2, "%s/%s", xbuf, *pp); 749 t0 = readlink(unmeta(xbuf2), xbuf3, PATH_MAX); 750 if (t0 == -1) { 751 strcat(xbuf, "/"); 752 strcat(xbuf, *pp); 753 zsfree(*pp); 754 } else { 755 ret = 1; 756 metafy(xbuf3, t0, META_NOALLOC); 757 if (*xbuf3 == '/') { 758 strcpy(xbuf, ""); 759 xsymlinks(xbuf3 + 1); 760 } else 761 xsymlinks(xbuf3); 762 zsfree(*pp); 763 } 764 } 765 free(opp); 766 return ret; 767} 768 769/* 770 * expand symlinks in s, and remove other weird things: 771 * note that this always expands symlinks. 772 */ 773 774/**/ 775char * 776xsymlink(char *s) 777{ 778 if (*s != '/') 779 return NULL; 780 *xbuf = '\0'; 781 xsymlinks(s + 1); 782 if (!*xbuf) 783 return ztrdup("/"); 784 return ztrdup(xbuf); 785} 786 787/**/ 788void 789print_if_link(char *s) 790{ 791 if (*s == '/') { 792 *xbuf = '\0'; 793 if (xsymlinks(s + 1)) 794 printf(" -> "), zputs(*xbuf ? xbuf : "/", stdout); 795 } 796} 797 798/* print a directory */ 799 800/**/ 801void 802fprintdir(char *s, FILE *f) 803{ 804 Nameddir d = finddir(s); 805 806 if (!d) 807 fputs(unmeta(s), f); 808 else { 809 putc('~', f); 810 fputs(unmeta(d->node.nam), f); 811 fputs(unmeta(s + strlen(d->dir)), f); 812 } 813} 814 815/* 816 * Substitute a directory using a name. 817 * If there is none, return the original argument. 818 * 819 * At this level all strings involved are metafied. 820 */ 821 822/**/ 823char * 824substnamedir(char *s) 825{ 826 Nameddir d = finddir(s); 827 828 if (!d) 829 return quotestring(s, NULL, QT_BACKSLASH); 830 return zhtricat("~", d->node.nam, quotestring(s + strlen(d->dir), 831 NULL, QT_BACKSLASH)); 832} 833 834 835/* Returns the current username. It caches the username * 836 * and uid to try to avoid requerying the password files * 837 * or NIS/NIS+ database. */ 838 839/**/ 840uid_t cached_uid; 841/**/ 842char *cached_username; 843 844/**/ 845char * 846get_username(void) 847{ 848#ifdef HAVE_GETPWUID 849 struct passwd *pswd; 850 uid_t current_uid; 851 852 current_uid = getuid(); 853 if (current_uid != cached_uid) { 854 cached_uid = current_uid; 855 zsfree(cached_username); 856 if ((pswd = getpwuid(current_uid))) 857 cached_username = ztrdup(pswd->pw_name); 858 else 859 cached_username = ztrdup(""); 860 } 861#else /* !HAVE_GETPWUID */ 862 cached_uid = getuid(); 863#endif /* !HAVE_GETPWUID */ 864 return cached_username; 865} 866 867/* static variables needed by finddir(). */ 868 869static char *finddir_full; 870static Nameddir finddir_last; 871static int finddir_best; 872 873/* ScanFunc used by finddir(). */ 874 875/**/ 876static void 877finddir_scan(HashNode hn, UNUSED(int flags)) 878{ 879 Nameddir nd = (Nameddir) hn; 880 881 if(nd->diff > finddir_best && !dircmp(nd->dir, finddir_full) 882 && !(nd->node.flags & ND_NOABBREV)) { 883 finddir_last=nd; 884 finddir_best=nd->diff; 885 } 886} 887 888/* 889 * See if a path has a named directory as its prefix. 890 * If passed a NULL argument, it will invalidate any 891 * cached information. 892 * 893 * s here is metafied. 894 */ 895 896/**/ 897Nameddir 898finddir(char *s) 899{ 900 static struct nameddir homenode = { {NULL, "", 0}, NULL, 0 }; 901 static int ffsz; 902 char **ares; 903 int len; 904 905 /* Invalidate directory cache if argument is NULL. This is called * 906 * whenever a node is added to or removed from the hash table, and * 907 * whenever the value of $HOME changes. (On startup, too.) */ 908 if (!s) { 909 homenode.dir = home ? home : ""; 910 homenode.diff = home ? strlen(home) : 0; 911 if(homenode.diff==1) 912 homenode.diff = 0; 913 if(!finddir_full) 914 finddir_full = zalloc(ffsz = PATH_MAX); 915 finddir_full[0] = 0; 916 return finddir_last = NULL; 917 } 918 919#if 0 920 /* 921 * It's not safe to use the cache while we have function 922 * transformations, and it's not clear it's worth the 923 * complexity of guessing here whether subst_string_by_hook 924 * is going to turn up the goods. 925 */ 926 if (!strcmp(s, finddir_full) && *finddir_full) 927 return finddir_last; 928#endif 929 930 if ((int)strlen(s) >= ffsz) { 931 free(finddir_full); 932 finddir_full = zalloc(ffsz = strlen(s) * 2); 933 } 934 strcpy(finddir_full, s); 935 finddir_best=0; 936 finddir_last=NULL; 937 finddir_scan(&homenode.node, 0); 938 scanhashtable(nameddirtab, 0, 0, 0, finddir_scan, 0); 939 940 ares = subst_string_by_hook("zsh_directory_name", "d", finddir_full); 941 if (ares && arrlen(ares) >= 2 && 942 (len = (int)zstrtol(ares[1], NULL, 10)) > finddir_best) { 943 /* better duplicate this string since it's come from REPLY */ 944 finddir_last = (Nameddir)hcalloc(sizeof(struct nameddir)); 945 finddir_last->node.nam = zhtricat("[", dupstring(ares[0]), "]"); 946 finddir_last->dir = dupstrpfx(finddir_full, len); 947 finddir_last->diff = len - strlen(finddir_last->node.nam); 948 finddir_best = len; 949 } 950 951 return finddir_last; 952} 953 954/* add a named directory */ 955 956/**/ 957mod_export void 958adduserdir(char *s, char *t, int flags, int always) 959{ 960 Nameddir nd; 961 char *eptr; 962 963 /* We don't maintain a hash table in non-interactive shells. */ 964 if (!interact) 965 return; 966 967 /* The ND_USERNAME flag means that this possible hash table * 968 * entry is derived from a passwd entry. Such entries are * 969 * subordinate to explicitly generated entries. */ 970 if ((flags & ND_USERNAME) && nameddirtab->getnode2(nameddirtab, s)) 971 return; 972 973 /* Normal parameter assignments generate calls to this function, * 974 * with always==0. Unless the AUTO_NAME_DIRS option is set, we * 975 * don't let such assignments actually create directory names. * 976 * Instead, a reference to the parameter as a directory name can * 977 * cause the actual creation of the hash table entry. */ 978 if (!always && unset(AUTONAMEDIRS) && 979 !nameddirtab->getnode2(nameddirtab, s)) 980 return; 981 982 if (!t || *t != '/' || strlen(t) >= PATH_MAX) { 983 /* We can't use this value as a directory, so simply remove * 984 * the corresponding entry in the hash table, if any. */ 985 HashNode hn = nameddirtab->removenode(nameddirtab, s); 986 987 if(hn) 988 nameddirtab->freenode(hn); 989 return; 990 } 991 992 /* add the name */ 993 nd = (Nameddir) zshcalloc(sizeof *nd); 994 nd->node.flags = flags; 995 eptr = t + strlen(t); 996 while (eptr > t && eptr[-1] == '/') 997 eptr--; 998 if (eptr == t) { 999 /* 1000 * Don't abbreviate multiple slashes at the start of a 1001 * named directory, since these are sometimes used for 1002 * special purposes. 1003 */ 1004 nd->dir = ztrdup(t); 1005 } else 1006 nd->dir = ztrduppfx(t, eptr - t); 1007 /* The variables PWD and OLDPWD are not to be displayed as ~PWD etc. */ 1008 if (!strcmp(s, "PWD") || !strcmp(s, "OLDPWD")) 1009 nd->node.flags |= ND_NOABBREV; 1010 nameddirtab->addnode(nameddirtab, ztrdup(s), nd); 1011} 1012 1013/* Get a named directory: this function can cause a directory name * 1014 * to be added to the hash table, if it isn't there already. */ 1015 1016/**/ 1017char * 1018getnameddir(char *name) 1019{ 1020 Param pm; 1021 char *str; 1022 Nameddir nd; 1023 1024 /* Check if it is already in the named directory table */ 1025 if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name))) 1026 return dupstring(nd->dir); 1027 1028 /* Check if there is a scalar parameter with this name whose value * 1029 * begins with a `/'. If there is, add it to the hash table and * 1030 * return the new value. */ 1031 if ((pm = (Param) paramtab->getnode(paramtab, name)) && 1032 (PM_TYPE(pm->node.flags) == PM_SCALAR) && 1033 (str = getsparam(name)) && *str == '/') { 1034 pm->node.flags |= PM_NAMEDDIR; 1035 adduserdir(name, str, 0, 1); 1036 return str; 1037 } 1038 1039#ifdef HAVE_GETPWNAM 1040 { 1041 /* Retrieve an entry from the password table/database for this user. */ 1042 struct passwd *pw; 1043 if ((pw = getpwnam(name))) { 1044 char *dir = isset(CHASELINKS) ? xsymlink(pw->pw_dir) 1045 : ztrdup(pw->pw_dir); 1046 adduserdir(name, dir, ND_USERNAME, 1); 1047 str = dupstring(dir); 1048 zsfree(dir); 1049 return str; 1050 } 1051 } 1052#endif /* HAVE_GETPWNAM */ 1053 1054 /* There are no more possible sources of directory names, so give up. */ 1055 return NULL; 1056} 1057 1058/* 1059 * Compare directories. Both are metafied. 1060 */ 1061 1062/**/ 1063static int 1064dircmp(char *s, char *t) 1065{ 1066 if (s) { 1067 for (; *s == *t; s++, t++) 1068 if (!*s) 1069 return 0; 1070 if (!*s && *t == '/') 1071 return 0; 1072 } 1073 return 1; 1074} 1075 1076/* 1077 * Extra functions to call before displaying the prompt. 1078 * The data is a Prepromptfn. 1079 */ 1080 1081static LinkList prepromptfns; 1082 1083/* Add a function to the list of pre-prompt functions. */ 1084 1085/**/ 1086mod_export void 1087addprepromptfn(voidvoidfnptr_t func) 1088{ 1089 Prepromptfn ppdat = (Prepromptfn)zalloc(sizeof(struct prepromptfn)); 1090 ppdat->func = func; 1091 if (!prepromptfns) 1092 prepromptfns = znewlinklist(); 1093 zaddlinknode(prepromptfns, ppdat); 1094} 1095 1096/* Remove a function from the list of pre-prompt functions. */ 1097 1098/**/ 1099mod_export void 1100delprepromptfn(voidvoidfnptr_t func) 1101{ 1102 LinkNode ln; 1103 1104 for (ln = firstnode(prepromptfns); ln; ln = nextnode(ln)) { 1105 Prepromptfn ppdat = (Prepromptfn)getdata(ln); 1106 if (ppdat->func == func) { 1107 (void)remnode(prepromptfns, ln); 1108 zfree(ppdat, sizeof(struct prepromptfn)); 1109 return; 1110 } 1111 } 1112#ifdef DEBUG 1113 dputs("BUG: failed to delete node from prepromptfns"); 1114#endif 1115} 1116 1117/* 1118 * Functions to call at a particular time even if not at 1119 * the prompt. This is handled by zle. The data is a 1120 * Timedfn. The functions must be in time order, but this 1121 * is enforced by addtimedfn(). 1122 * 1123 * Note on debugging: the code in sched.c currently assumes it's 1124 * the only user of timedfns for the purposes of checking whether 1125 * there's a function on the list. If this becomes no longer the case, 1126 * the DPUTS() tests in sched.c need rewriting. 1127 */ 1128 1129/**/ 1130mod_export LinkList timedfns; 1131 1132/* Add a function to the list of timed functions. */ 1133 1134/**/ 1135mod_export void 1136addtimedfn(voidvoidfnptr_t func, time_t when) 1137{ 1138 Timedfn tfdat = (Timedfn)zalloc(sizeof(struct timedfn)); 1139 tfdat->func = func; 1140 tfdat->when = when; 1141 1142 if (!timedfns) { 1143 timedfns = znewlinklist(); 1144 zaddlinknode(timedfns, tfdat); 1145 } else { 1146 LinkNode ln = firstnode(timedfns); 1147 1148 /* 1149 * Insert the new element in the linked list. We do 1150 * rather too much work here since the standard 1151 * functions insert after a given node, whereas we 1152 * want to insert the new data before the first element 1153 * with a greater time. 1154 * 1155 * In practice, the only use of timed functions is 1156 * sched, which only adds the one function; so this 1157 * whole branch isn't used beyond the following block. 1158 */ 1159 if (!ln) { 1160 zaddlinknode(timedfns, tfdat); 1161 return; 1162 } 1163 for (;;) { 1164 Timedfn tfdat2; 1165 LinkNode next = nextnode(ln); 1166 if (!next) { 1167 zaddlinknode(timedfns, tfdat); 1168 return; 1169 } 1170 tfdat2 = (Timedfn)getdata(next); 1171 if (when < tfdat2->when) { 1172 zinsertlinknode(timedfns, ln, tfdat); 1173 return; 1174 } 1175 ln = next; 1176 } 1177 } 1178} 1179 1180/* 1181 * Delete a function from the list of timed functions. 1182 * Note that if the function apperas multiple times only 1183 * the first occurrence will be removed. 1184 * 1185 * Note also that when zle calls the function it does *not* 1186 * automatically delete the entry from the list. That must 1187 * be done by the function called. This is recommended as otherwise 1188 * the function will keep being called immediately. (It just so 1189 * happens this "feature" fits in well with the only current use 1190 * of timed functions.) 1191 */ 1192 1193/**/ 1194mod_export void 1195deltimedfn(voidvoidfnptr_t func) 1196{ 1197 LinkNode ln; 1198 1199 for (ln = firstnode(timedfns); ln; ln = nextnode(ln)) { 1200 Timedfn ppdat = (Timedfn)getdata(ln); 1201 if (ppdat->func == func) { 1202 (void)remnode(timedfns, ln); 1203 zfree(ppdat, sizeof(struct timedfn)); 1204 return; 1205 } 1206 } 1207#ifdef DEBUG 1208 dputs("BUG: failed to delete node from timedfns"); 1209#endif 1210} 1211 1212/* the last time we checked mail */ 1213 1214/**/ 1215time_t lastmailcheck; 1216 1217/* the last time we checked the people in the WATCH variable */ 1218 1219/**/ 1220time_t lastwatch; 1221 1222/* 1223 * Call a function given by "name" with optional arguments 1224 * "lnklist". If these are present the first argument is the function name. 1225 * 1226 * If "arrayp" is not zero, we also look through 1227 * the array "name"_functions and execute functions found there. 1228 * 1229 * If "retval" is not NULL, the return value of the first hook function to 1230 * return non-zero is stored in *"retval". The return value is not otherwise 1231 * available as the calling context is restored. 1232 */ 1233 1234/**/ 1235mod_export int 1236callhookfunc(char *name, LinkList lnklst, int arrayp, int *retval) 1237{ 1238 Shfunc shfunc; 1239 /* 1240 * Save stopmsg, since user doesn't get a chance to respond 1241 * to a list of jobs generated in a hook. 1242 */ 1243 int osc = sfcontext, osm = stopmsg, stat = 1, ret = 0; 1244 int old_incompfunc = incompfunc; 1245 1246 sfcontext = SFC_HOOK; 1247 incompfunc = 0; 1248 1249 if ((shfunc = getshfunc(name))) { 1250 ret = doshfunc(shfunc, lnklst, 1); 1251 stat = 0; 1252 } 1253 1254 if (arrayp) { 1255 char **arrptr; 1256 int namlen = strlen(name); 1257 VARARR(char, arrnam, namlen + HOOK_SUFFIX_LEN); 1258 memcpy(arrnam, name, namlen); 1259 memcpy(arrnam + namlen, HOOK_SUFFIX, HOOK_SUFFIX_LEN); 1260 1261 if ((arrptr = getaparam(arrnam))) { 1262 arrptr = arrdup(arrptr); 1263 for (; *arrptr; arrptr++) { 1264 if ((shfunc = getshfunc(*arrptr))) { 1265 int newret = doshfunc(shfunc, lnklst, 1); 1266 if (!ret) 1267 ret = newret; 1268 stat = 0; 1269 } 1270 } 1271 } 1272 } 1273 1274 sfcontext = osc; 1275 stopmsg = osm; 1276 incompfunc = old_incompfunc; 1277 1278 if (retval) 1279 *retval = ret; 1280 return stat; 1281} 1282 1283/* do pre-prompt stuff */ 1284 1285/**/ 1286void 1287preprompt(void) 1288{ 1289 static time_t lastperiodic; 1290 time_t currentmailcheck; 1291 LinkNode ln; 1292 zlong period = getiparam("PERIOD"); 1293 zlong mailcheck = getiparam("MAILCHECK"); 1294 1295 /* 1296 * Handle any pending window size changes before we compute prompts, 1297 * then block them again to avoid interrupts during prompt display. 1298 */ 1299 winch_unblock(); 1300 winch_block(); 1301 1302 if (isset(PROMPTSP) && isset(PROMPTCR) && !use_exit_printed && shout) { 1303 /* The PROMPT_SP heuristic will move the prompt down to a new line 1304 * if there was any dangling output on the line (assuming the terminal 1305 * has automatic margins, but we try even if hasam isn't set). 1306 * Unfortunately it interacts badly with ZLE displaying message 1307 * when ^D has been pressed. So just disable PROMPT_SP logic in 1308 * this case */ 1309 char *eolmark = getsparam("PROMPT_EOL_MARK"); 1310 char *str; 1311 int percents = opts[PROMPTPERCENT], w = 0; 1312 if (!eolmark) 1313 eolmark = "%B%S%#%s%b"; 1314 opts[PROMPTPERCENT] = 1; 1315 str = promptexpand(eolmark, 1, NULL, NULL, NULL); 1316 countprompt(str, &w, 0, -1); 1317 opts[PROMPTPERCENT] = percents; 1318 zputs(str, shout); 1319 fprintf(shout, "%*s\r%*s\r", (int)zterm_columns - w - !hasxn, 1320 "", w, ""); 1321 fflush(shout); 1322 free(str); 1323 } 1324 1325 /* If NOTIFY is not set, then check for completed * 1326 * jobs before we print the prompt. */ 1327 if (unset(NOTIFY)) 1328 scanjobs(); 1329 if (errflag) 1330 return; 1331 1332 /* If a shell function named "precmd" exists, * 1333 * then execute it. */ 1334 callhookfunc("precmd", NULL, 1, NULL); 1335 if (errflag) 1336 return; 1337 1338 /* If 1) the parameter PERIOD exists, 2) a hook function for * 1339 * "periodic" exists, 3) it's been greater than PERIOD since we * 1340 * executed any such hook, then execute it now. */ 1341 if (period && ((zlong)time(NULL) > (zlong)lastperiodic + period) && 1342 !callhookfunc("periodic", NULL, 1, NULL)) 1343 lastperiodic = time(NULL); 1344 if (errflag) 1345 return; 1346 1347 /* If WATCH is set, then check for the * 1348 * specified login/logout events. */ 1349 if (watch) { 1350 if ((int) difftime(time(NULL), lastwatch) > getiparam("LOGCHECK")) { 1351 dowatch(); 1352 lastwatch = time(NULL); 1353 } 1354 } 1355 if (errflag) 1356 return; 1357 1358 /* Check mail */ 1359 currentmailcheck = time(NULL); 1360 if (mailcheck && 1361 (zlong) difftime(currentmailcheck, lastmailcheck) > mailcheck) { 1362 char *mailfile; 1363 1364 if (mailpath && *mailpath && **mailpath) 1365 checkmailpath(mailpath); 1366 else { 1367 queue_signals(); 1368 if ((mailfile = getsparam("MAIL")) && *mailfile) { 1369 char *x[2]; 1370 1371 x[0] = mailfile; 1372 x[1] = NULL; 1373 checkmailpath(x); 1374 } 1375 unqueue_signals(); 1376 } 1377 lastmailcheck = currentmailcheck; 1378 } 1379 1380 if (prepromptfns) { 1381 for(ln = firstnode(prepromptfns); ln; ln = nextnode(ln)) { 1382 Prepromptfn ppnode = (Prepromptfn)getdata(ln); 1383 ppnode->func(); 1384 } 1385 } 1386} 1387 1388/**/ 1389static void 1390checkmailpath(char **s) 1391{ 1392 struct stat st; 1393 char *v, *u, c; 1394 1395 while (*s) { 1396 for (v = *s; *v && *v != '?'; v++); 1397 c = *v; 1398 *v = '\0'; 1399 if (c != '?') 1400 u = NULL; 1401 else 1402 u = v + 1; 1403 if (**s == 0) { 1404 *v = c; 1405 zerr("empty MAILPATH component: %s", *s); 1406 } else if (mailstat(unmeta(*s), &st) == -1) { 1407 if (errno != ENOENT) 1408 zerr("%e: %s", errno, *s); 1409 } else if (S_ISDIR(st.st_mode)) { 1410 LinkList l; 1411 DIR *lock = opendir(unmeta(*s)); 1412 char buf[PATH_MAX * 2], **arr, **ap; 1413 int ct = 1; 1414 1415 if (lock) { 1416 char *fn; 1417 1418 pushheap(); 1419 l = newlinklist(); 1420 while ((fn = zreaddir(lock, 1)) && !errflag) { 1421 if (u) 1422 sprintf(buf, "%s/%s?%s", *s, fn, u); 1423 else 1424 sprintf(buf, "%s/%s", *s, fn); 1425 addlinknode(l, dupstring(buf)); 1426 ct++; 1427 } 1428 closedir(lock); 1429 ap = arr = (char **) zhalloc(ct * sizeof(char *)); 1430 1431 while ((*ap++ = (char *)ugetnode(l))); 1432 checkmailpath(arr); 1433 popheap(); 1434 } 1435 } else if (shout) { 1436 if (st.st_size && st.st_atime <= st.st_mtime && 1437 st.st_mtime >= lastmailcheck) { 1438 if (!u) { 1439 fprintf(shout, "You have new mail.\n"); 1440 fflush(shout); 1441 } else { 1442 char *usav; 1443 int uusav = underscoreused; 1444 1445 usav = zalloc(underscoreused); 1446 1447 if (usav) 1448 memcpy(usav, zunderscore, underscoreused); 1449 1450 setunderscore(*s); 1451 1452 u = dupstring(u); 1453 if (! parsestr(u)) { 1454 singsub(&u); 1455 zputs(u, shout); 1456 fputc('\n', shout); 1457 fflush(shout); 1458 } 1459 if (usav) { 1460 setunderscore(usav); 1461 zfree(usav, uusav); 1462 } 1463 } 1464 } 1465 if (isset(MAILWARNING) && st.st_atime > st.st_mtime && 1466 st.st_atime > lastmailcheck && st.st_size) { 1467 fprintf(shout, "The mail in %s has been read.\n", unmeta(*s)); 1468 fflush(shout); 1469 } 1470 } 1471 *v = c; 1472 s++; 1473 } 1474} 1475 1476/* This prints the XTRACE prompt. */ 1477 1478/**/ 1479FILE *xtrerr = 0; 1480 1481/**/ 1482void 1483printprompt4(void) 1484{ 1485 if (!xtrerr) 1486 xtrerr = stderr; 1487 if (prompt4) { 1488 int l, t = opts[XTRACE]; 1489 char *s = dupstring(prompt4); 1490 1491 opts[XTRACE] = 0; 1492 unmetafy(s, &l); 1493 s = unmetafy(promptexpand(metafy(s, l, META_NOALLOC), 1494 0, NULL, NULL, NULL), &l); 1495 opts[XTRACE] = t; 1496 1497 fprintf(xtrerr, "%s", s); 1498 free(s); 1499 } 1500} 1501 1502/**/ 1503mod_export void 1504freestr(void *a) 1505{ 1506 zsfree(a); 1507} 1508 1509/**/ 1510mod_export void 1511gettyinfo(struct ttyinfo *ti) 1512{ 1513 if (SHTTY != -1) { 1514#ifdef HAVE_TERMIOS_H 1515# ifdef HAVE_TCGETATTR 1516 if (tcgetattr(SHTTY, &ti->tio) == -1) 1517# else 1518 if (ioctl(SHTTY, TCGETS, &ti->tio) == -1) 1519# endif 1520 zerr("bad tcgets: %e", errno); 1521#else 1522# ifdef HAVE_TERMIO_H 1523 ioctl(SHTTY, TCGETA, &ti->tio); 1524# else 1525 ioctl(SHTTY, TIOCGETP, &ti->sgttyb); 1526 ioctl(SHTTY, TIOCLGET, &ti->lmodes); 1527 ioctl(SHTTY, TIOCGETC, &ti->tchars); 1528 ioctl(SHTTY, TIOCGLTC, &ti->ltchars); 1529# endif 1530#endif 1531 } 1532} 1533 1534/**/ 1535mod_export void 1536settyinfo(struct ttyinfo *ti) 1537{ 1538 if (SHTTY != -1) { 1539#ifdef HAVE_TERMIOS_H 1540# ifdef HAVE_TCGETATTR 1541# ifndef TCSADRAIN 1542# define TCSADRAIN 1 /* XXX Princeton's include files are screwed up */ 1543# endif 1544 while (tcsetattr(SHTTY, TCSADRAIN, &ti->tio) == -1 && errno == EINTR) 1545 ; 1546# else 1547 while (ioctl(SHTTY, TCSETS, &ti->tio) == -1 && errno == EINTR) 1548 ; 1549# endif 1550 /* zerr("settyinfo: %e",errno);*/ 1551#else 1552# ifdef HAVE_TERMIO_H 1553 ioctl(SHTTY, TCSETA, &ti->tio); 1554# else 1555 ioctl(SHTTY, TIOCSETN, &ti->sgttyb); 1556 ioctl(SHTTY, TIOCLSET, &ti->lmodes); 1557 ioctl(SHTTY, TIOCSETC, &ti->tchars); 1558 ioctl(SHTTY, TIOCSLTC, &ti->ltchars); 1559# endif 1560#endif 1561 } 1562} 1563 1564/* the default tty state */ 1565 1566/**/ 1567mod_export struct ttyinfo shttyinfo; 1568 1569/* != 0 if we need to call resetvideo() */ 1570 1571/**/ 1572mod_export int resetneeded; 1573 1574#ifdef TIOCGWINSZ 1575/* window size changed */ 1576 1577/**/ 1578mod_export int winchanged; 1579#endif 1580 1581static int 1582adjustlines(int signalled) 1583{ 1584 int oldlines = zterm_lines; 1585 1586#ifdef TIOCGWINSZ 1587 if (signalled || zterm_lines <= 0) 1588 zterm_lines = shttyinfo.winsize.ws_row; 1589 else 1590 shttyinfo.winsize.ws_row = zterm_lines; 1591#endif /* TIOCGWINSZ */ 1592 if (zterm_lines <= 0) { 1593 DPUTS(signalled, "BUG: Impossible TIOCGWINSZ rows"); 1594 zterm_lines = tclines > 0 ? tclines : 24; 1595 } 1596 1597 if (zterm_lines > 2) 1598 termflags &= ~TERM_SHORT; 1599 else 1600 termflags |= TERM_SHORT; 1601 1602 return (zterm_lines != oldlines); 1603} 1604 1605static int 1606adjustcolumns(int signalled) 1607{ 1608 int oldcolumns = zterm_columns; 1609 1610#ifdef TIOCGWINSZ 1611 if (signalled || zterm_columns <= 0) 1612 zterm_columns = shttyinfo.winsize.ws_col; 1613 else 1614 shttyinfo.winsize.ws_col = zterm_columns; 1615#endif /* TIOCGWINSZ */ 1616 if (zterm_columns <= 0) { 1617 DPUTS(signalled, "BUG: Impossible TIOCGWINSZ cols"); 1618 zterm_columns = tccolumns > 0 ? tccolumns : 80; 1619 } 1620 1621 if (zterm_columns > 2) 1622 termflags &= ~TERM_NARROW; 1623 else 1624 termflags |= TERM_NARROW; 1625 1626 return (zterm_columns != oldcolumns); 1627} 1628 1629/* check the size of the window and adjust if necessary. * 1630 * The value of from: * 1631 * 0: called from update_job or setupvals * 1632 * 1: called from the SIGWINCH handler * 1633 * 2: called from the LINES parameter callback * 1634 * 3: called from the COLUMNS parameter callback */ 1635 1636/**/ 1637void 1638adjustwinsize(int from) 1639{ 1640 static int getwinsz = 1; 1641#ifdef TIOCGWINSZ 1642 int ttyrows = shttyinfo.winsize.ws_row; 1643 int ttycols = shttyinfo.winsize.ws_col; 1644#endif 1645 int resetzle = 0; 1646 1647 if (getwinsz || from == 1) { 1648#ifdef TIOCGWINSZ 1649 if (SHTTY == -1) 1650 return; 1651 if (ioctl(SHTTY, TIOCGWINSZ, (char *)&shttyinfo.winsize) == 0) { 1652 resetzle = (ttyrows != shttyinfo.winsize.ws_row || 1653 ttycols != shttyinfo.winsize.ws_col); 1654 if (from == 0 && resetzle && ttyrows && ttycols) 1655 from = 1; /* Signal missed while a job owned the tty? */ 1656 ttyrows = shttyinfo.winsize.ws_row; 1657 ttycols = shttyinfo.winsize.ws_col; 1658 } else { 1659 /* Set to value from environment on failure */ 1660 shttyinfo.winsize.ws_row = zterm_lines; 1661 shttyinfo.winsize.ws_col = zterm_columns; 1662 resetzle = (from == 1); 1663 } 1664#else 1665 resetzle = from == 1; 1666#endif /* TIOCGWINSZ */ 1667 } /* else 1668 return; */ 1669 1670 switch (from) { 1671 case 0: 1672 case 1: 1673 getwinsz = 0; 1674 /* Calling setiparam() here calls this function recursively, but * 1675 * because we've already called adjustlines() and adjustcolumns() * 1676 * here, recursive calls are no-ops unless a signal intervenes. * 1677 * The commented "else return;" above might be a safe shortcut, * 1678 * but I'm concerned about what happens on race conditions; e.g., * 1679 * suppose the user resizes his xterm during `eval $(resize)'? */ 1680 if (adjustlines(from) && zgetenv("LINES")) 1681 setiparam("LINES", zterm_lines); 1682 if (adjustcolumns(from) && zgetenv("COLUMNS")) 1683 setiparam("COLUMNS", zterm_columns); 1684 getwinsz = 1; 1685 break; 1686 case 2: 1687 resetzle = adjustlines(0); 1688 break; 1689 case 3: 1690 resetzle = adjustcolumns(0); 1691 break; 1692 } 1693 1694#ifdef TIOCGWINSZ 1695 if (interact && from >= 2 && 1696 (shttyinfo.winsize.ws_row != ttyrows || 1697 shttyinfo.winsize.ws_col != ttycols)) { 1698 /* shttyinfo.winsize is already set up correctly */ 1699 /* ioctl(SHTTY, TIOCSWINSZ, (char *)&shttyinfo.winsize); */ 1700 } 1701#endif /* TIOCGWINSZ */ 1702 1703 if (zleactive && resetzle) { 1704#ifdef TIOCGWINSZ 1705 winchanged = 1706#endif /* TIOCGWINSZ */ 1707 resetneeded = 1; 1708 zleentry(ZLE_CMD_RESET_PROMPT); 1709 zleentry(ZLE_CMD_REFRESH); 1710 } 1711} 1712 1713/* 1714 * Ensure the fdtable is large enough for fd, and that the 1715 * maximum fd is set appropriately. 1716 */ 1717static void 1718check_fd_table(int fd) 1719{ 1720 if (fd <= max_zsh_fd) 1721 return; 1722 1723 if (fd >= fdtable_size) { 1724 int old_size = fdtable_size; 1725 while (fd >= fdtable_size) 1726 fdtable = zrealloc(fdtable, 1727 (fdtable_size *= 2)*sizeof(*fdtable)); 1728 memset(fdtable + old_size, 0, 1729 (fdtable_size - old_size) * sizeof(*fdtable)); 1730 } 1731 max_zsh_fd = fd; 1732} 1733 1734/* Move a fd to a place >= 10 and mark the new fd in fdtable. If the fd * 1735 * is already >= 10, it is not moved. If it is invalid, -1 is returned. */ 1736 1737/**/ 1738mod_export int 1739movefd(int fd) 1740{ 1741 if(fd != -1 && fd < 10) { 1742#ifdef F_DUPFD 1743 int fe = fcntl(fd, F_DUPFD, 10); 1744#else 1745 int fe = movefd(dup(fd)); 1746#endif 1747 /* 1748 * To close or not to close if fe is -1? 1749 * If it is -1, we haven't moved the fd, so if we close 1750 * it we lose it; but we're probably not going to be able 1751 * to use it in situ anyway. So probably better to avoid a leak. 1752 */ 1753 zclose(fd); 1754 fd = fe; 1755 } 1756 if(fd != -1) { 1757 check_fd_table(fd); 1758 fdtable[fd] = FDT_INTERNAL; 1759 } 1760 return fd; 1761} 1762 1763/* 1764 * Move fd x to y. If x == -1, fd y is closed. 1765 * Returns y for success, -1 for failure. 1766 */ 1767 1768/**/ 1769mod_export int 1770redup(int x, int y) 1771{ 1772 int ret = y; 1773 1774 if(x < 0) 1775 zclose(y); 1776 else if (x != y) { 1777 if (dup2(x, y) == -1) { 1778 ret = -1; 1779 } else { 1780 check_fd_table(y); 1781 fdtable[y] = fdtable[x]; 1782 if (fdtable[y] == FDT_FLOCK || fdtable[y] == FDT_FLOCK_EXEC) 1783 fdtable[y] = FDT_INTERNAL; 1784 } 1785 /* 1786 * Closing any fd to the locked file releases the lock. 1787 * This isn't expected to happen, it's here for completeness. 1788 */ 1789 if (fdtable[x] == FDT_FLOCK) 1790 fdtable_flocks--; 1791 zclose(x); 1792 } 1793 1794 return ret; 1795} 1796 1797/* 1798 * Indicate that an fd has a file lock; if cloexec is 1 it will be closed 1799 * on exec. 1800 * The fd should already be known to fdtable (e.g. by movefd). 1801 * Note the fdtable code doesn't care what sort of lock 1802 * is used; this simply prevents the main shell exiting prematurely 1803 * when it holds a lock. 1804 */ 1805 1806/**/ 1807mod_export void 1808addlockfd(int fd, int cloexec) 1809{ 1810 if (cloexec) { 1811 if (fdtable[fd] != FDT_FLOCK) 1812 fdtable_flocks++; 1813 fdtable[fd] = FDT_FLOCK; 1814 } else { 1815 fdtable[fd] = FDT_FLOCK_EXEC; 1816 } 1817} 1818 1819/* Close the given fd, and clear it from fdtable. */ 1820 1821/**/ 1822mod_export int 1823zclose(int fd) 1824{ 1825 if (fd >= 0) { 1826 /* 1827 * Careful: we allow closing of arbitrary fd's, beyond 1828 * max_zsh_fd. In that case we don't try anything clever. 1829 */ 1830 if (fd <= max_zsh_fd) { 1831 if (fdtable[fd] == FDT_FLOCK) 1832 fdtable_flocks--; 1833 fdtable[fd] = FDT_UNUSED; 1834 while (max_zsh_fd > 0 && fdtable[max_zsh_fd] == FDT_UNUSED) 1835 max_zsh_fd--; 1836 if (fd == coprocin) 1837 coprocin = -1; 1838 if (fd == coprocout) 1839 coprocout = -1; 1840 } 1841 return close(fd); 1842 } 1843 return -1; 1844} 1845 1846/* 1847 * Close an fd returning 0 if used for locking; return -1 if it isn't. 1848 */ 1849 1850/**/ 1851mod_export int 1852zcloselockfd(int fd) 1853{ 1854 if (fd > max_zsh_fd) 1855 return -1; 1856 if (fdtable[fd] != FDT_FLOCK && fdtable[fd] != FDT_FLOCK_EXEC) 1857 return -1; 1858 zclose(fd); 1859 return 0; 1860} 1861 1862#ifdef HAVE__MKTEMP 1863extern char *_mktemp(char *); 1864#endif 1865 1866/* Get a unique filename for use as a temporary file. If "prefix" is 1867 * NULL, the name is relative to $TMPPREFIX; If it is non-NULL, the 1868 * unique suffix includes a prefixed '.' for improved readability. If 1869 * "use_heap" is true, we allocate the returned name on the heap. */ 1870 1871/**/ 1872mod_export char * 1873gettempname(const char *prefix, int use_heap) 1874{ 1875 char *ret, *suffix = prefix ? ".XXXXXX" : "XXXXXX"; 1876 1877 queue_signals(); 1878 if (!prefix && !(prefix = getsparam("TMPPREFIX"))) 1879 prefix = DEFAULT_TMPPREFIX; 1880 if (use_heap) 1881 ret = dyncat(unmeta(prefix), suffix); 1882 else 1883 ret = bicat(unmeta(prefix), suffix); 1884 1885#ifdef HAVE__MKTEMP 1886 /* Zsh uses mktemp() safely, so silence the warnings */ 1887 ret = (char *) _mktemp(ret); 1888#else 1889 ret = (char *) mktemp(ret); 1890#endif 1891 unqueue_signals(); 1892 1893 return ret; 1894} 1895 1896/**/ 1897mod_export int 1898gettempfile(const char *prefix, int use_heap, char **tempname) 1899{ 1900 char *fn; 1901 int fd; 1902#if HAVE_MKSTEMP 1903 char *suffix = prefix ? ".XXXXXX" : "XXXXXX"; 1904 1905 if (!prefix && !(prefix = getsparam("TMPPREFIX"))) 1906 prefix = DEFAULT_TMPPREFIX; 1907 if (use_heap) 1908 fn = dyncat(unmeta(prefix), suffix); 1909 else 1910 fn = bicat(unmeta(prefix), suffix); 1911 1912 fd = mkstemp(fn); 1913 if (fd < 0) { 1914 if (!use_heap) 1915 free(fn); 1916 fn = NULL; 1917 } 1918#else 1919 int failures = 0; 1920 1921 do { 1922 if (!(fn = gettempname(prefix, use_heap))) { 1923 fd = -1; 1924 break; 1925 } 1926 if ((fd = open(fn, O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0) 1927 break; 1928 if (!use_heap) 1929 free(fn); 1930 fn = NULL; 1931 } while (errno == EEXIST && ++failures < 16); 1932#endif 1933 *tempname = fn; 1934 return fd; 1935} 1936 1937/* Check if a string contains a token */ 1938 1939/**/ 1940mod_export int 1941has_token(const char *s) 1942{ 1943 while(*s) 1944 if(itok(*s++)) 1945 return 1; 1946 return 0; 1947} 1948 1949/* Delete a character in a string */ 1950 1951/**/ 1952mod_export void 1953chuck(char *str) 1954{ 1955 while ((str[0] = str[1])) 1956 str++; 1957} 1958 1959/**/ 1960mod_export int 1961tulower(int c) 1962{ 1963 c &= 0xff; 1964 return (isupper(c) ? tolower(c) : c); 1965} 1966 1967/**/ 1968mod_export int 1969tuupper(int c) 1970{ 1971 c &= 0xff; 1972 return (islower(c) ? toupper(c) : c); 1973} 1974 1975/* copy len chars from t into s, and null terminate */ 1976 1977/**/ 1978void 1979ztrncpy(char *s, char *t, int len) 1980{ 1981 while (len--) 1982 *s++ = *t++; 1983 *s = '\0'; 1984} 1985 1986/* copy t into *s and update s */ 1987 1988/**/ 1989mod_export void 1990strucpy(char **s, char *t) 1991{ 1992 char *u = *s; 1993 1994 while ((*u++ = *t++)); 1995 *s = u - 1; 1996} 1997 1998/**/ 1999mod_export void 2000struncpy(char **s, char *t, int n) 2001{ 2002 char *u = *s; 2003 2004 while (n--) 2005 *u++ = *t++; 2006 *s = u; 2007 *u = '\0'; 2008} 2009 2010/* Return the number of elements in an array of pointers. * 2011 * It doesn't count the NULL pointer at the end. */ 2012 2013/**/ 2014mod_export int 2015arrlen(char **s) 2016{ 2017 int count; 2018 2019 for (count = 0; *s; s++, count++); 2020 return count; 2021} 2022 2023/* Skip over a balanced pair of parenthesis. */ 2024 2025/**/ 2026mod_export int 2027skipparens(char inpar, char outpar, char **s) 2028{ 2029 int level; 2030 2031 if (**s != inpar) 2032 return -1; 2033 2034 for (level = 1; *++*s && level;) 2035 if (**s == inpar) 2036 ++level; 2037 else if (**s == outpar) 2038 --level; 2039 2040 return level; 2041} 2042 2043/**/ 2044mod_export zlong 2045zstrtol(const char *s, char **t, int base) 2046{ 2047 return zstrtol_underscore(s, t, base, 0); 2048} 2049 2050/* Convert string to zlong (see zsh.h). This function (without the z) * 2051 * is contained in the ANSI standard C library, but a lot of them seem * 2052 * to be broken. */ 2053 2054/**/ 2055mod_export zlong 2056zstrtol_underscore(const char *s, char **t, int base, int underscore) 2057{ 2058 const char *inp, *trunc = NULL; 2059 zulong calc = 0, newcalc = 0; 2060 int neg; 2061 2062 while (inblank(*s)) 2063 s++; 2064 2065 if ((neg = (*s == '-'))) 2066 s++; 2067 else if (*s == '+') 2068 s++; 2069 2070 if (!base) { 2071 if (*s != '0') 2072 base = 10; 2073 else if (*++s == 'x' || *s == 'X') 2074 base = 16, s++; 2075 else 2076 base = 8; 2077 } 2078 inp = s; 2079 if (base < 2 || base > 36) { 2080 zerr("invalid base (must be 2 to 36 inclusive): %d", base); 2081 return (zlong)0; 2082 } else if (base <= 10) { 2083 for (; (*s >= '0' && *s < ('0' + base)) || 2084 (underscore && *s == '_'); s++) { 2085 if (trunc || *s == '_') 2086 continue; 2087 newcalc = calc * base + *s - '0'; 2088 if (newcalc < calc) 2089 { 2090 trunc = s; 2091 continue; 2092 } 2093 calc = newcalc; 2094 } 2095 } else { 2096 for (; idigit(*s) || (*s >= 'a' && *s < ('a' + base - 10)) 2097 || (*s >= 'A' && *s < ('A' + base - 10)) 2098 || (underscore && *s == '_'); s++) { 2099 if (trunc || *s == '_') 2100 continue; 2101 newcalc = calc*base + (idigit(*s) ? (*s - '0') : (*s & 0x1f) + 9); 2102 if (newcalc < calc) 2103 { 2104 trunc = s; 2105 continue; 2106 } 2107 calc = newcalc; 2108 } 2109 } 2110 2111 /* 2112 * Special case: check for a number that was just too long for 2113 * signed notation. 2114 * Extra special case: the lowest negative number would trigger 2115 * the first test, but is actually representable correctly. 2116 * This is a 1 in the top bit, all others zero, so test for 2117 * that explicitly. 2118 */ 2119 if (!trunc && (zlong)calc < 0 && 2120 (!neg || calc & ~((zulong)1 << (8*sizeof(zulong)-1)))) 2121 { 2122 trunc = s - 1; 2123 calc /= base; 2124 } 2125 2126 if (trunc) 2127 zwarn("number truncated after %d digits: %s", (int)(trunc - inp), inp); 2128 2129 if (t) 2130 *t = (char *)s; 2131 return neg ? -(zlong)calc : (zlong)calc; 2132} 2133 2134/**/ 2135mod_export int 2136setblock_fd(int turnonblocking, int fd, long *modep) 2137{ 2138#ifdef O_NDELAY 2139# ifdef O_NONBLOCK 2140# define NONBLOCK (O_NDELAY|O_NONBLOCK) 2141# else /* !O_NONBLOCK */ 2142# define NONBLOCK O_NDELAY 2143# endif /* !O_NONBLOCK */ 2144#else /* !O_NDELAY */ 2145# ifdef O_NONBLOCK 2146# define NONBLOCK O_NONBLOCK 2147# else /* !O_NONBLOCK */ 2148# define NONBLOCK 0 2149# endif /* !O_NONBLOCK */ 2150#endif /* !O_NDELAY */ 2151 2152#if NONBLOCK 2153 struct stat st; 2154 2155 if (!fstat(fd, &st) && !S_ISREG(st.st_mode)) { 2156 *modep = fcntl(fd, F_GETFL, 0); 2157 if (*modep != -1) { 2158 if (!turnonblocking) { 2159 /* We want to know if blocking was off */ 2160 if ((*modep & NONBLOCK) || 2161 !fcntl(fd, F_SETFL, *modep | NONBLOCK)) 2162 return 1; 2163 } else if ((*modep & NONBLOCK) && 2164 !fcntl(fd, F_SETFL, *modep & ~NONBLOCK)) { 2165 /* Here we want to know if the state changed */ 2166 return 1; 2167 } 2168 } 2169 } else 2170#endif /* NONBLOCK */ 2171 *modep = -1; 2172 return 0; 2173 2174#undef NONBLOCK 2175} 2176 2177/**/ 2178int 2179setblock_stdin(void) 2180{ 2181 long mode; 2182 return setblock_fd(1, 0, &mode); 2183} 2184 2185/* 2186 * Check for pending input on fd. If polltty is set, we may need to 2187 * use termio to look for input. As a final resort, go to non-blocking 2188 * input and try to read a character, which in this case will be 2189 * returned in *readchar. 2190 * 2191 * Note that apart from setting (and restoring) non-blocking input, 2192 * this function does not change the input mode. The calling function 2193 * should have set cbreak mode if necessary. 2194 */ 2195 2196/**/ 2197mod_export int 2198read_poll(int fd, int *readchar, int polltty, zlong microseconds) 2199{ 2200 int ret = -1; 2201 long mode = -1; 2202 char c; 2203#ifdef HAVE_SELECT 2204 fd_set foofd; 2205 struct timeval expire_tv; 2206#else 2207#ifdef FIONREAD 2208 int val; 2209#endif 2210#endif 2211#ifdef HAS_TIO 2212 struct ttyinfo ti; 2213#endif 2214 2215 2216#if defined(HAS_TIO) && !defined(__CYGWIN__) 2217 /* 2218 * Under Solaris, at least, reading from the terminal in non-canonical 2219 * mode requires that we use the VMIN mechanism to poll. Any attempt 2220 * to check any other way, or to set the terminal to non-blocking mode 2221 * and poll that way, fails; it will just for canonical mode input. 2222 * We should probably use this mechanism if the user has set non-canonical 2223 * mode, in which case testing here for isatty() and ~ICANON would be 2224 * better than testing whether bin_read() set it, but for now we've got 2225 * enough problems. 2226 * 2227 * Under Cygwin, you won't be surprised to here, this mechanism, 2228 * although present, doesn't work, and we *have* to use ordinary 2229 * non-blocking reads to find out if there is a character present 2230 * in non-canonical mode. 2231 * 2232 * I am assuming Solaris is nearer the UNIX norm. This is not necessarily 2233 * as plausible as it sounds, but it seems the right way to guess. 2234 * pws 2000/06/26 2235 */ 2236 if (polltty) { 2237 gettyinfo(&ti); 2238 if ((polltty = ti.tio.c_cc[VMIN])) { 2239 ti.tio.c_cc[VMIN] = 0; 2240 /* termios timeout is 10ths of a second */ 2241 ti.tio.c_cc[VTIME] = (int) (microseconds / (zlong)100000); 2242 settyinfo(&ti); 2243 } 2244 } 2245#else 2246 polltty = 0; 2247#endif 2248#ifdef HAVE_SELECT 2249 expire_tv.tv_sec = (int) (microseconds / (zlong)1000000); 2250 expire_tv.tv_usec = microseconds % (zlong)1000000; 2251 FD_ZERO(&foofd); 2252 FD_SET(fd, &foofd); 2253 ret = select(fd+1, (SELECT_ARG_2_T) &foofd, NULL, NULL, &expire_tv); 2254#else 2255#ifdef FIONREAD 2256 if (ioctl(fd, FIONREAD, (char *) &val) == 0) 2257 ret = (val > 0); 2258#endif 2259#endif 2260 2261 if (ret < 0) { 2262 /* 2263 * Final attempt: set non-blocking read and try to read a character. 2264 * Praise Bill, this works under Cygwin (nothing else seems to). 2265 */ 2266 if ((polltty || setblock_fd(0, fd, &mode)) && read(fd, &c, 1) > 0) { 2267 *readchar = c; 2268 ret = 1; 2269 } 2270 if (mode != -1) 2271 fcntl(fd, F_SETFL, mode); 2272 } 2273#ifdef HAS_TIO 2274 if (polltty) { 2275 ti.tio.c_cc[VMIN] = 1; 2276 ti.tio.c_cc[VTIME] = 0; 2277 settyinfo(&ti); 2278 } 2279#endif 2280 return (ret > 0); 2281} 2282 2283/**/ 2284int 2285checkrmall(char *s) 2286{ 2287 if (!shout) 2288 return 1; 2289 fprintf(shout, "zsh: sure you want to delete all the files in "); 2290 if (*s != '/') { 2291 nicezputs(pwd[1] ? unmeta(pwd) : "", shout); 2292 fputc('/', shout); 2293 } 2294 nicezputs(s, shout); 2295 if(isset(RMSTARWAIT)) { 2296 fputs("? (waiting ten seconds)", shout); 2297 fflush(shout); 2298 zbeep(); 2299 sleep(10); 2300 fputc('\n', shout); 2301 } 2302 if (errflag) 2303 return 0; 2304 fputs(" [yn]? ", shout); 2305 fflush(shout); 2306 zbeep(); 2307 return (getquery("ny", 1) == 'y'); 2308} 2309 2310/**/ 2311mod_export ssize_t 2312read_loop(int fd, char *buf, size_t len) 2313{ 2314 ssize_t got = len; 2315 2316 while (1) { 2317 ssize_t ret = read(fd, buf, len); 2318 if (ret == len) 2319 break; 2320 if (ret <= 0) { 2321 if (ret < 0) { 2322 if (errno == EINTR) 2323 continue; 2324 if (fd != SHTTY) 2325 zwarn("read failed: %e", errno); 2326 } 2327 return ret; 2328 } 2329 buf += ret; 2330 len -= ret; 2331 } 2332 2333 return got; 2334} 2335 2336/**/ 2337mod_export ssize_t 2338write_loop(int fd, const char *buf, size_t len) 2339{ 2340 ssize_t wrote = len; 2341 2342 while (1) { 2343 ssize_t ret = write(fd, buf, len); 2344 if (ret == len) 2345 break; 2346 if (ret < 0) { 2347 if (errno == EINTR) 2348 continue; 2349 if (fd != SHTTY) 2350 zwarn("write failed: %e", errno); 2351 return -1; 2352 } 2353 buf += ret; 2354 len -= ret; 2355 } 2356 2357 return wrote; 2358} 2359 2360static int 2361read1char(int echo) 2362{ 2363 char c; 2364 2365 while (read(SHTTY, &c, 1) != 1) { 2366 if (errno != EINTR || errflag || retflag || breaks || contflag) 2367 return -1; 2368 } 2369 if (echo) 2370 write_loop(SHTTY, &c, 1); 2371 return STOUC(c); 2372} 2373 2374/**/ 2375mod_export int 2376noquery(int purge) 2377{ 2378 int val = 0; 2379 2380#ifdef FIONREAD 2381 char c; 2382 2383 ioctl(SHTTY, FIONREAD, (char *)&val); 2384 if (purge) { 2385 for (; val; val--) { 2386 if (read(SHTTY, &c, 1) != 1) { 2387 /* Do nothing... */ 2388 } 2389 } 2390 } 2391#endif 2392 2393 return val; 2394} 2395 2396/**/ 2397int 2398getquery(char *valid_chars, int purge) 2399{ 2400 int c, d, nl = 0; 2401 int isem = !strcmp(term, "emacs"); 2402 struct ttyinfo ti; 2403 2404 attachtty(mypgrp); 2405 2406 gettyinfo(&ti); 2407#ifdef HAS_TIO 2408 ti.tio.c_lflag &= ~ECHO; 2409 if (!isem) { 2410 ti.tio.c_lflag &= ~ICANON; 2411 ti.tio.c_cc[VMIN] = 1; 2412 ti.tio.c_cc[VTIME] = 0; 2413 } 2414#else 2415 ti.sgttyb.sg_flags &= ~ECHO; 2416 if (!isem) 2417 ti.sgttyb.sg_flags |= CBREAK; 2418#endif 2419 settyinfo(&ti); 2420 2421 if (noquery(purge)) { 2422 if (!isem) 2423 settyinfo(&shttyinfo); 2424 write_loop(SHTTY, "n\n", 2); 2425 return 'n'; 2426 } 2427 2428 while ((c = read1char(0)) >= 0) { 2429 if (c == 'Y') 2430 c = 'y'; 2431 else if (c == 'N') 2432 c = 'n'; 2433 if (!valid_chars) 2434 break; 2435 if (c == '\n') { 2436 c = *valid_chars; 2437 nl = 1; 2438 break; 2439 } 2440 if (strchr(valid_chars, c)) { 2441 nl = 1; 2442 break; 2443 } 2444 zbeep(); 2445 } 2446 if (c >= 0) { 2447 char buf = (char)c; 2448 write_loop(SHTTY, &buf, 1); 2449 } 2450 if (nl) 2451 write_loop(SHTTY, "\n", 1); 2452 2453 if (isem) { 2454 if (c != '\n') 2455 while ((d = read1char(1)) >= 0 && d != '\n'); 2456 } else { 2457 if (c != '\n' && !valid_chars) { 2458#ifdef MULTIBYTE_SUPPORT 2459 if (isset(MULTIBYTE) && c >= 0) { 2460 /* 2461 * No waiting for a valid character, and no draining; 2462 * we should ensure we haven't stopped in the middle 2463 * of a multibyte character. 2464 */ 2465 mbstate_t mbs; 2466 char cc = (char)c; 2467 memset(&mbs, 0, sizeof(mbs)); 2468 for (;;) { 2469 size_t ret = mbrlen(&cc, 1, &mbs); 2470 2471 if (ret != MB_INCOMPLETE) 2472 break; 2473 c = read1char(1); 2474 if (c < 0) 2475 break; 2476 cc = (char)c; 2477 } 2478 } 2479#endif 2480 write_loop(SHTTY, "\n", 1); 2481 } 2482 } 2483 settyinfo(&shttyinfo); 2484 return c; 2485} 2486 2487static int d; 2488static char *guess, *best; 2489static Patprog spckpat; 2490 2491/**/ 2492static void 2493spscan(HashNode hn, UNUSED(int scanflags)) 2494{ 2495 int nd; 2496 2497 if (spckpat && pattry(spckpat, hn->nam)) 2498 return; 2499 2500 nd = spdist(hn->nam, guess, (int) strlen(guess) / 4 + 1); 2501 if (nd <= d) { 2502 best = hn->nam; 2503 d = nd; 2504 } 2505} 2506 2507/* spellcheck a word */ 2508/* fix s ; if hist is nonzero, fix the history list too */ 2509 2510/**/ 2511mod_export void 2512spckword(char **s, int hist, int cmd, int ask) 2513{ 2514 char *t, *correct_ignore; 2515 int x; 2516 char ic = '\0'; 2517 int ne; 2518 int preflen = 0; 2519 int autocd = cmd && isset(AUTOCD) && strcmp(*s, ".") && strcmp(*s, ".."); 2520 2521 if ((histdone & HISTFLAG_NOEXEC) || **s == '-' || **s == '%') 2522 return; 2523 if (!strcmp(*s, "in")) 2524 return; 2525 if (!(*s)[0] || !(*s)[1]) 2526 return; 2527 if (cmd) { 2528 if (shfunctab->getnode(shfunctab, *s) || 2529 builtintab->getnode(builtintab, *s) || 2530 cmdnamtab->getnode(cmdnamtab, *s) || 2531 aliastab->getnode(aliastab, *s) || 2532 reswdtab->getnode(reswdtab, *s)) 2533 return; 2534 else if (isset(HASHLISTALL)) { 2535 cmdnamtab->filltable(cmdnamtab); 2536 if (cmdnamtab->getnode(cmdnamtab, *s)) 2537 return; 2538 } 2539 } 2540 t = *s; 2541 if (*t == Tilde || *t == Equals || *t == String) 2542 t++; 2543 for (; *t; t++) 2544 if (itok(*t)) 2545 return; 2546 best = NULL; 2547 for (t = *s; *t; t++) 2548 if (*t == '/') 2549 break; 2550 if (**s == Tilde && !*t) 2551 return; 2552 2553 if ((correct_ignore = getsparam("CORRECT_IGNORE")) != NULL) { 2554 tokenize(correct_ignore = dupstring(correct_ignore)); 2555 remnulargs(correct_ignore); 2556 spckpat = patcompile(correct_ignore, 0, NULL); 2557 } else 2558 spckpat = NULL; 2559 2560 if (**s == String && !*t) { 2561 guess = *s + 1; 2562 if (itype_end(guess, IIDENT, 1) == guess) 2563 return; 2564 ic = String; 2565 d = 100; 2566 scanhashtable(paramtab, 1, 0, 0, spscan, 0); 2567 } else if (**s == Equals) { 2568 if (*t) 2569 return; 2570 if (hashcmd(guess = *s + 1, pathchecked)) 2571 return; 2572 d = 100; 2573 ic = Equals; 2574 scanhashtable(aliastab, 1, 0, 0, spscan, 0); 2575 scanhashtable(cmdnamtab, 1, 0, 0, spscan, 0); 2576 } else { 2577 guess = *s; 2578 if (*guess == Tilde || *guess == String) { 2579 ic = *guess; 2580 if (!*++t) 2581 return; 2582 guess = dupstring(guess); 2583 ne = noerrs; 2584 noerrs = 2; 2585 singsub(&guess); 2586 noerrs = ne; 2587 if (!guess) 2588 return; 2589 preflen = strlen(guess) - strlen(t); 2590 } 2591 if (access(unmeta(guess), F_OK) == 0) 2592 return; 2593 best = spname(guess); 2594 if (!*t && cmd) { 2595 if (hashcmd(guess, pathchecked)) 2596 return; 2597 d = 100; 2598 scanhashtable(reswdtab, 1, 0, 0, spscan, 0); 2599 scanhashtable(aliastab, 1, 0, 0, spscan, 0); 2600 scanhashtable(shfunctab, 1, 0, 0, spscan, 0); 2601 scanhashtable(builtintab, 1, 0, 0, spscan, 0); 2602 scanhashtable(cmdnamtab, 1, 0, 0, spscan, 0); 2603 if (autocd) { 2604 char **pp; 2605 for (pp = cdpath; *pp; pp++) { 2606 char bestcd[PATH_MAX + 1]; 2607 int thisdist; 2608 /* Less than d here, instead of less than or equal * 2609 * as used in spscan(), so that an autocd is chosen * 2610 * only when it is better than anything so far, and * 2611 * so we prefer directories earlier in the cdpath. */ 2612 if ((thisdist = mindist(*pp, *s, bestcd)) < d) { 2613 best = dupstring(bestcd); 2614 d = thisdist; 2615 } 2616 } 2617 } 2618 } 2619 } 2620 if (errflag) 2621 return; 2622 if (best && (int)strlen(best) > 1 && strcmp(best, guess)) { 2623 if (ic) { 2624 char *u; 2625 if (preflen) { 2626 /* do not correct the result of an expansion */ 2627 if (strncmp(guess, best, preflen)) 2628 return; 2629 /* replace the temporarily expanded prefix with the original */ 2630 u = (char *) hcalloc(t - *s + strlen(best + preflen) + 1); 2631 strncpy(u, *s, t - *s); 2632 strcpy(u + (t - *s), best + preflen); 2633 } else { 2634 u = (char *) hcalloc(strlen(best) + 2); 2635 strcpy(u + 1, best); 2636 } 2637 best = u; 2638 guess = *s; 2639 *guess = *best = ztokens[ic - Pound]; 2640 } 2641 if (ask) { 2642 if (noquery(0)) { 2643 x = 'n'; 2644 } else if (shout) { 2645 char *pptbuf; 2646 pptbuf = promptexpand(sprompt, 0, best, guess, NULL); 2647 zputs(pptbuf, shout); 2648 free(pptbuf); 2649 fflush(shout); 2650 zbeep(); 2651 x = getquery("nyae \t", 0); 2652 if (cmd && x == 'n') 2653 pathchecked = path; 2654 } else 2655 x = 'n'; 2656 } else 2657 x = 'y'; 2658 if (x == 'y' || x == ' ' || x == '\t') { 2659 *s = dupstring(best); 2660 if (hist) 2661 hwrep(best); 2662 } else if (x == 'a') { 2663 histdone |= HISTFLAG_NOEXEC; 2664 } else if (x == 'e') { 2665 histdone |= HISTFLAG_NOEXEC | HISTFLAG_RECALL; 2666 } 2667 if (ic) 2668 **s = ic; 2669 } 2670} 2671 2672/* 2673 * Helper for ztrftime. Called with a pointer to the length left 2674 * in the buffer, and a new string length to decrement from that. 2675 * Returns 0 if the new length fits, 1 otherwise. We assume a terminating 2676 * NUL and return 1 if that doesn't fit. 2677 */ 2678 2679static int 2680ztrftimebuf(int *bufsizeptr, int decr) 2681{ 2682 if (*bufsizeptr <= decr) 2683 return 1; 2684 *bufsizeptr -= decr; 2685 return 0; 2686} 2687 2688/* 2689 * Like the system function, this returns the number of characters 2690 * copied, not including the terminating NUL. This may be zero 2691 * if the string didn't fit. 2692 * 2693 * As an extension, try to detect an error in strftime --- typically 2694 * not enough memory --- and return -1. Not guaranteed to be portable, 2695 * since the strftime() interface doesn't make any guarantees about 2696 * the state of the buffer if it returns zero. 2697 */ 2698 2699/**/ 2700mod_export int 2701ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm) 2702{ 2703 int hr12, decr; 2704#ifndef HAVE_STRFTIME 2705 static char *astr[] = 2706 {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; 2707 static char *estr[] = 2708 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", 2709 "Aug", "Sep", "Oct", "Nov", "Dec"}; 2710#endif 2711 char *origbuf = buf; 2712 char tmp[4]; 2713 2714 2715 while (*fmt) 2716 if (*fmt == '%') { 2717 int strip; 2718 2719 fmt++; 2720 if (*fmt == '-') { 2721 strip = 1; 2722 fmt++; 2723 } else 2724 strip = 0; 2725 /* 2726 * Assume this format will take up at least two 2727 * characters. Not always true, but if that matters 2728 * we are so close to the edge it's not a big deal. 2729 * Fix up some longer cases specially when we get to them. 2730 */ 2731 if (ztrftimebuf(&bufsize, 2)) 2732 return -1; 2733 switch (*fmt++) { 2734 case 'd': 2735 if (tm->tm_mday > 9 || !strip) 2736 *buf++ = '0' + tm->tm_mday / 10; 2737 *buf++ = '0' + tm->tm_mday % 10; 2738 break; 2739 case 'f': 2740 strip = 1; 2741 /* FALLTHROUGH */ 2742 case 'e': 2743 if (tm->tm_mday > 9) 2744 *buf++ = '0' + tm->tm_mday / 10; 2745 else if (!strip) 2746 *buf++ = ' '; 2747 *buf++ = '0' + tm->tm_mday % 10; 2748 break; 2749 case 'K': 2750 strip = 1; 2751 /* FALLTHROUGH */ 2752 case 'H': 2753 case 'k': 2754 if (tm->tm_hour > 9) 2755 *buf++ = '0' + tm->tm_hour / 10; 2756 else if (!strip) { 2757 if (fmt[-1] == 'H') 2758 *buf++ = '0'; 2759 else 2760 *buf++ = ' '; 2761 } 2762 *buf++ = '0' + tm->tm_hour % 10; 2763 break; 2764 case 'L': 2765 strip = 1; 2766 /* FALLTHROUGH */ 2767 case 'l': 2768 hr12 = tm->tm_hour % 12; 2769 if (hr12 == 0) 2770 hr12 = 12; 2771 if (hr12 > 9) 2772 *buf++ = '1'; 2773 else if (!strip) 2774 *buf++ = ' '; 2775 2776 *buf++ = '0' + (hr12 % 10); 2777 break; 2778 case 'm': 2779 if (tm->tm_mon > 8 || !strip) 2780 *buf++ = '0' + (tm->tm_mon + 1) / 10; 2781 *buf++ = '0' + (tm->tm_mon + 1) % 10; 2782 break; 2783 case 'M': 2784 if (tm->tm_min > 9 || !strip) 2785 *buf++ = '0' + tm->tm_min / 10; 2786 *buf++ = '0' + tm->tm_min % 10; 2787 break; 2788 case 'S': 2789 if (tm->tm_sec > 9 || !strip) 2790 *buf++ = '0' + tm->tm_sec / 10; 2791 *buf++ = '0' + tm->tm_sec % 10; 2792 break; 2793 case 'y': 2794 if (tm->tm_year > 9 || !strip) 2795 *buf++ = '0' + (tm->tm_year / 10) % 10; 2796 *buf++ = '0' + tm->tm_year % 10; 2797 break; 2798 case '\0': 2799 /* Guard against premature end of string */ 2800 *buf++ = '%'; 2801 fmt--; 2802 break; 2803#ifndef HAVE_STRFTIME 2804 case 'Y': 2805 { 2806 /* 2807 * Not worth handling this natively if 2808 * strftime has it. 2809 */ 2810 int year, digits, testyear; 2811 year = tm->tm_year + 1900; 2812 digits = 1; 2813 testyear = year; 2814 while (testyear > 9) { 2815 digits++; 2816 testyear /= 10; 2817 } 2818 if (ztrftimebuf(&bufsize, digits)) 2819 return -1; 2820 sprintf(buf, "%d", year); 2821 buf += digits; 2822 break; 2823 } 2824 case 'a': 2825 if (ztrftimebuf(&bufsize, strlen(astr[tm->tm_wday]) - 2)) 2826 return -1; 2827 strucpy(&buf, astr[tm->tm_wday]); 2828 break; 2829 case 'b': 2830 if (ztrftimebuf(&bufsize, strlen(estr[tm->tm_mon]) - 2)) 2831 return -1; 2832 strucpy(&buf, estr[tm->tm_mon]); 2833 break; 2834 case 'p': 2835 *buf++ = (tm->tm_hour > 11) ? 'p' : 'a'; 2836 *buf++ = 'm'; 2837 break; 2838 default: 2839 *buf++ = '%'; 2840 if (fmt[-1] != '%') 2841 *buf++ = fmt[-1]; 2842#else 2843 default: 2844 /* 2845 * Remember we've already allowed for two characters 2846 * in the accounting in bufsize (but nowhere else). 2847 */ 2848 *buf = '\1'; 2849 sprintf(tmp, strip ? "%%-%c" : "%%%c", fmt[-1]); 2850 if (!strftime(buf, bufsize + 2, tmp, tm)) 2851 { 2852 if (*buf) { 2853 buf[0] = '\0'; 2854 return -1; 2855 } 2856 return 0; 2857 } 2858 decr = strlen(buf); 2859 buf += decr; 2860 bufsize -= decr - 2; 2861#endif 2862 break; 2863 } 2864 } else { 2865 if (ztrftimebuf(&bufsize, 1)) 2866 return -1; 2867 *buf++ = *fmt++; 2868 } 2869 *buf = '\0'; 2870 return buf - origbuf; 2871} 2872 2873/**/ 2874mod_export char * 2875zjoin(char **arr, int delim, int heap) 2876{ 2877 int len = 0; 2878 char **s, *ret, *ptr; 2879 2880 for (s = arr; *s; s++) 2881 len += strlen(*s) + 1 + (imeta(delim) ? 1 : 0); 2882 if (!len) 2883 return heap? "" : ztrdup(""); 2884 ptr = ret = (heap ? (char *) hcalloc(len) : (char *) zshcalloc(len)); 2885 for (s = arr; *s; s++) { 2886 strucpy(&ptr, *s); 2887 if (imeta(delim)) { 2888 *ptr++ = Meta; 2889 *ptr++ = delim ^ 32; 2890 } 2891 else 2892 *ptr++ = delim; 2893 } 2894 ptr[-1 - (imeta(delim) ? 1 : 0)] = '\0'; 2895 return ret; 2896} 2897 2898/* Split a string containing a colon separated list * 2899 * of items into an array of strings. */ 2900 2901/**/ 2902mod_export char ** 2903colonsplit(char *s, int uniq) 2904{ 2905 int ct; 2906 char *t, **ret, **ptr, **p; 2907 2908 for (t = s, ct = 0; *t; t++) /* count number of colons */ 2909 if (*t == ':') 2910 ct++; 2911 ptr = ret = (char **) zalloc(sizeof(char **) * (ct + 2)); 2912 2913 t = s; 2914 do { 2915 s = t; 2916 /* move t to point at next colon */ 2917 for (; *t && *t != ':'; t++); 2918 if (uniq) 2919 for (p = ret; p < ptr; p++) 2920 if ((int)strlen(*p) == t - s && ! strncmp(*p, s, t - s)) 2921 goto cont; 2922 *ptr = (char *) zalloc((t - s) + 1); 2923 ztrncpy(*ptr++, s, t - s); 2924 cont: ; 2925 } 2926 while (*t++); 2927 *ptr = NULL; 2928 return ret; 2929} 2930 2931/**/ 2932static int 2933skipwsep(char **s) 2934{ 2935 char *t = *s; 2936 int i = 0; 2937 2938 /* 2939 * Don't need to handle mutlibyte characters, they can't 2940 * be IWSEP. Do need to check for metafication. 2941 */ 2942 while (*t && iwsep(*t == Meta ? t[1] ^ 32 : *t)) { 2943 if (*t == Meta) 2944 t++; 2945 t++; 2946 i++; 2947 } 2948 *s = t; 2949 return i; 2950} 2951 2952/* 2953 * haven't worked out what allownull does; it's passed down from 2954 * sepsplit but all the cases it's used are either 0 or 1 without 2955 * a comment. it seems to be something to do with the `nulstring' 2956 * which i think is some kind of a metafication thing, so probably 2957 * allownull's value is associated with whether we are using 2958 * metafied strings. 2959 * see findsep() below for handling of `quote' argument 2960 */ 2961 2962/**/ 2963mod_export char ** 2964spacesplit(char *s, int allownull, int heap, int quote) 2965{ 2966 char *t, **ret, **ptr; 2967 int l = sizeof(*ret) * (wordcount(s, NULL, -!allownull) + 1); 2968 char *(*dup)(const char *) = (heap ? dupstring : ztrdup); 2969 2970 ptr = ret = (heap ? (char **) hcalloc(l) : (char **) zshcalloc(l)); 2971 2972 if (quote) { 2973 /* 2974 * we will be stripping quoted separators by hacking string, 2975 * so make sure it's hackable. 2976 */ 2977 s = dupstring(s); 2978 } 2979 2980 t = s; 2981 skipwsep(&s); 2982 MB_METACHARINIT(); 2983 if (*s && itype_end(s, ISEP, 1) != s) 2984 *ptr++ = dup(allownull ? "" : nulstring); 2985 else if (!allownull && t != s) 2986 *ptr++ = dup(""); 2987 while (*s) { 2988 char *iend = itype_end(s, ISEP, 1); 2989 if (iend != s) { 2990 s = iend; 2991 skipwsep(&s); 2992 } 2993 else if (quote && *s == '\\') { 2994 s++; 2995 skipwsep(&s); 2996 } 2997 t = s; 2998 (void)findsep(&s, NULL, quote); 2999 if (s > t || allownull) { 3000 *ptr = (heap ? (char *) hcalloc((s - t) + 1) : 3001 (char *) zshcalloc((s - t) + 1)); 3002 ztrncpy(*ptr++, t, s - t); 3003 } else 3004 *ptr++ = dup(nulstring); 3005 t = s; 3006 skipwsep(&s); 3007 } 3008 if (!allownull && t != s) 3009 *ptr++ = dup(""); 3010 *ptr = NULL; 3011 return ret; 3012} 3013 3014/* 3015 * Find a separator. Return 0 if already at separator, 1 if separator 3016 * found later, else -1. (Historical note: used to return length into 3017 * string but this is all that is necessary and is less ambiguous with 3018 * multibyte characters around.) 3019 * 3020 * *s is the string we are looking along, which will be updated 3021 * to the point we have got to. 3022 * 3023 * sep is a possibly multicharacter separator to look for. If NULL, 3024 * use normal separator characters. If *sep is NULL, split on individual 3025 * characters. 3026 * 3027 * quote is a flag that '\<sep>' should not be treated as a separator. 3028 * in this case we need to be able to strip the backslash directly 3029 * in the string, so the calling function must have sent us something 3030 * modifiable. currently this only works for sep == NULL. also in 3031 * in this case only, we need to turn \\ into \. 3032 */ 3033 3034/**/ 3035static int 3036findsep(char **s, char *sep, int quote) 3037{ 3038 /* 3039 */ 3040 int i, ilen; 3041 char *t, *tt; 3042 convchar_t c; 3043 3044 MB_METACHARINIT(); 3045 if (!sep) { 3046 for (t = *s; *t; t += ilen) { 3047 if (quote && *t == '\\') { 3048 if (t[1] == '\\') { 3049 chuck(t); 3050 ilen = 1; 3051 continue; 3052 } else { 3053 ilen = MB_METACHARLENCONV(t+1, &c); 3054 if (WC_ZISTYPE(c, ISEP)) { 3055 chuck(t); 3056 /* then advance over new character, length ilen */ 3057 } else { 3058 /* treat *t (backslash) as normal byte */ 3059 if (isep(*t)) 3060 break; 3061 ilen = 1; 3062 } 3063 } 3064 } else { 3065 ilen = MB_METACHARLENCONV(t, &c); 3066 if (WC_ZISTYPE(c, ISEP)) 3067 break; 3068 } 3069 } 3070 i = (t > *s); 3071 *s = t; 3072 return i; 3073 } 3074 if (!sep[0]) { 3075 /* 3076 * NULL separator just means advance past first character, 3077 * if any. 3078 */ 3079 if (**s) { 3080 *s += MB_METACHARLEN(*s); 3081 return 1; 3082 } 3083 return -1; 3084 } 3085 for (i = 0; **s; i++) { 3086 /* 3087 * The following works for multibyte characters by virtue of 3088 * the fact that sep may be a string (and we don't care how 3089 * it divides up, we need to match all of it). 3090 */ 3091 for (t = sep, tt = *s; *t && *tt && *t == *tt; t++, tt++); 3092 if (!*t) 3093 return (i > 0); 3094 *s += MB_METACHARLEN(*s); 3095 } 3096 return -1; 3097} 3098 3099/**/ 3100char * 3101findword(char **s, char *sep) 3102{ 3103 char *r, *t; 3104 int sl; 3105 3106 if (!**s) 3107 return NULL; 3108 3109 if (sep) { 3110 sl = strlen(sep); 3111 r = *s; 3112 while (! findsep(s, sep, 0)) { 3113 r = *s += sl; 3114 } 3115 return r; 3116 } 3117 MB_METACHARINIT(); 3118 for (t = *s; *t; t += sl) { 3119 convchar_t c; 3120 sl = MB_METACHARLENCONV(t, &c); 3121 if (!WC_ZISTYPE(c, ISEP)) 3122 break; 3123 } 3124 *s = t; 3125 (void)findsep(s, sep, 0); 3126 return t; 3127} 3128 3129/**/ 3130int 3131wordcount(char *s, char *sep, int mul) 3132{ 3133 int r, sl, c; 3134 3135 if (sep) { 3136 r = 1; 3137 sl = strlen(sep); 3138 for (; (c = findsep(&s, sep, 0)) >= 0; s += sl) 3139 if ((c || mul) && (sl || *(s + sl))) 3140 r++; 3141 } else { 3142 char *t = s; 3143 3144 r = 0; 3145 if (mul <= 0) 3146 skipwsep(&s); 3147 if ((*s && itype_end(s, ISEP, 1) != s) || 3148 (mul < 0 && t != s)) 3149 r++; 3150 for (; *s; r++) { 3151 char *ie = itype_end(s, ISEP, 1); 3152 if (ie != s) { 3153 s = ie; 3154 if (mul <= 0) 3155 skipwsep(&s); 3156 } 3157 (void)findsep(&s, NULL, 0); 3158 t = s; 3159 if (mul <= 0) 3160 skipwsep(&s); 3161 } 3162 if (mul < 0 && t != s) 3163 r++; 3164 } 3165 return r; 3166} 3167 3168/**/ 3169mod_export char * 3170sepjoin(char **s, char *sep, int heap) 3171{ 3172 char *r, *p, **t; 3173 int l, sl; 3174 char sepbuf[2]; 3175 3176 if (!*s) 3177 return heap ? "" : ztrdup(""); 3178 if (!sep) { 3179 /* optimise common case that ifs[0] is space */ 3180 if (ifs && *ifs != ' ') { 3181 MB_METACHARINIT(); 3182 sep = dupstrpfx(ifs, MB_METACHARLEN(ifs)); 3183 } else { 3184 p = sep = sepbuf; 3185 *p++ = ' '; 3186 *p = '\0'; 3187 } 3188 } 3189 sl = strlen(sep); 3190 for (t = s, l = 1 - sl; *t; l += strlen(*t) + sl, t++); 3191 r = p = (heap ? (char *) hcalloc(l) : (char *) zshcalloc(l)); 3192 t = s; 3193 while (*t) { 3194 strucpy(&p, *t); 3195 if (*++t) 3196 strucpy(&p, sep); 3197 } 3198 *p = '\0'; 3199 return r; 3200} 3201 3202/**/ 3203char ** 3204sepsplit(char *s, char *sep, int allownull, int heap) 3205{ 3206 int n, sl; 3207 char *t, *tt, **r, **p; 3208 3209 /* Null string? Treat as empty string. */ 3210 if (s[0] == Nularg && !s[1]) 3211 s++; 3212 3213 if (!sep) 3214 return spacesplit(s, allownull, heap, 0); 3215 3216 sl = strlen(sep); 3217 n = wordcount(s, sep, 1); 3218 r = p = (heap ? (char **) hcalloc((n + 1) * sizeof(char *)) : 3219 (char **) zshcalloc((n + 1) * sizeof(char *))); 3220 3221 for (t = s; n--;) { 3222 tt = t; 3223 (void)findsep(&t, sep, 0); 3224 *p = (heap ? (char *) hcalloc(t - tt + 1) : 3225 (char *) zshcalloc(t - tt + 1)); 3226 strncpy(*p, tt, t - tt); 3227 (*p)[t - tt] = '\0'; 3228 p++; 3229 t += sl; 3230 } 3231 *p = NULL; 3232 3233 return r; 3234} 3235 3236/* Get the definition of a shell function */ 3237 3238/**/ 3239mod_export Shfunc 3240getshfunc(char *nam) 3241{ 3242 return (Shfunc) shfunctab->getnode(shfunctab, nam); 3243} 3244 3245/* 3246 * Call the function func to substitute string orig by setting 3247 * the parameter reply. 3248 * Return the array from reply, or NULL if the function returned 3249 * non-zero status. 3250 * The returned value comes directly from the parameter and 3251 * so should be used before there is any chance of that 3252 * being changed or unset. 3253 * If arg1 is not NULL, it is used as an initial argument to 3254 * the function, with the original string as the second argument. 3255 */ 3256 3257/**/ 3258char ** 3259subst_string_by_func(Shfunc func, char *arg1, char *orig) 3260{ 3261 int osc = sfcontext, osm = stopmsg, old_incompfunc = incompfunc; 3262 LinkList l = newlinklist(); 3263 char **ret; 3264 3265 addlinknode(l, func->node.nam); 3266 if (arg1) 3267 addlinknode(l, arg1); 3268 addlinknode(l, orig); 3269 sfcontext = SFC_SUBST; 3270 incompfunc = 0; 3271 3272 if (doshfunc(func, l, 1)) 3273 ret = NULL; 3274 else 3275 ret = getaparam("reply"); 3276 3277 sfcontext = osc; 3278 stopmsg = osm; 3279 incompfunc = old_incompfunc; 3280 return ret; 3281} 3282 3283/** 3284 * Front end to subst_string_by_func to use hook-like logic. 3285 * name can refer to a function, and name + "_hook" can refer 3286 * to an array containing a list of functions. The functions 3287 * are tried in order until one returns success. 3288 */ 3289/**/ 3290char ** 3291subst_string_by_hook(char *name, char *arg1, char *orig) 3292{ 3293 Shfunc func; 3294 char **ret = NULL; 3295 3296 if ((func = getshfunc(name))) { 3297 ret = subst_string_by_func(func, arg1, orig); 3298 } 3299 3300 if (!ret) { 3301 char **arrptr; 3302 int namlen = strlen(name); 3303 VARARR(char, arrnam, namlen + HOOK_SUFFIX_LEN); 3304 memcpy(arrnam, name, namlen); 3305 memcpy(arrnam + namlen, HOOK_SUFFIX, HOOK_SUFFIX_LEN); 3306 3307 if ((arrptr = getaparam(arrnam))) { 3308 /* Guard against internal modification of the array */ 3309 arrptr = arrdup(arrptr); 3310 for (; *arrptr; arrptr++) { 3311 if ((func = getshfunc(*arrptr))) { 3312 ret = subst_string_by_func(func, arg1, orig); 3313 if (ret) 3314 break; 3315 } 3316 } 3317 } 3318 } 3319 3320 return ret; 3321} 3322 3323/**/ 3324mod_export char ** 3325mkarray(char *s) 3326{ 3327 char **t = (char **) zalloc((s) ? (2 * sizeof s) : (sizeof s)); 3328 3329 if ((*t = s)) 3330 t[1] = NULL; 3331 return t; 3332} 3333 3334/**/ 3335mod_export void 3336zbeep(void) 3337{ 3338 char *vb; 3339 queue_signals(); 3340 if ((vb = getsparam("ZBEEP"))) { 3341 int len; 3342 vb = getkeystring(vb, &len, GETKEYS_BINDKEY, NULL); 3343 write_loop(SHTTY, vb, len); 3344 } else if (isset(BEEP)) 3345 write_loop(SHTTY, "\07", 1); 3346 unqueue_signals(); 3347} 3348 3349/**/ 3350mod_export void 3351freearray(char **s) 3352{ 3353 char **t = s; 3354 3355 DPUTS(!s, "freearray() with zero argument"); 3356 3357 while (*s) 3358 zsfree(*s++); 3359 free(t); 3360} 3361 3362/**/ 3363int 3364equalsplit(char *s, char **t) 3365{ 3366 for (; *s && *s != '='; s++); 3367 if (*s == '=') { 3368 *s++ = '\0'; 3369 *t = s; 3370 return 1; 3371 } 3372 return 0; 3373} 3374 3375static int specialcomma; 3376 3377/* the ztypes table */ 3378 3379/**/ 3380mod_export short int typtab[256]; 3381 3382/* initialize the ztypes table */ 3383 3384/**/ 3385void 3386inittyptab(void) 3387{ 3388 int t0; 3389 char *s; 3390 3391 for (t0 = 0; t0 != 256; t0++) 3392 typtab[t0] = 0; 3393 for (t0 = 0; t0 != 32; t0++) 3394 typtab[t0] = typtab[t0 + 128] = ICNTRL; 3395 typtab[127] = ICNTRL; 3396 for (t0 = '0'; t0 <= '9'; t0++) 3397 typtab[t0] = IDIGIT | IALNUM | IWORD | IIDENT | IUSER; 3398 for (t0 = 'a'; t0 <= 'z'; t0++) 3399 typtab[t0] = typtab[t0 - 'a' + 'A'] = IALPHA | IALNUM | IIDENT | IUSER | IWORD; 3400#ifndef MULTIBYTE_SUPPORT 3401 /* 3402 * This really doesn't seem to me the right thing to do when 3403 * we have multibyte character support... it was a hack to assume 3404 * eight bit characters `worked' for some values of work before 3405 * we could test for them properly. I'm not 100% convinced 3406 * having IIDENT here is a good idea at all, but this code 3407 * should disappear into history... 3408 */ 3409 for (t0 = 0240; t0 != 0400; t0++) 3410 typtab[t0] = IALPHA | IALNUM | IIDENT | IUSER | IWORD; 3411#endif 3412 /* typtab['.'] |= IIDENT; */ /* Allow '.' in variable names - broken */ 3413 typtab['_'] = IIDENT | IUSER; 3414 typtab['-'] = typtab['.'] = IUSER; 3415 typtab[' '] |= IBLANK | INBLANK; 3416 typtab['\t'] |= IBLANK | INBLANK; 3417 typtab['\n'] |= INBLANK; 3418 typtab['\0'] |= IMETA; 3419 typtab[STOUC(Meta) ] |= IMETA; 3420 typtab[STOUC(Marker)] |= IMETA; 3421 for (t0 = (int)STOUC(Pound); t0 <= (int)STOUC(Comma); t0++) 3422 typtab[t0] |= ITOK | IMETA; 3423 for (t0 = (int)STOUC(Snull); t0 <= (int)STOUC(Nularg); t0++) 3424 typtab[t0] |= ITOK | IMETA | INULL; 3425 for (s = ifs ? ifs : EMULATION(EMULATE_KSH|EMULATE_SH) ? 3426 ztrdup(DEFAULT_IFS_SH) : ztrdup(DEFAULT_IFS); *s; s++) { 3427 int c = STOUC(*s == Meta ? *++s ^ 32 : *s); 3428#ifdef MULTIBYTE_SUPPORT 3429 if (!isascii(c)) { 3430 /* see comment for wordchars below */ 3431 continue; 3432 } 3433#endif 3434 if (inblank(c)) { 3435 if (s[1] == c) 3436 s++; 3437 else 3438 typtab[c] |= IWSEP; 3439 } 3440 typtab[c] |= ISEP; 3441 } 3442 for (s = wordchars ? wordchars : DEFAULT_WORDCHARS; *s; s++) { 3443 int c = STOUC(*s == Meta ? *++s ^ 32 : *s); 3444#ifdef MULTIBYTE_SUPPORT 3445 if (!isascii(c)) { 3446 /* 3447 * If we have support for multibyte characters, we don't 3448 * handle non-ASCII characters here; instead, we turn 3449 * wordchars into a wide character array. 3450 * (We may actually have a single-byte 8-bit character set, 3451 * but it works the same way.) 3452 */ 3453 continue; 3454 } 3455#endif 3456 typtab[c] |= IWORD; 3457 } 3458#ifdef MULTIBYTE_SUPPORT 3459 set_widearray(wordchars, &wordchars_wide); 3460 set_widearray(ifs ? ifs : EMULATION(EMULATE_KSH|EMULATE_SH) ? 3461 ztrdup(DEFAULT_IFS_SH) : ztrdup(DEFAULT_IFS), &ifs_wide); 3462#endif 3463 for (s = SPECCHARS; *s; s++) 3464 typtab[STOUC(*s)] |= ISPECIAL; 3465 if (specialcomma) 3466 typtab[STOUC(',')] |= ISPECIAL; 3467 if (isset(BANGHIST) && bangchar && interact && isset(SHINSTDIN)) 3468 typtab[bangchar] |= ISPECIAL; 3469} 3470 3471/**/ 3472mod_export void 3473makecommaspecial(int yesno) 3474{ 3475 if ((specialcomma = yesno) != 0) 3476 typtab[STOUC(',')] |= ISPECIAL; 3477 else 3478 typtab[STOUC(',')] &= ~ISPECIAL; 3479} 3480 3481 3482/**/ 3483#ifdef MULTIBYTE_SUPPORT 3484/* A wide-character version of the iblank() macro. */ 3485/**/ 3486mod_export int 3487wcsiblank(wint_t wc) 3488{ 3489 if (iswspace(wc) && wc != L'\n') 3490 return 1; 3491 return 0; 3492} 3493 3494/* 3495 * zistype macro extended to support wide characters. 3496 * Works for IIDENT, IWORD, IALNUM, ISEP. 3497 * We don't need this for IWSEP because that only applies to 3498 * a fixed set of ASCII characters. 3499 * Note here that use of multibyte mode is not tested: 3500 * that's because for ZLE this is unconditional, 3501 * not dependent on the option. The caller must decide. 3502 */ 3503 3504/**/ 3505mod_export int 3506wcsitype(wchar_t c, int itype) 3507{ 3508 int len; 3509 mbstate_t mbs; 3510 VARARR(char, outstr, MB_CUR_MAX); 3511 3512 if (!isset(MULTIBYTE)) 3513 return zistype(c, itype); 3514 3515 /* 3516 * Strategy: the shell requires that the multibyte representation 3517 * be an extension of ASCII. So see if converting the character 3518 * produces an ASCII character. If it does, use zistype on that. 3519 * If it doesn't, use iswalnum on the original character. 3520 * If that fails, resort to the appropriate wide character array. 3521 */ 3522 memset(&mbs, 0, sizeof(mbs)); 3523 len = wcrtomb(outstr, c, &mbs); 3524 3525 if (len == 0) { 3526 /* NULL is special */ 3527 return zistype(0, itype); 3528 } else if (len == 1 && isascii(outstr[0])) { 3529 return zistype(outstr[0], itype); 3530 } else { 3531 switch (itype) { 3532 case IIDENT: 3533 if (!isset(POSIXIDENTIFIERS)) 3534 return 0; 3535 return iswalnum(c); 3536 3537 case IWORD: 3538 if (iswalnum(c)) 3539 return 1; 3540 /* 3541 * If we are handling combining characters, any punctuation 3542 * characters with zero width needs to be considered part of 3543 * a word. If we are not handling combining characters then 3544 * logically they are still part of the word, even if they 3545 * don't get displayed properly, so always do this. 3546 */ 3547 if (IS_COMBINING(c)) 3548 return 1; 3549 return !!wmemchr(wordchars_wide.chars, c, wordchars_wide.len); 3550 3551 case ISEP: 3552 return !!wmemchr(ifs_wide.chars, c, ifs_wide.len); 3553 3554 default: 3555 return iswalnum(c); 3556 } 3557 } 3558} 3559 3560/**/ 3561#endif 3562 3563 3564/* 3565 * Find the end of a set of characters in the set specified by itype; 3566 * one of IALNUM, IIDENT, IWORD or IUSER. For non-ASCII characters, we assume 3567 * alphanumerics are part of the set, with the exception that 3568 * identifiers are not treated that way if POSIXIDENTIFIERS is set. 3569 * 3570 * See notes above for identifiers. 3571 * Returns the same pointer as passed if not on an identifier character. 3572 * If "once" is set, just test the first character, i.e. (outptr != 3573 * inptr) tests whether the first character is valid in an identifier. 3574 * 3575 * Currently this is only called with itype IIDENT, IUSER or ISEP. 3576 */ 3577 3578/**/ 3579mod_export char * 3580itype_end(const char *ptr, int itype, int once) 3581{ 3582#ifdef MULTIBYTE_SUPPORT 3583 if (isset(MULTIBYTE) && 3584 (itype != IIDENT || !isset(POSIXIDENTIFIERS))) { 3585 mb_metacharinit(); 3586 while (*ptr) { 3587 wint_t wc; 3588 int len = mb_metacharlenconv(ptr, &wc); 3589 3590 if (!len) 3591 break; 3592 3593 if (wc == WEOF) { 3594 /* invalid, treat as single character */ 3595 int chr = STOUC(*ptr == Meta ? ptr[1] ^ 32 : *ptr); 3596 /* in this case non-ASCII characters can't match */ 3597 if (chr > 127 || !zistype(chr,itype)) 3598 break; 3599 } else if (len == 1 && isascii(*ptr)) { 3600 /* ASCII: can't be metafied, use standard test */ 3601 if (!zistype(*ptr,itype)) 3602 break; 3603 } else { 3604 /* 3605 * Valid non-ASCII character. 3606 */ 3607 switch (itype) { 3608 case IWORD: 3609 if (!iswalnum(wc) && 3610 !wmemchr(wordchars_wide.chars, wc, 3611 wordchars_wide.len)) 3612 return (char *)ptr; 3613 break; 3614 3615 case ISEP: 3616 if (!wmemchr(ifs_wide.chars, wc, ifs_wide.len)) 3617 return (char *)ptr; 3618 break; 3619 3620 default: 3621 if (!iswalnum(wc)) 3622 return (char *)ptr; 3623 } 3624 } 3625 ptr += len; 3626 3627 if (once) 3628 break; 3629 } 3630 } else 3631#endif 3632 for (;;) { 3633 int chr = STOUC(*ptr == Meta ? ptr[1] ^ 32 : *ptr); 3634 if (!zistype(chr,itype)) 3635 break; 3636 ptr += (*ptr == Meta) ? 2 : 1; 3637 3638 if (once) 3639 break; 3640 } 3641 3642 /* 3643 * Nasty. The first argument is const char * because we 3644 * don't modify it here. However, we really want to pass 3645 * back the same type as was passed down, to allow idioms like 3646 * p = itype_end(p, IIDENT, 0); 3647 * So returning a const char * isn't really the right thing to do. 3648 * Without having two different functions the following seems 3649 * to be the best we can do. 3650 */ 3651 return (char *)ptr; 3652} 3653 3654/**/ 3655mod_export char ** 3656arrdup(char **s) 3657{ 3658 char **x, **y; 3659 3660 y = x = (char **) zhalloc(sizeof(char *) * (arrlen(s) + 1)); 3661 3662 while ((*x++ = dupstring(*s++))); 3663 3664 return y; 3665} 3666 3667/**/ 3668mod_export char ** 3669zarrdup(char **s) 3670{ 3671 char **x, **y; 3672 3673 y = x = (char **) zalloc(sizeof(char *) * (arrlen(s) + 1)); 3674 3675 while ((*x++ = ztrdup(*s++))); 3676 3677 return y; 3678} 3679 3680/**/ 3681#ifdef MULTIBYTE_SUPPORT 3682/**/ 3683mod_export wchar_t ** 3684wcs_zarrdup(wchar_t **s) 3685{ 3686 wchar_t **x, **y; 3687 3688 y = x = (wchar_t **) zalloc(sizeof(wchar_t *) * (arrlen((char **)s) + 1)); 3689 3690 while ((*x++ = wcs_ztrdup(*s++))); 3691 3692 return y; 3693} 3694/**/ 3695#endif /* MULTIBYTE_SUPPORT */ 3696 3697/**/ 3698static char * 3699spname(char *oldname) 3700{ 3701 char *p, spnameguess[PATH_MAX + 1], spnamebest[PATH_MAX + 1]; 3702 static char newname[PATH_MAX + 1]; 3703 char *new = newname, *old = oldname; 3704 int bestdist = 0, thisdist, thresh, maxthresh = 0; 3705 3706 /* This loop corrects each directory component of the path, stopping * 3707 * when any correction distance would exceed the distance threshold. * 3708 * NULL is returned only if the first component cannot be corrected; * 3709 * otherwise a copy of oldname with a corrected prefix is returned. * 3710 * Rationale for this, if there ever was any, has been forgotten. */ 3711 for (;;) { 3712 while (*old == '/') { 3713 if ((new - newname) >= (sizeof(newname)-1)) 3714 return NULL; 3715 *new++ = *old++; 3716 } 3717 *new = '\0'; 3718 if (*old == '\0') 3719 return newname; 3720 p = spnameguess; 3721 for (; *old != '/' && *old != '\0'; old++) 3722 if (p < spnameguess + PATH_MAX) 3723 *p++ = *old; 3724 *p = '\0'; 3725 /* Every component is allowed a single distance 2 correction or two * 3726 * distance 1 corrections. Longer ones get additional corrections. */ 3727 thresh = (int)(p - spnameguess) / 4 + 1; 3728 if (thresh < 3) 3729 thresh = 3; 3730 else if (thresh > 100) 3731 thresh = 100; 3732 if ((thisdist = mindist(newname, spnameguess, spnamebest)) >= thresh) { 3733 /* The next test is always true, except for the first path * 3734 * component. We could initialize bestdist to some large * 3735 * constant instead, and then compare to that constant here, * 3736 * because an invariant is that we've never exceeded the * 3737 * threshold for any component so far; but I think that looks * 3738 * odd to the human reader, and we may make use of the total * 3739 * distance for all corrections at some point in the future. */ 3740 if (bestdist < maxthresh) { 3741 strcpy(new, spnameguess); 3742 strcat(new, old); 3743 return newname; 3744 } else 3745 return NULL; 3746 } else { 3747 maxthresh = bestdist + thresh; 3748 bestdist += thisdist; 3749 } 3750 for (p = spnamebest; (*new = *p++);) 3751 new++; 3752 } 3753} 3754 3755/**/ 3756static int 3757mindist(char *dir, char *mindistguess, char *mindistbest) 3758{ 3759 int mindistd, nd; 3760 DIR *dd; 3761 char *fn; 3762 char *buf; 3763 3764 if (dir[0] == '\0') 3765 dir = "."; 3766 mindistd = 100; 3767 3768 buf = zalloc(strlen(dir) + strlen(mindistguess) + 2); 3769 sprintf(buf, "%s/%s", dir, mindistguess); 3770 3771 if (access(unmeta(buf), F_OK) == 0) { 3772 strcpy(mindistbest, mindistguess); 3773 free(buf); 3774 return 0; 3775 } 3776 free(buf); 3777 3778 if (!(dd = opendir(unmeta(dir)))) 3779 return mindistd; 3780 while ((fn = zreaddir(dd, 0))) { 3781 nd = spdist(fn, mindistguess, 3782 (int)strlen(mindistguess) / 4 + 1); 3783 if (nd <= mindistd) { 3784 strcpy(mindistbest, fn); 3785 mindistd = nd; 3786 if (mindistd == 0) 3787 break; 3788 } 3789 } 3790 closedir(dd); 3791 return mindistd; 3792} 3793 3794/**/ 3795static int 3796spdist(char *s, char *t, int thresh) 3797{ 3798 /* TODO: Correction for non-ASCII and multibyte-input keyboards. */ 3799 char *p, *q; 3800 const char qwertykeymap[] = 3801 "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ 3802\t1234567890-=\t\ 3803\tqwertyuiop[]\t\ 3804\tasdfghjkl;'\n\t\ 3805\tzxcvbnm,./\t\t\t\ 3806\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ 3807\t!@#$%^&*()_+\t\ 3808\tQWERTYUIOP{}\t\ 3809\tASDFGHJKL:\"\n\t\ 3810\tZXCVBNM<>?\n\n\t\ 3811\n\n\n\n\n\n\n\n\n\n\n\n\n\n"; 3812 const char dvorakkeymap[] = 3813 "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ 3814\t1234567890[]\t\ 3815\t',.pyfgcrl/=\t\ 3816\taoeuidhtns-\n\t\ 3817\t;qjkxbmwvz\t\t\t\ 3818\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ 3819\t!@#$%^&*(){}\t\ 3820\t\"<>PYFGCRL?+\t\ 3821\tAOEUIDHTNS_\n\t\ 3822\t:QJKXBMWVZ\n\n\t\ 3823\n\n\n\n\n\n\n\n\n\n\n\n\n\n"; 3824 const char *keymap; 3825 if ( isset( DVORAK ) ) 3826 keymap = dvorakkeymap; 3827 else 3828 keymap = qwertykeymap; 3829 3830 if (!strcmp(s, t)) 3831 return 0; 3832 /* any number of upper/lower mistakes allowed (dist = 1) */ 3833 for (p = s, q = t; *p && tulower(*p) == tulower(*q); p++, q++); 3834 if (!*p && !*q) 3835 return 1; 3836 if (!thresh) 3837 return 200; 3838 for (p = s, q = t; *p && *q; p++, q++) 3839 if (*p == *q) 3840 continue; /* don't consider "aa" transposed, ash */ 3841 else if (p[1] == q[0] && q[1] == p[0]) /* transpositions */ 3842 return spdist(p + 2, q + 2, thresh - 1) + 1; 3843 else if (p[1] == q[0]) /* missing letter */ 3844 return spdist(p + 1, q + 0, thresh - 1) + 2; 3845 else if (p[0] == q[1]) /* missing letter */ 3846 return spdist(p + 0, q + 1, thresh - 1) + 2; 3847 else if (*p != *q) 3848 break; 3849 if ((!*p && strlen(q) == 1) || (!*q && strlen(p) == 1)) 3850 return 2; 3851 for (p = s, q = t; *p && *q; p++, q++) 3852 if (p[0] != q[0] && p[1] == q[1]) { 3853 int t0; 3854 char *z; 3855 3856 /* mistyped letter */ 3857 3858 if (!(z = strchr(keymap, p[0])) || *z == '\n' || *z == '\t') 3859 return spdist(p + 1, q + 1, thresh - 1) + 1; 3860 t0 = z - keymap; 3861 if (*q == keymap[t0 - 15] || *q == keymap[t0 - 14] || 3862 *q == keymap[t0 - 13] || 3863 *q == keymap[t0 - 1] || *q == keymap[t0 + 1] || 3864 *q == keymap[t0 + 13] || *q == keymap[t0 + 14] || 3865 *q == keymap[t0 + 15]) 3866 return spdist(p + 1, q + 1, thresh - 1) + 2; 3867 return 200; 3868 } else if (*p != *q) 3869 break; 3870 return 200; 3871} 3872 3873/* set cbreak mode, or the equivalent */ 3874 3875/**/ 3876void 3877setcbreak(void) 3878{ 3879 struct ttyinfo ti; 3880 3881 ti = shttyinfo; 3882#ifdef HAS_TIO 3883 ti.tio.c_lflag &= ~ICANON; 3884 ti.tio.c_cc[VMIN] = 1; 3885 ti.tio.c_cc[VTIME] = 0; 3886#else 3887 ti.sgttyb.sg_flags |= CBREAK; 3888#endif 3889 settyinfo(&ti); 3890} 3891 3892/* give the tty to some process */ 3893 3894/**/ 3895mod_export void 3896attachtty(pid_t pgrp) 3897{ 3898 static int ep = 0; 3899 3900 if (jobbing && interact) { 3901#ifdef HAVE_TCSETPGRP 3902 if (SHTTY != -1 && tcsetpgrp(SHTTY, pgrp) == -1 && !ep) 3903#else 3904# if ardent 3905 if (SHTTY != -1 && setpgrp() == -1 && !ep) 3906# else 3907 int arg = pgrp; 3908 3909 if (SHTTY != -1 && ioctl(SHTTY, TIOCSPGRP, &arg) == -1 && !ep) 3910# endif 3911#endif 3912 { 3913 if (pgrp != mypgrp && kill(-pgrp, 0) == -1) 3914 attachtty(mypgrp); 3915 else { 3916 if (errno != ENOTTY) 3917 { 3918 zwarn("can't set tty pgrp: %e", errno); 3919 fflush(stderr); 3920 } 3921 opts[MONITOR] = 0; 3922 ep = 1; 3923 } 3924 } 3925 } 3926} 3927 3928/* get the process group associated with the tty */ 3929 3930/**/ 3931pid_t 3932gettygrp(void) 3933{ 3934 pid_t arg; 3935 3936 if (SHTTY == -1) 3937 return -1; 3938 3939#ifdef HAVE_TCSETPGRP 3940 arg = tcgetpgrp(SHTTY); 3941#else 3942 ioctl(SHTTY, TIOCGPGRP, &arg); 3943#endif 3944 3945 return arg; 3946} 3947 3948 3949/* Escape tokens and null characters. Buf is the string which should be * 3950 * escaped. len is the length of the string. If len is -1, buf should be * 3951 * null terminated. If len is non-negative and the third parameter is not * 3952 * META_DUP, buf should point to an at least len+1 long memory area. The * 3953 * return value points to the quoted string. If the given string does not * 3954 * contain any special character which should be quoted and the third * 3955 * parameter is not META_(HEAP|)DUP, buf is returned unchanged (a * 3956 * terminating null character is appended to buf if necessary). Otherwise * 3957 * the third `heap' argument determines the method used to allocate space * 3958 * for the result. It can have the following values: * 3959 * META_REALLOC: use zrealloc on buf * 3960 * META_HREALLOC: use hrealloc on buf * 3961 * META_USEHEAP: get memory from the heap. This leaves buf unchanged. * 3962 * META_NOALLOC: buf points to a memory area which is long enough to hold * 3963 * the quoted form, just quote it and return buf. * 3964 * META_STATIC: store the quoted string in a static area. The original * 3965 * string should be at most PATH_MAX long. * 3966 * META_ALLOC: allocate memory for the new string with zalloc(). * 3967 * META_DUP: leave buf unchanged and allocate space for the return * 3968 * value even if buf does not contains special characters * 3969 * META_HEAPDUP: same as META_DUP, but uses the heap */ 3970 3971/**/ 3972mod_export char * 3973metafy(char *buf, int len, int heap) 3974{ 3975 int meta = 0; 3976 char *t, *p, *e; 3977 static char mbuf[PATH_MAX*2+1]; 3978 3979 if (len == -1) { 3980 for (e = buf, len = 0; *e; len++) 3981 if (imeta(*e++)) 3982 meta++; 3983 } else 3984 for (e = buf; e < buf + len;) 3985 if (imeta(*e++)) 3986 meta++; 3987 3988 if (meta || heap == META_DUP || heap == META_HEAPDUP) { 3989 switch (heap) { 3990 case META_REALLOC: 3991 buf = zrealloc(buf, len + meta + 1); 3992 break; 3993 case META_HREALLOC: 3994 buf = hrealloc(buf, len, len + meta + 1); 3995 break; 3996 case META_ALLOC: 3997 case META_DUP: 3998 buf = memcpy(zalloc(len + meta + 1), buf, len); 3999 break; 4000 case META_USEHEAP: 4001 case META_HEAPDUP: 4002 buf = memcpy(zhalloc(len + meta + 1), buf, len); 4003 break; 4004 case META_STATIC: 4005#ifdef DEBUG 4006 if (len > PATH_MAX) { 4007 fprintf(stderr, "BUG: len = %d > PATH_MAX in metafy\n", len); 4008 fflush(stderr); 4009 } 4010#endif 4011 buf = memcpy(mbuf, buf, len); 4012 break; 4013#ifdef DEBUG 4014 case META_NOALLOC: 4015 break; 4016 default: 4017 fprintf(stderr, "BUG: metafy called with invalid heap value\n"); 4018 fflush(stderr); 4019 break; 4020#endif 4021 } 4022 p = buf + len; 4023 e = t = buf + len + meta; 4024 while (meta) { 4025 if (imeta(*--t = *--p)) { 4026 *t-- ^= 32; 4027 *t = Meta; 4028 meta--; 4029 } 4030 } 4031 } 4032 *e = '\0'; 4033 return buf; 4034} 4035 4036 4037/* 4038 * Duplicate a string, metafying it as we go. 4039 * 4040 * Typically, this is used only for strings imported from outside 4041 * zsh, as strings internally are either already metafied or passed 4042 * around with an associated length. 4043 */ 4044/**/ 4045mod_export char * 4046ztrdup_metafy(const char *s) 4047{ 4048 /* To mimic ztrdup() behaviour */ 4049 if (!s) 4050 return NULL; 4051 /* 4052 * metafy() does lots of different things, so the pointer 4053 * isn't const. Using it with META_DUP should be safe. 4054 */ 4055 return metafy((char *)s, -1, META_DUP); 4056} 4057 4058 4059/* 4060 * Take a null-terminated, metafied string in s into a literal 4061 * representation by converting in place. The length is in *len 4062 * len is non-NULL; if len is NULL, you don't know the length of 4063 * the final string, but if it's to be supplied to some system 4064 * routine that always uses NULL termination, such as a filename 4065 * interpreter, that doesn't matter. Note the NULL termination 4066 * is always copied for purposes of that kind. 4067 */ 4068 4069/**/ 4070mod_export char * 4071unmetafy(char *s, int *len) 4072{ 4073 char *p, *t; 4074 4075 for (p = s; *p && *p != Meta; p++); 4076 for (t = p; (*t = *p++);) 4077 if (*t++ == Meta) 4078 t[-1] = *p++ ^ 32; 4079 if (len) 4080 *len = t - s; 4081 return s; 4082} 4083 4084/* Return the character length of a metafied substring, given the * 4085 * unmetafied substring length. */ 4086 4087/**/ 4088mod_export int 4089metalen(const char *s, int len) 4090{ 4091 int mlen = len; 4092 4093 while (len--) { 4094 if (*s++ == Meta) { 4095 mlen++; 4096 s++; 4097 } 4098 } 4099 return mlen; 4100} 4101 4102/* 4103 * This function converts a zsh internal string to a form which can be 4104 * passed to a system call as a filename. The result is stored in a 4105 * single static area, sized to fit. If there is no Meta character 4106 * the original string is returned. 4107 */ 4108 4109/**/ 4110mod_export char * 4111unmeta(const char *file_name) 4112{ 4113 static char *fn; 4114 static int sz; 4115 char *p; 4116 const char *t; 4117 int newsz, meta; 4118 4119 meta = 0; 4120 for (t = file_name; *t; t++) { 4121 if (*t == Meta) 4122 meta = 1; 4123 } 4124 if (!meta) { 4125 /* 4126 * don't need allocation... free if it's long, see below 4127 */ 4128 if (sz > 4 * PATH_MAX) { 4129 zfree(fn, sz); 4130 fn = NULL; 4131 sz = 0; 4132 } 4133 return (char *) file_name; 4134 } 4135 4136 newsz = (t - file_name) + 1; 4137 /* 4138 * Optimisation: don't resize if we don't have to. 4139 * We need a new allocation if 4140 * - nothing was allocated before 4141 * - the new string is larger than the old one 4142 * - the old string was larger than an arbitrary limit but the 4143 * new string isn't so that we free up significant space by resizing. 4144 */ 4145 if (!fn || newsz > sz || (sz > 4 * PATH_MAX && newsz <= 4 * PATH_MAX)) 4146 { 4147 if (fn) 4148 zfree(fn, sz); 4149 sz = newsz; 4150 fn = (char *)zalloc(sz); 4151 if (!fn) { 4152 sz = 0; 4153 /* 4154 * will quite likely crash in the caller anyway... 4155 */ 4156 return NULL; 4157 } 4158 } 4159 4160 for (t = file_name, p = fn; *t; p++) 4161 if ((*p = *t++) == Meta) 4162 *p = *t++ ^ 32; 4163 *p = '\0'; 4164 return fn; 4165} 4166 4167/* 4168 * Unmetafy and compare two strings, comparing unsigned character values. 4169 * "a\0" sorts after "a". 4170 * 4171 * Currently this is only used in hash table sorting, where the 4172 * keys are names of hash nodes and where we don't use strcoll(); 4173 * it's not clear if that's right but it does guarantee the ordering 4174 * of shell structures on output. 4175 * 4176 * As we don't use strcoll(), it seems overkill to convert multibyte 4177 * characters to wide characters for comparison every time. In the case 4178 * of UTF-8, Unicode ordering is preserved when sorted raw, and for 4179 * other character sets we rely on an extension of ASCII so the result, 4180 * while it may not be correct, is at least rational. 4181 */ 4182 4183/**/ 4184int 4185ztrcmp(char const *s1, char const *s2) 4186{ 4187 int c1, c2; 4188 4189 while(*s1 && *s1 == *s2) { 4190 s1++; 4191 s2++; 4192 } 4193 4194 if(!(c1 = *s1)) 4195 c1 = -1; 4196 else if(c1 == STOUC(Meta)) 4197 c1 = *++s1 ^ 32; 4198 if(!(c2 = *s2)) 4199 c2 = -1; 4200 else if(c2 == STOUC(Meta)) 4201 c2 = *++s2 ^ 32; 4202 4203 if(c1 == c2) 4204 return 0; 4205 else if(c1 < c2) 4206 return -1; 4207 else 4208 return 1; 4209} 4210 4211/* Return the unmetafied length of a metafied string. */ 4212 4213/**/ 4214mod_export int 4215ztrlen(char const *s) 4216{ 4217 int l; 4218 4219 for (l = 0; *s; l++) { 4220 if (*s++ == Meta) { 4221#ifdef DEBUG 4222 if (! *s) 4223 fprintf(stderr, "BUG: unexpected end of string in ztrlen()\n"); 4224 else 4225#endif 4226 s++; 4227 } 4228 } 4229 return l; 4230} 4231 4232/* Subtract two pointers in a metafied string. */ 4233 4234/**/ 4235mod_export int 4236ztrsub(char const *t, char const *s) 4237{ 4238 int l = t - s; 4239 4240 while (s != t) { 4241 if (*s++ == Meta) { 4242#ifdef DEBUG 4243 if (! *s || s == t) 4244 fprintf(stderr, "BUG: substring ends in the middle of a metachar in ztrsub()\n"); 4245 else 4246#endif 4247 s++; 4248 l--; 4249 } 4250 } 4251 return l; 4252} 4253 4254/**/ 4255mod_export char * 4256zreaddir(DIR *dir, int ignoredots) 4257{ 4258 struct dirent *de; 4259 4260 do { 4261 de = readdir(dir); 4262 if(!de) 4263 return NULL; 4264 } while(ignoredots && de->d_name[0] == '.' && 4265 (!de->d_name[1] || (de->d_name[1] == '.' && !de->d_name[2]))); 4266 4267 return metafy(de->d_name, -1, META_STATIC); 4268} 4269 4270/* Unmetafy and output a string. Tokens are skipped. */ 4271 4272/**/ 4273mod_export int 4274zputs(char const *s, FILE *stream) 4275{ 4276 int c; 4277 4278 while (*s) { 4279 if (*s == Meta) 4280 c = *++s ^ 32; 4281 else if(itok(*s)) { 4282 s++; 4283 continue; 4284 } else 4285 c = *s; 4286 s++; 4287 if (fputc(c, stream) < 0) 4288 return EOF; 4289 } 4290 return 0; 4291} 4292 4293#ifndef MULTIBYTE_SUPPORT 4294/* Create a visibly-represented duplicate of a string. */ 4295 4296/**/ 4297mod_export char * 4298nicedup(char const *s, int heap) 4299{ 4300 int c, len = strlen(s) * 5 + 1; 4301 VARARR(char, buf, len); 4302 char *p = buf, *n; 4303 4304 while ((c = *s++)) { 4305 if (itok(c)) { 4306 if (c <= Comma) 4307 c = ztokens[c - Pound]; 4308 else 4309 continue; 4310 } 4311 if (c == Meta) 4312 c = *s++ ^ 32; 4313 /* The result here is metafied */ 4314 n = nicechar(c); 4315 while(*n) 4316 *p++ = *n++; 4317 } 4318 *p = '\0'; 4319 return heap ? dupstring(buf) : ztrdup(buf); 4320} 4321#endif 4322 4323/**/ 4324mod_export char * 4325nicedupstring(char const *s) 4326{ 4327 return nicedup(s, 1); 4328} 4329 4330 4331#ifndef MULTIBYTE_SUPPORT 4332/* Unmetafy and output a string, displaying special characters readably. */ 4333 4334/**/ 4335mod_export int 4336nicezputs(char const *s, FILE *stream) 4337{ 4338 int c; 4339 4340 while ((c = *s++)) { 4341 if (itok(c)) { 4342 if (c <= Comma) 4343 c = ztokens[c - Pound]; 4344 else 4345 continue; 4346 } 4347 if (c == Meta) 4348 c = *s++ ^ 32; 4349 if(zputs(nicechar(c), stream) < 0) 4350 return EOF; 4351 } 4352 return 0; 4353} 4354 4355 4356/* Return the length of the visible representation of a metafied string. */ 4357 4358/**/ 4359mod_export size_t 4360niceztrlen(char const *s) 4361{ 4362 size_t l = 0; 4363 int c; 4364 4365 while ((c = *s++)) { 4366 if (itok(c)) { 4367 if (c <= Comma) 4368 c = ztokens[c - Pound]; 4369 else 4370 continue; 4371 } 4372 if (c == Meta) 4373 c = *s++ ^ 32; 4374 l += strlen(nicechar(c)); 4375 } 4376 return l; 4377} 4378#endif 4379 4380 4381/**/ 4382#ifdef MULTIBYTE_SUPPORT 4383/* 4384 * Version of both nicezputs() and niceztrlen() for use with multibyte 4385 * characters. Input is a metafied string; output is the screen width of 4386 * the string. 4387 * 4388 * If the FILE * is not NULL, output to that, too. 4389 * 4390 * If outstrp is not NULL, set *outstrp to a zalloc'd version of 4391 * the output (still metafied). 4392 * 4393 * If "heap" is non-zero, use the heap for *outstrp, else zalloc. 4394 */ 4395 4396/**/ 4397mod_export size_t 4398mb_niceformat(const char *s, FILE *stream, char **outstrp, int heap) 4399{ 4400 size_t l = 0, newl; 4401 int umlen, outalloc, outleft, eol = 0; 4402 wchar_t c; 4403 char *ums, *ptr, *fmt, *outstr, *outptr; 4404 mbstate_t mbs; 4405 4406 if (outstrp) { 4407 outleft = outalloc = 5 * strlen(s); 4408 outptr = outstr = zalloc(outalloc); 4409 } else { 4410 outleft = outalloc = 0; 4411 outptr = outstr = NULL; 4412 } 4413 4414 ums = ztrdup(s); 4415 /* 4416 * is this necessary at this point? niceztrlen does this 4417 * but it's used in lots of places. however, one day this may 4418 * be, too. 4419 */ 4420 untokenize(ums); 4421 ptr = unmetafy(ums, ¨en); 4422 4423 memset(&mbs, 0, sizeof mbs); 4424 while (umlen > 0) { 4425 size_t cnt = eol ? MB_INVALID : mbrtowc(&c, ptr, umlen, &mbs); 4426 4427 switch (cnt) { 4428 case MB_INCOMPLETE: 4429 eol = 1; 4430 /* FALL THROUGH */ 4431 case MB_INVALID: 4432 /* The byte didn't convert, so output it as a \M-... sequence. */ 4433 fmt = nicechar(*ptr); 4434 newl = strlen(fmt); 4435 cnt = 1; 4436 /* Get mbs out of its undefined state. */ 4437 memset(&mbs, 0, sizeof mbs); 4438 break; 4439 case 0: 4440 /* Careful: converting '\0' returns 0, but a '\0' is a 4441 * real character for us, so we should consume 1 byte. */ 4442 cnt = 1; 4443 /* FALL THROUGH */ 4444 default: 4445 fmt = wcs_nicechar(c, &newl, NULL); 4446 break; 4447 } 4448 4449 umlen -= cnt; 4450 ptr += cnt; 4451 l += newl; 4452 4453 if (stream) 4454 zputs(fmt, stream); 4455 if (outstr) { 4456 /* Append to output string */ 4457 int outlen = strlen(fmt); 4458 if (outlen >= outleft) { 4459 /* Reallocate to twice the length */ 4460 int outoffset = outptr - outstr; 4461 4462 outleft += outalloc; 4463 outalloc *= 2; 4464 outstr = zrealloc(outstr, outalloc); 4465 outptr = outstr + outoffset; 4466 } 4467 memcpy(outptr, fmt, outlen); 4468 /* Update start position */ 4469 outptr += outlen; 4470 /* Update available bytes */ 4471 outleft -= outlen; 4472 } 4473 } 4474 4475 free(ums); 4476 if (outstrp) { 4477 *outptr = '\0'; 4478 /* Use more efficient storage for returned string */ 4479 *outstrp = heap ? dupstring(outstr) : ztrdup(outstr); 4480 free(outstr); 4481 } 4482 4483 return l; 4484} 4485 4486/* ztrdup multibyte string with nice formatting */ 4487 4488/**/ 4489mod_export char * 4490nicedup(const char *s, int heap) 4491{ 4492 char *retstr; 4493 4494 (void)mb_niceformat(s, NULL, &retstr, heap); 4495 4496 return retstr; 4497} 4498 4499 4500/* 4501 * The guts of mb_metacharlenconv(). This version assumes we are 4502 * processing a true multibyte character string without tokens, and 4503 * takes the shift state as an argument. 4504 */ 4505 4506/**/ 4507mod_export int 4508mb_metacharlenconv_r(const char *s, wint_t *wcp, mbstate_t *mbsp) 4509{ 4510 size_t ret = MB_INVALID; 4511 char inchar; 4512 const char *ptr; 4513 wchar_t wc; 4514 4515 for (ptr = s; *ptr; ) { 4516 if (*ptr == Meta) { 4517 inchar = *++ptr ^ 32; 4518 DPUTS(!*ptr, 4519 "BUG: unexpected end of string in mb_metacharlen()\n"); 4520 } else 4521 inchar = *ptr; 4522 ptr++; 4523 ret = mbrtowc(&wc, &inchar, 1, mbsp); 4524 4525 if (ret == MB_INVALID) 4526 break; 4527 if (ret == MB_INCOMPLETE) 4528 continue; 4529 if (wcp) 4530 *wcp = wc; 4531 return ptr - s; 4532 } 4533 4534 if (wcp) 4535 *wcp = WEOF; 4536 /* No valid multibyte sequence */ 4537 memset(mbsp, 0, sizeof(*mbsp)); 4538 if (ptr > s) { 4539 return 1 + (*s == Meta); /* Treat as single byte character */ 4540 } else 4541 return 0; /* Probably shouldn't happen */ 4542} 4543 4544/* 4545 * Length of metafied string s which contains the next multibyte 4546 * character; single (possibly metafied) character if string is not null 4547 * but character is not valid (e.g. possibly incomplete at end of string). 4548 * Returned value is guaranteed not to reach beyond the end of the 4549 * string (assuming correct metafication). 4550 * 4551 * If wcp is not NULL, the converted wide character is stored there. 4552 * If no conversion could be done WEOF is used. 4553 */ 4554 4555/**/ 4556mod_export int 4557mb_metacharlenconv(const char *s, wint_t *wcp) 4558{ 4559 if (!isset(MULTIBYTE)) { 4560 /* treat as single byte, possibly metafied */ 4561 if (wcp) 4562 *wcp = (wint_t)(*s == Meta ? s[1] ^ 32 : *s); 4563 return 1 + (*s == Meta); 4564 } 4565 /* 4566 * We have to handle tokens here, since we may be looking 4567 * through a tokenized input. Obviously this isn't 4568 * a valid multibyte character, so just return WEOF 4569 * and let the caller handle it as a single character. 4570 * 4571 * TODO: I've a sneaking suspicion we could do more here 4572 * to prevent the caller always needing to handle invalid 4573 * characters specially, but sometimes it may need to know. 4574 */ 4575 if (itok(*s)) { 4576 if (wcp) 4577 *wcp = WEOF; 4578 return 1; 4579 } 4580 4581 return mb_metacharlenconv_r(s, wcp, &mb_shiftstate); 4582} 4583 4584/* 4585 * Total number of multibyte characters in metafied string s. 4586 * Same answer as iterating mb_metacharlen() and counting calls 4587 * until end of string. 4588 * 4589 * If width is 1, return total character width rather than number. 4590 * If width is greater than 1, return 1 if character has non-zero width, 4591 * else 0. 4592 */ 4593 4594/**/ 4595mod_export int 4596mb_metastrlen(char *ptr, int width) 4597{ 4598 char inchar, *laststart; 4599 size_t ret; 4600 wchar_t wc; 4601 int num, num_in_char; 4602 4603 if (!isset(MULTIBYTE)) 4604 return ztrlen(ptr); 4605 4606 laststart = ptr; 4607 ret = MB_INVALID; 4608 num = num_in_char = 0; 4609 4610 memset(&mb_shiftstate, 0, sizeof(mb_shiftstate)); 4611 while (*ptr) { 4612 if (*ptr == Meta) 4613 inchar = *++ptr ^ 32; 4614 else 4615 inchar = *ptr; 4616 ptr++; 4617 ret = mbrtowc(&wc, &inchar, 1, &mb_shiftstate); 4618 4619 if (ret == MB_INCOMPLETE) { 4620 num_in_char++; 4621 } else { 4622 if (ret == MB_INVALID) { 4623 /* Reset, treat as single character */ 4624 memset(&mb_shiftstate, 0, sizeof(mb_shiftstate)); 4625 ptr = laststart + (*laststart == Meta) + 1; 4626 num++; 4627 } else if (width) { 4628 /* 4629 * Returns -1 if not a printable character. We 4630 * turn this into 0. 4631 */ 4632 int wcw = WCWIDTH(wc); 4633 if (wcw > 0) { 4634 if (width == 1) 4635 num += wcw; 4636 else 4637 num++; 4638 } 4639 } else 4640 num++; 4641 laststart = ptr; 4642 num_in_char = 0; 4643 } 4644 } 4645 4646 /* If incomplete, treat remainder as trailing single bytes */ 4647 return num + num_in_char; 4648} 4649 4650/**/ 4651#else 4652 4653/* Simple replacement for mb_metacharlenconv */ 4654 4655/**/ 4656mod_export int 4657metacharlenconv(const char *x, int *c) 4658{ 4659 /* 4660 * Here we don't use STOUC() on the chars since they 4661 * may be compared against other chars and this will fail 4662 * if chars are signed and the high bit is set. 4663 */ 4664 if (*x == Meta) { 4665 if (c) 4666 *c = x[1] ^ 32; 4667 return 2; 4668 } 4669 if (c) 4670 *c = (char)*x; 4671 return 1; 4672} 4673 4674/**/ 4675#endif /* MULTIBYTE_SUPPORT */ 4676 4677/* check for special characters in the string */ 4678 4679/**/ 4680mod_export int 4681hasspecial(char const *s) 4682{ 4683 for (; *s; s++) { 4684 if (ispecial(*s == Meta ? *++s ^ 32 : *s)) 4685 return 1; 4686 } 4687 return 0; 4688} 4689 4690 4691static char * 4692addunprintable(char *v, const char *u, const char *uend) 4693{ 4694 for (; u < uend; u++) { 4695 /* 4696 * Just do this byte by byte; there's no great 4697 * advantage in being clever with multibyte 4698 * characters if we don't think they're printable. 4699 */ 4700 int c; 4701 if (*u == Meta) 4702 c = STOUC(*++u ^ 32); 4703 else 4704 c = STOUC(*u); 4705 switch (c) { 4706 case '\0': 4707 *v++ = '\\'; 4708 *v++ = '0'; 4709 if ('0' <= u[1] && u[1] <= '7') { 4710 *v++ = '0'; 4711 *v++ = '0'; 4712 } 4713 break; 4714 4715 case '\007': *v++ = '\\'; *v++ = 'a'; break; 4716 case '\b': *v++ = '\\'; *v++ = 'b'; break; 4717 case '\f': *v++ = '\\'; *v++ = 'f'; break; 4718 case '\n': *v++ = '\\'; *v++ = 'n'; break; 4719 case '\r': *v++ = '\\'; *v++ = 'r'; break; 4720 case '\t': *v++ = '\\'; *v++ = 't'; break; 4721 case '\v': *v++ = '\\'; *v++ = 'v'; break; 4722 4723 default: 4724 *v++ = '\\'; 4725 *v++ = '0' + ((c >> 6) & 7); 4726 *v++ = '0' + ((c >> 3) & 7); 4727 *v++ = '0' + (c & 7); 4728 break; 4729 } 4730 } 4731 4732 return v; 4733} 4734 4735/* 4736 * Quote the string s and return the result as a string from the heap. 4737 * 4738 * If e is non-zero, the 4739 * pointer it points to may point to a position in s and in e the position 4740 * of the corresponding character in the quoted string is returned. 4741 * 4742 * The last argument is a QT_ value defined in zsh.h other than QT_NONE. 4743 * 4744 * Most quote styles other than backslash assume the quotes are to 4745 * be added outside quotestring(). QT_SINGLE_OPTIONAL is different: 4746 * the single quotes are only added where necessary, so the 4747 * whole expression is handled here. 4748 * 4749 * The string may be metafied and contain tokens. 4750 */ 4751 4752/**/ 4753mod_export char * 4754quotestring(const char *s, char **e, int instring) 4755{ 4756 const char *u; 4757 char *v; 4758 int alloclen; 4759 char *buf; 4760 int sf = 0, shownull = 0; 4761 /* 4762 * quotesub is used with QT_SINGLE_OPTIONAL. 4763 * quotesub = 0: mechanism not active 4764 * quotesub = 1: mechanism pending, no "'" yet; 4765 * needs adding at quotestart. 4766 * quotesub = 2: mechanism active, added opening "'"; need 4767 * closing "'". 4768 */ 4769 int quotesub = 0, slen; 4770 char *quotestart; 4771 convchar_t cc; 4772 const char *uend; 4773 4774 slen = strlen(s); 4775 switch (instring) 4776 { 4777 case QT_BACKSLASH_SHOWNULL: 4778 shownull = 1; 4779 instring = QT_BACKSLASH; 4780 /*FALLTHROUGH*/ 4781 case QT_BACKSLASH: 4782 /* 4783 * With QT_BACKSLASH we may need to use $'\300' stuff. 4784 * Keep memory usage within limits by allocating temporary 4785 * storage and using heap for correct size at end. 4786 */ 4787 alloclen = slen * 7 + 1; 4788 break; 4789 4790 case QT_SINGLE_OPTIONAL: 4791 /* 4792 * Here, we may need to add single quotes. 4793 * Always show empty strings. 4794 */ 4795 alloclen = slen * 4 + 3; 4796 quotesub = shownull = 1; 4797 break; 4798 4799 default: 4800 alloclen = slen * 4 + 1; 4801 break; 4802 } 4803 if (!*s && shownull) 4804 alloclen += 2; /* for '' */ 4805 4806 quotestart = v = buf = zshcalloc(alloclen); 4807 4808 DPUTS(instring < QT_BACKSLASH || instring == QT_BACKTICK || 4809 instring > QT_SINGLE_OPTIONAL, 4810 "BUG: bad quote type in quotestring"); 4811 u = s; 4812 if (instring == QT_DOLLARS) { 4813 /* 4814 * As we test for printability here we need to be able 4815 * to look for multibyte characters. 4816 */ 4817 MB_METACHARINIT(); 4818 while (*u) { 4819 uend = u + MB_METACHARLENCONV(u, &cc); 4820 4821 if (e && !sf && *e <= u) { 4822 *e = v; 4823 sf = 1; 4824 } 4825 if ( 4826#ifdef MULTIBYTE_SUPPORT 4827 cc != WEOF && 4828#endif 4829 WC_ISPRINT(cc)) { 4830 switch (cc) { 4831 case ZWC('\\'): 4832 case ZWC('\''): 4833 *v++ = '\\'; 4834 break; 4835 4836 default: 4837 if (isset(BANGHIST) && cc == (wchar_t)bangchar) 4838 *v++ = '\\'; 4839 break; 4840 } 4841 while (u < uend) 4842 *v++ = *u++; 4843 } else { 4844 /* Not printable */ 4845 v = addunprintable(v, u, uend); 4846 u = uend; 4847 } 4848 } 4849 } 4850 else 4851 { 4852 if (shownull) { 4853 /* We can't show an empty string with just backslash quoting. */ 4854 if (!*u) { 4855 *v++ = '\''; 4856 *v++ = '\''; 4857 } 4858 } 4859 /* 4860 * Here there are syntactic special characters, so 4861 * we start by going through bytewise. 4862 */ 4863 while (*u) { 4864 int dobackslash = 0; 4865 if (e && *e == u) 4866 *e = v, sf = 1; 4867 if (*u == Tick || *u == Qtick) { 4868 char c = *u++; 4869 4870 *v++ = c; 4871 while (*u && *u != c) 4872 *v++ = *u++; 4873 *v++ = c; 4874 if (*u) 4875 u++; 4876 continue; 4877 } else if ((*u == Qstring || *u == '$') && u[1] == '\'' && 4878 instring == QT_DOUBLE) { 4879 /* 4880 * We don't need to quote $'...' inside a double-quoted 4881 * string. This is largely cosmetic; it looks neater 4882 * if we don't but it doesn't do any harm since the 4883 * \ is stripped. 4884 */ 4885 *v++ = *u++; 4886 } else if ((*u == String || *u == Qstring) && 4887 (u[1] == Inpar || u[1] == Inbrack || u[1] == Inbrace)) { 4888 char c = (u[1] == Inpar ? Outpar : (u[1] == Inbrace ? 4889 Outbrace : Outbrack)); 4890 char beg = *u; 4891 int level = 0; 4892 4893 *v++ = *u++; 4894 *v++ = *u++; 4895 while (*u && (*u != c || level)) { 4896 if (*u == beg) 4897 level++; 4898 else if (*u == c) 4899 level--; 4900 *v++ = *u++; 4901 } 4902 if (*u) 4903 *v++ = *u++; 4904 continue; 4905 } 4906 else if (ispecial(*u) && 4907 ((*u != '=' && *u != '~') || 4908 u == s || 4909 (isset(MAGICEQUALSUBST) && 4910 (u[-1] == '=' || u[-1] == ':')) || 4911 (*u == '~' && isset(EXTENDEDGLOB))) && 4912 (instring == QT_BACKSLASH || 4913 instring == QT_SINGLE_OPTIONAL || 4914 (isset(BANGHIST) && *u == (char)bangchar && 4915 instring != QT_SINGLE) || 4916 (instring == QT_DOUBLE && 4917 (*u == '$' || *u == '`' || *u == '\"' || *u == '\\')) || 4918 (instring == QT_SINGLE && *u == '\''))) { 4919 if (instring == QT_SINGLE_OPTIONAL) { 4920 if (quotesub == 1) { 4921 /* 4922 * We haven't yet had to quote at the start. 4923 */ 4924 if (*u == '\'') { 4925 /* 4926 * We don't need to. 4927 */ 4928 *v++ = '\\'; 4929 } else { 4930 /* 4931 * It's now time to add quotes. 4932 */ 4933 if (v > quotestart) 4934 { 4935 char *addq; 4936 4937 for (addq = v; addq > quotestart; addq--) 4938 *addq = addq[-1]; 4939 } 4940 *quotestart = '\''; 4941 v++; 4942 quotesub = 2; 4943 } 4944 *v++ = *u++; 4945 /* 4946 * Next place to start quotes is here. 4947 */ 4948 quotestart = v; 4949 } else if (*u == '\'') { 4950 if (unset(RCQUOTES)) { 4951 *v++ = '\''; 4952 *v++ = '\\'; 4953 *v++ = '\''; 4954 /* Don't restart quotes unless we need them */ 4955 quotesub = 1; 4956 quotestart = v; 4957 } else { 4958 /* simplest just to use '' always */ 4959 *v++ = '\''; 4960 *v++ = '\''; 4961 } 4962 /* dealt with */ 4963 u++; 4964 } else { 4965 /* else already quoting, just add */ 4966 *v++ = *u++; 4967 } 4968 continue; 4969 } else if (*u == '\n' || 4970 (instring == QT_SINGLE && *u == '\'')) { 4971 if (*u == '\n') { 4972 *v++ = '$'; 4973 *v++ = '\''; 4974 *v++ = '\\'; 4975 *v++ = 'n'; 4976 *v++ = '\''; 4977 } else if (unset(RCQUOTES)) { 4978 *v++ = '\''; 4979 if (*u == '\'') 4980 *v++ = '\\'; 4981 *v++ = *u; 4982 *v++ = '\''; 4983 } else 4984 *v++ = '\'', *v++ = '\''; 4985 u++; 4986 continue; 4987 } else { 4988 /* 4989 * We'll need a backslash, but don't add it 4990 * yet since if the character isn't printable 4991 * we'll have to upgrade it to $'...'. 4992 */ 4993 dobackslash = 1; 4994 } 4995 } 4996 4997 if (itok(*u) || instring != QT_BACKSLASH) { 4998 /* Needs to be passed straight through. */ 4999 if (dobackslash) 5000 *v++ = '\\'; 5001 *v++ = *u++; 5002 continue; 5003 } 5004 5005 /* 5006 * Now check if the output is unprintable in the 5007 * current character set. 5008 */ 5009 uend = u + MB_METACHARLENCONV(u, &cc); 5010 if ( 5011#ifdef MULTIBYTE_SUPPORT 5012 cc != WEOF && 5013#endif 5014 WC_ISPRINT(cc)) { 5015 if (dobackslash) 5016 *v++ = '\\'; 5017 while (u < uend) { 5018 if (*u == Meta) 5019 *v++ = *u++; 5020 *v++ = *u++; 5021 } 5022 } else { 5023 /* Not printable */ 5024 *v++ = '$'; 5025 *v++ = '\''; 5026 v = addunprintable(v, u, uend); 5027 *v++ = '\''; 5028 u = uend; 5029 } 5030 } 5031 } 5032 if (quotesub == 2) 5033 *v++ = '\''; 5034 *v = '\0'; 5035 5036 if (e && *e == u) 5037 *e = v, sf = 1; 5038 DPUTS(e && !sf, "BUG: Wild pointer *e in quotestring()"); 5039 5040 v = dupstring(buf); 5041 zfree(buf, alloclen); 5042 return v; 5043} 5044 5045/* Unmetafy and output a string, quoted if it contains special characters. */ 5046 5047/**/ 5048mod_export int 5049quotedzputs(char const *s, FILE *stream) 5050{ 5051 int inquote = 0, c; 5052 5053 /* check for empty string */ 5054 if(!*s) 5055 return fputs("''", stream); 5056 5057 if (!hasspecial(s)) 5058 return zputs(s, stream); 5059 5060 if (isset(RCQUOTES)) { 5061 /* use rc-style quotes-within-quotes for the whole string */ 5062 if(fputc('\'', stream) < 0) 5063 return EOF; 5064 while(*s) { 5065 if (*s == Meta) 5066 c = *++s ^ 32; 5067 else 5068 c = *s; 5069 s++; 5070 if (c == '\'') { 5071 if(fputc('\'', stream) < 0) 5072 return EOF; 5073 } else if(c == '\n' && isset(CSHJUNKIEQUOTES)) { 5074 if(fputc('\\', stream) < 0) 5075 return EOF; 5076 } 5077 if(fputc(c, stream) < 0) 5078 return EOF; 5079 } 5080 if(fputc('\'', stream) < 0) 5081 return EOF; 5082 } else { 5083 /* use Bourne-style quoting, avoiding empty quoted strings */ 5084 while(*s) { 5085 if (*s == Meta) 5086 c = *++s ^ 32; 5087 else 5088 c = *s; 5089 s++; 5090 if (c == '\'') { 5091 if(inquote) { 5092 if(fputc('\'', stream) < 0) 5093 return EOF; 5094 inquote=0; 5095 } 5096 if(fputs("\\'", stream) < 0) 5097 return EOF; 5098 } else { 5099 if (!inquote) { 5100 if(fputc('\'', stream) < 0) 5101 return EOF; 5102 inquote=1; 5103 } 5104 if(c == '\n' && isset(CSHJUNKIEQUOTES)) { 5105 if(fputc('\\', stream) < 0) 5106 return EOF; 5107 } 5108 if(fputc(c, stream) < 0) 5109 return EOF; 5110 } 5111 } 5112 if (inquote) { 5113 if(fputc('\'', stream) < 0) 5114 return EOF; 5115 } 5116 } 5117 return 0; 5118} 5119 5120/* Double-quote a metafied string. */ 5121 5122/**/ 5123mod_export char * 5124dquotedztrdup(char const *s) 5125{ 5126 int len = strlen(s) * 4 + 2; 5127 char *buf = zalloc(len); 5128 char *p = buf, *ret; 5129 5130 if(isset(CSHJUNKIEQUOTES)) { 5131 int inquote = 0; 5132 5133 while(*s) { 5134 int c = *s++; 5135 5136 if (c == Meta) 5137 c = *s++ ^ 32; 5138 switch(c) { 5139 case '"': 5140 case '$': 5141 case '`': 5142 if(inquote) { 5143 *p++ = '"'; 5144 inquote = 0; 5145 } 5146 *p++ = '\\'; 5147 *p++ = c; 5148 break; 5149 default: 5150 if(!inquote) { 5151 *p++ = '"'; 5152 inquote = 1; 5153 } 5154 if(c == '\n') 5155 *p++ = '\\'; 5156 *p++ = c; 5157 break; 5158 } 5159 } 5160 if (inquote) 5161 *p++ = '"'; 5162 } else { 5163 int pending = 0; 5164 5165 *p++ = '"'; 5166 while(*s) { 5167 int c = *s++; 5168 5169 if (c == Meta) 5170 c = *s++ ^ 32; 5171 switch(c) { 5172 case '\\': 5173 if(pending) 5174 *p++ = '\\'; 5175 *p++ = '\\'; 5176 pending = 1; 5177 break; 5178 case '"': 5179 case '$': 5180 case '`': 5181 if(pending) 5182 *p++ = '\\'; 5183 *p++ = '\\'; 5184 /* FALL THROUGH */ 5185 default: 5186 *p++ = c; 5187 pending = 0; 5188 break; 5189 } 5190 } 5191 if(pending) 5192 *p++ = '\\'; 5193 *p++ = '"'; 5194 } 5195 ret = metafy(buf, p - buf, META_DUP); 5196 zfree(buf, len); 5197 return ret; 5198} 5199 5200/* Unmetafy and output a string, double quoting it in its entirety. */ 5201 5202#if 0 /**/ 5203int 5204dquotedzputs(char const *s, FILE *stream) 5205{ 5206 char *d = dquotedztrdup(s); 5207 int ret = zputs(d, stream); 5208 5209 zsfree(d); 5210 return ret; 5211} 5212#endif 5213 5214# if defined(HAVE_NL_LANGINFO) && defined(CODESET) && !defined(__STDC_ISO_10646__) 5215/* Convert a character from UCS4 encoding to UTF-8 */ 5216 5217static size_t 5218ucs4toutf8(char *dest, unsigned int wval) 5219{ 5220 size_t len; 5221 5222 if (wval < 0x80) 5223 len = 1; 5224 else if (wval < 0x800) 5225 len = 2; 5226 else if (wval < 0x10000) 5227 len = 3; 5228 else if (wval < 0x200000) 5229 len = 4; 5230 else if (wval < 0x4000000) 5231 len = 5; 5232 else 5233 len = 6; 5234 5235 switch (len) { /* falls through except to the last case */ 5236 case 6: dest[5] = (wval & 0x3f) | 0x80; wval >>= 6; 5237 case 5: dest[4] = (wval & 0x3f) | 0x80; wval >>= 6; 5238 case 4: dest[3] = (wval & 0x3f) | 0x80; wval >>= 6; 5239 case 3: dest[2] = (wval & 0x3f) | 0x80; wval >>= 6; 5240 case 2: dest[1] = (wval & 0x3f) | 0x80; wval >>= 6; 5241 *dest = wval | ((0xfc << (6 - len)) & 0xfc); 5242 break; 5243 case 1: *dest = wval; 5244 } 5245 5246 return len; 5247} 5248#endif 5249 5250 5251/* 5252 * The following only occurs once or twice in the code, but in different 5253 * places depending how character set conversion is implemented. 5254 */ 5255#define CHARSET_FAILED() \ 5256 if (how & GETKEY_DOLLAR_QUOTE) { \ 5257 while ((*tdest++ = *++s)) { \ 5258 if (how & GETKEY_UPDATE_OFFSET) { \ 5259 if (s - sstart > *misc) \ 5260 (*misc)++; \ 5261 } \ 5262 if (*s == Snull) { \ 5263 *len = (s - sstart) + 1; \ 5264 *tdest = '\0'; \ 5265 return buf; \ 5266 } \ 5267 } \ 5268 *len = tdest - buf; \ 5269 return buf; \ 5270 } \ 5271 *t = '\0'; \ 5272 *len = t - buf; \ 5273 return buf 5274 5275/* 5276 * Decode a key string, turning it into the literal characters. 5277 * The value returned is a newly allocated string from the heap. 5278 * 5279 * The length is returned in *len. This is usually the length of 5280 * the final unmetafied string. The exception is the case of 5281 * a complete GETKEY_DOLLAR_QUOTE conversion where *len is the 5282 * length of the input string which has been used (up to and including 5283 * the terminating single quote); as the final string is metafied and 5284 * NULL-terminated its length is not required. If both GETKEY_DOLLAR_QUOTE 5285 * and GETKEY_UPDATE_OFFSET are present in "how", the string is not 5286 * expected to be terminated (this is used in completion to parse 5287 * a partial $'...'-quoted string) and the length passed back is 5288 * that of the converted string. Note in both cases that this is a length 5289 * in bytes (i.e. the same as given by a raw pointer difference), not 5290 * characters, which may occupy multiple bytes. 5291 * 5292 * how is a set of bits from the GETKEY_ values defined in zsh.h; 5293 * not all combinations of bits are useful. Callers will typically 5294 * use one of the GETKEYS_ values which define sets of bits. 5295 * Note, for example that: 5296 * - GETKEY_SINGLE_CHAR must not be combined with GETKEY_DOLLAR_QUOTE. 5297 * - GETKEY_UPDATE_OFFSET is only allowed if GETKEY_DOLLAR_QUOTE is 5298 * also present. 5299 * 5300 * *misc is used for various purposes: 5301 * - If GETKEY_BACKSLASH_MINUS is set, it indicates the presence 5302 * of \- in the input. 5303 * - If GETKEY_BACKSLASH_C is set, it indicates the presence 5304 * of \c in the input. 5305 * - If GETKEY_UPDATE_OFFSET is set, it is set on input to some 5306 * mystical completion offset and is updated to a new offset based 5307 * on the converted characters. All Hail the Completion System 5308 * [makes the mystic completion system runic sign in the air]. 5309 * 5310 * The return value is unmetafied unless GETKEY_DOLLAR_QUOTE is 5311 * in use. 5312 */ 5313 5314/**/ 5315mod_export char * 5316getkeystring(char *s, int *len, int how, int *misc) 5317{ 5318 char *buf, tmp[1]; 5319 char *t, *tdest = NULL, *u = NULL, *sstart = s, *tbuf = NULL; 5320 char svchar = '\0'; 5321 int meta = 0, control = 0, ignoring = 0; 5322 int i; 5323#if defined(HAVE_WCHAR_H) && defined(HAVE_WCTOMB) && defined(__STDC_ISO_10646__) 5324 wint_t wval; 5325 int count; 5326#else 5327 unsigned int wval; 5328# if defined(HAVE_NL_LANGINFO) && defined(CODESET) 5329# if defined(HAVE_ICONV) 5330 iconv_t cd; 5331 char inbuf[4]; 5332 size_t inbytes, outbytes; 5333# endif 5334 size_t count; 5335# endif 5336#endif 5337 5338 DPUTS((how & GETKEY_UPDATE_OFFSET) && 5339 (how & ~(GETKEYS_DOLLARS_QUOTE|GETKEY_UPDATE_OFFSET)), 5340 "BUG: offset updating in getkeystring only supported with $'."); 5341 DPUTS((how & (GETKEY_DOLLAR_QUOTE|GETKEY_SINGLE_CHAR)) == 5342 (GETKEY_DOLLAR_QUOTE|GETKEY_SINGLE_CHAR), 5343 "BUG: incompatible options in getkeystring"); 5344 5345 if (how & GETKEY_SINGLE_CHAR) 5346 t = buf = tmp; 5347 else { 5348 /* Length including terminating NULL */ 5349 int maxlen = 1; 5350 /* 5351 * We're not necessarily guaranteed the output string will 5352 * be no longer than the input with \u and \U when output 5353 * characters need to be metafied. As this is the only 5354 * case where the string can get longer (?I think), 5355 * include it in the allocation length here but don't 5356 * bother taking account of other factors. 5357 */ 5358 for (t = s; *t; t++) { 5359 if (*t == '\\') { 5360 if (!t[1]) { 5361 maxlen++; 5362 break; 5363 } 5364 if (t[1] == 'u' || t[1] == 'U') 5365 maxlen += MB_CUR_MAX * 2; 5366 else 5367 maxlen += 2; 5368 /* skip the backslash and the following character */ 5369 t++; 5370 } else 5371 maxlen++; 5372 } 5373 if (how & GETKEY_DOLLAR_QUOTE) { 5374 /* 5375 * We're going to unmetafy into a new string, but 5376 * to get a proper metafied input we're going to metafy 5377 * into an intermediate buffer. This is necessary if we have 5378 * \u and \U's with multiple metafied bytes. We can't 5379 * simply remetafy the entire string because there may 5380 * be tokens (indeed, we know there are lexical nulls floating 5381 * around), so we have to be aware character by character 5382 * what we are converting. 5383 * 5384 * In this case, buf is the final buffer (as usual), 5385 * but t points into a temporary buffer that just has 5386 * to be long enough to hold the result of one escape 5387 * code transformation. We count this is a full multibyte 5388 * character (MB_CUR_MAX) with every character metafied 5389 * (*2) plus a little bit of fuzz (for e.g. the odd backslash). 5390 */ 5391 buf = tdest = zhalloc(maxlen); 5392 t = tbuf = zhalloc(MB_CUR_MAX * 3 + 1); 5393 } else { 5394 t = buf = zhalloc(maxlen); 5395 } 5396 } 5397 for (; *s; s++) { 5398 if (*s == '\\' && s[1]) { 5399 int miscadded; 5400 if ((how & GETKEY_UPDATE_OFFSET) && s - sstart < *misc) { 5401 (*misc)--; 5402 miscadded = 1; 5403 } else 5404 miscadded = 0; 5405 switch (*++s) { 5406 case 'a': 5407#ifdef __STDC__ 5408 *t++ = '\a'; 5409#else 5410 *t++ = '\07'; 5411#endif 5412 break; 5413 case 'n': 5414 *t++ = '\n'; 5415 break; 5416 case 'b': 5417 *t++ = '\b'; 5418 break; 5419 case 't': 5420 *t++ = '\t'; 5421 break; 5422 case 'v': 5423 *t++ = '\v'; 5424 break; 5425 case 'f': 5426 *t++ = '\f'; 5427 break; 5428 case 'r': 5429 *t++ = '\r'; 5430 break; 5431 case 'E': 5432 if (!(how & GETKEY_EMACS)) { 5433 *t++ = '\\', s--; 5434 if (miscadded) 5435 (*misc)++; 5436 continue; 5437 } 5438 /* FALL THROUGH */ 5439 case 'e': 5440 *t++ = '\033'; 5441 break; 5442 case 'M': 5443 /* HERE: GETKEY_UPDATE_OFFSET */ 5444 if (how & GETKEY_EMACS) { 5445 if (s[1] == '-') 5446 s++; 5447 meta = 1 + control; /* preserve the order of ^ and meta */ 5448 } else { 5449 if (miscadded) 5450 (*misc)++; 5451 *t++ = '\\', s--; 5452 } 5453 continue; 5454 case 'C': 5455 /* HERE: GETKEY_UPDATE_OFFSET */ 5456 if (how & GETKEY_EMACS) { 5457 if (s[1] == '-') 5458 s++; 5459 control = 1; 5460 } else { 5461 if (miscadded) 5462 (*misc)++; 5463 *t++ = '\\', s--; 5464 } 5465 continue; 5466 case Meta: 5467 if (miscadded) 5468 (*misc)++; 5469 *t++ = '\\', s--; 5470 break; 5471 case '-': 5472 if (how & GETKEY_BACKSLASH_MINUS) { 5473 *misc = 1; 5474 break; 5475 } 5476 goto def; 5477 case 'c': 5478 if (how & GETKEY_BACKSLASH_C) { 5479 *misc = 1; 5480 *t = '\0'; 5481 *len = t - buf; 5482 return buf; 5483 } 5484 goto def; 5485 case 'U': 5486 if ((how & GETKEY_UPDATE_OFFSET) && s - sstart < *misc) 5487 (*misc) -= 4; 5488 /* FALLTHROUGH */ 5489 case 'u': 5490 if ((how & GETKEY_UPDATE_OFFSET) && s - sstart < *misc) { 5491 (*misc) -= 6; /* HERE don't really believe this */ 5492 /* 5493 * We've now adjusted the offset for all the input 5494 * characters, so we need to add for each 5495 * byte of output below. 5496 */ 5497 } 5498 wval = 0; 5499 for (i=(*s == 'u' ? 4 : 8); i>0; i--) { 5500 if (*++s && idigit(*s)) 5501 wval = wval * 16 + (*s - '0'); 5502 else if (*s && ((*s >= 'a' && *s <= 'f') || 5503 (*s >= 'A' && *s <= 'F'))) 5504 wval = wval * 16 + (*s & 0x1f) + 9; 5505 else { 5506 s--; 5507 break; 5508 } 5509 } 5510 if (how & GETKEY_SINGLE_CHAR) { 5511 *misc = wval; 5512 return s+1; 5513 } 5514#if defined(HAVE_WCHAR_H) && defined(HAVE_WCTOMB) && defined(__STDC_ISO_10646__) 5515 count = wctomb(t, (wchar_t)wval); 5516 if (count == -1) { 5517 zerr("character not in range"); 5518 CHARSET_FAILED(); 5519 } 5520 if ((how & GETKEY_UPDATE_OFFSET) && s - sstart < *misc) 5521 (*misc) += count; 5522 t += count; 5523# else 5524# if defined(HAVE_NL_LANGINFO) && defined(CODESET) 5525 if (!strcmp(nl_langinfo(CODESET), "UTF-8")) { 5526 count = ucs4toutf8(t, wval); 5527 t += count; 5528 if ((how & GETKEY_UPDATE_OFFSET) && s - sstart < *misc) 5529 (*misc) += count; 5530 } else { 5531# ifdef HAVE_ICONV 5532 ICONV_CONST char *inptr = inbuf; 5533 const char *codesetstr = nl_langinfo(CODESET); 5534 inbytes = 4; 5535 outbytes = 6; 5536 /* store value in big endian form */ 5537 for (i=3;i>=0;i--) { 5538 inbuf[i] = wval & 0xff; 5539 wval >>= 8; 5540 } 5541 5542 /* 5543 * If the code set isn't handled, we'd better 5544 * assume it's US-ASCII rather than just failing 5545 * hopelessly. Solaris has a weird habit of 5546 * returning 646. This is handled by the 5547 * native iconv(), but not by GNU iconv; what's 5548 * more, some versions of the native iconv don't 5549 * handle standard names like ASCII. 5550 * 5551 * This should only be a problem if there's a 5552 * mismatch between the NLS and the iconv in use, 5553 * which probably only means if libiconv is in use. 5554 * We checked at configure time if our libraries 5555 * pulled in _libiconv_version, which should be 5556 * a good test. 5557 * 5558 * It shouldn't ever be NULL, but while we're 5559 * being paranoid... 5560 */ 5561#ifdef ICONV_FROM_LIBICONV 5562 if (!codesetstr || !*codesetstr) 5563 codesetstr = "US-ASCII"; 5564#endif 5565 cd = iconv_open(codesetstr, "UCS-4BE"); 5566#ifdef ICONV_FROM_LIBICONV 5567 if (cd == (iconv_t)-1 && !strcmp(codesetstr, "646")) { 5568 codesetstr = "US-ASCII"; 5569 cd = iconv_open(codesetstr, "UCS-4BE"); 5570 } 5571#endif 5572 if (cd == (iconv_t)-1) { 5573 zerr("cannot do charset conversion (iconv failed)"); 5574 CHARSET_FAILED(); 5575 } 5576 count = iconv(cd, &inptr, &inbytes, &t, &outbytes); 5577 iconv_close(cd); 5578 if (count == (size_t)-1) { 5579 zerr("character not in range"); 5580 CHARSET_FAILED(); 5581 } 5582 if ((how & GETKEY_UPDATE_OFFSET) && s - sstart < *misc) 5583 (*misc) += count; 5584# else 5585 zerr("cannot do charset conversion (iconv not available)"); 5586 CHARSET_FAILED(); 5587# endif 5588 } 5589# else 5590 zerr("cannot do charset conversion (NLS not supported)"); 5591 CHARSET_FAILED(); 5592# endif 5593# endif 5594 if (how & GETKEY_DOLLAR_QUOTE) { 5595 char *t2; 5596 for (t2 = tbuf; t2 < t; t2++) { 5597 if (imeta(*t2)) { 5598 *tdest++ = Meta; 5599 *tdest++ = *t2 ^ 32; 5600 } else 5601 *tdest++ = *t2; 5602 } 5603 /* reset temporary buffer after handling */ 5604 t = tbuf; 5605 } 5606 continue; 5607 case '\'': 5608 case '\\': 5609 if (how & GETKEY_DOLLAR_QUOTE) { 5610 /* 5611 * Usually \' and \\ will have the initial 5612 * \ turned into a Bnull, however that's not 5613 * necessarily the case when called from 5614 * completion. 5615 */ 5616 *t++ = *s; 5617 break; 5618 } 5619 /* FALLTHROUGH */ 5620 default: 5621 def: 5622 /* HERE: GETKEY_UPDATE_OFFSET? */ 5623 if ((idigit(*s) && *s < '8') || *s == 'x') { 5624 if (!(how & GETKEY_OCTAL_ESC)) { 5625 if (*s == '0') 5626 s++; 5627 else if (*s != 'x') { 5628 *t++ = '\\', s--; 5629 continue; 5630 } 5631 } 5632 if (s[1] && s[2] && s[3]) { 5633 svchar = s[3]; 5634 s[3] = '\0'; 5635 u = s; 5636 } 5637 *t++ = zstrtol(s + (*s == 'x'), &s, 5638 (*s == 'x') ? 16 : 8); 5639 if ((how & GETKEY_PRINTF_PERCENT) && t[-1] == '%') 5640 *t++ = '%'; 5641 if (svchar) { 5642 u[3] = svchar; 5643 svchar = '\0'; 5644 } 5645 s--; 5646 } else { 5647 if (!(how & GETKEY_EMACS) && *s != '\\') { 5648 if (miscadded) 5649 (*misc)++; 5650 *t++ = '\\'; 5651 } 5652 *t++ = *s; 5653 } 5654 break; 5655 } 5656 } else if ((how & GETKEY_DOLLAR_QUOTE) && *s == Snull) { 5657 /* return length to following character */ 5658 *len = (s - sstart) + 1; 5659 *tdest = '\0'; 5660 return buf; 5661 } else if (*s == '^' && !control && (how & GETKEY_CTRL) && s[1]) { 5662 control = 1; 5663 continue; 5664#ifdef MULTIBYTE_SUPPORT 5665 } else if ((how & GETKEY_SINGLE_CHAR) && 5666 isset(MULTIBYTE) && STOUC(*s) > 127) { 5667 wint_t wc; 5668 int len; 5669 len = mb_metacharlenconv(s, &wc); 5670 if (wc != WEOF) { 5671 *misc = (int)wc; 5672 return s + len; 5673 } 5674#endif 5675 5676 } else if (*s == Meta) 5677 *t++ = *++s ^ 32; 5678 else { 5679 if (itok(*s)) { 5680 /* 5681 * We need to be quite careful here. We haven't 5682 * necessarily got an input stream with all tokens 5683 * removed, so the majority of tokens need passing 5684 * through untouched and without Meta handling. 5685 * However, me may need to handle tokenized 5686 * backslashes. 5687 */ 5688 if (meta || control) { 5689 /* 5690 * Presumably we should be using meta or control 5691 * on the character representing the token. 5692 * 5693 * Special case: $'\M-\\' where the token is a Bnull. 5694 * This time we dump the Bnull since we're 5695 * replacing the whole thing. The lexer 5696 * doesn't know about the meta or control modifiers. 5697 */ 5698 if ((how & GETKEY_DOLLAR_QUOTE) && *s == Bnull) 5699 *t++ = *++s; 5700 else 5701 *t++ = ztokens[*s - Pound]; 5702 } else if (how & GETKEY_DOLLAR_QUOTE) { 5703 /* 5704 * We don't want to metafy this, it's a real 5705 * token. 5706 */ 5707 *tdest++ = *s; 5708 if (*s == Bnull) { 5709 /* 5710 * Bnull is a backslash which quotes a couple 5711 * of special characters that always appear 5712 * literally next. See strquote handling 5713 * in gettokstr() in lex.c. We need 5714 * to retain the Bnull (as above) so that quote 5715 * handling in completion can tell where the 5716 * backslash was. 5717 */ 5718 *tdest++ = *++s; 5719 } 5720 /* reset temporary buffer, now handled */ 5721 t = tbuf; 5722 continue; 5723 } else 5724 *t++ = *s; 5725 } else 5726 *t++ = *s; 5727 } 5728 if (meta == 2) { 5729 t[-1] |= 0x80; 5730 meta = 0; 5731 } 5732 if (control) { 5733 if (t[-1] == '?') 5734 t[-1] = 0x7f; 5735 else 5736 t[-1] &= 0x9f; 5737 control = 0; 5738 } 5739 if (meta) { 5740 t[-1] |= 0x80; 5741 meta = 0; 5742 } 5743 if (how & GETKEY_DOLLAR_QUOTE) { 5744 char *t2; 5745 for (t2 = tbuf; t2 < t; t2++) { 5746 /* 5747 * In POSIX mode, an embedded NULL is discarded and 5748 * terminates processing. It just does, that's why. 5749 */ 5750 if (isset(POSIXSTRINGS)) { 5751 if (*t2 == '\0') 5752 ignoring = 1; 5753 if (ignoring) 5754 break; 5755 } 5756 if (imeta(*t2)) { 5757 *tdest++ = Meta; 5758 *tdest++ = *t2 ^ 32; 5759 } else { 5760 *tdest++ = *t2; 5761 } 5762 } 5763 /* 5764 * Reset use of temporary buffer. 5765 */ 5766 t = tbuf; 5767 } 5768 if ((how & GETKEY_SINGLE_CHAR) && t != tmp) { 5769 *misc = STOUC(tmp[0]); 5770 return s + 1; 5771 } 5772 } 5773 /* 5774 * When called from completion, where we use GETKEY_UPDATE_OFFSET to 5775 * update the index into the metafied editor line, we don't necessarily 5776 * have the end of a $'...' quotation, else we should do. 5777 */ 5778 DPUTS((how & (GETKEY_DOLLAR_QUOTE|GETKEY_UPDATE_OFFSET)) == 5779 GETKEY_DOLLAR_QUOTE, "BUG: unterminated $' substitution"); 5780 *t = '\0'; 5781 if (how & GETKEY_DOLLAR_QUOTE) 5782 *tdest = '\0'; 5783 if (how & GETKEY_SINGLE_CHAR) 5784 *misc = 0; 5785 else 5786 *len = ((how & GETKEY_DOLLAR_QUOTE) ? tdest : t) - buf; 5787 return buf; 5788} 5789 5790/* Return non-zero if s is a prefix of t. */ 5791 5792/**/ 5793mod_export int 5794strpfx(const char *s, const char *t) 5795{ 5796 while (*s && *s == *t) 5797 s++, t++; 5798 return !*s; 5799} 5800 5801/* Return non-zero if s is a suffix of t. */ 5802 5803/**/ 5804mod_export int 5805strsfx(char *s, char *t) 5806{ 5807 int ls = strlen(s), lt = strlen(t); 5808 5809 if (ls <= lt) 5810 return !strcmp(t + lt - ls, s); 5811 return 0; 5812} 5813 5814/**/ 5815static int 5816upchdir(int n) 5817{ 5818 char buf[PATH_MAX]; 5819 char *s; 5820 int err = -1; 5821 5822 while (n > 0) { 5823 for (s = buf; s < buf + PATH_MAX - 4 && n--; ) 5824 *s++ = '.', *s++ = '.', *s++ = '/'; 5825 s[-1] = '\0'; 5826 if (chdir(buf)) 5827 return err; 5828 err = -2; 5829 } 5830 return 0; 5831} 5832 5833/* 5834 * Initialize a "struct dirsav". 5835 * The structure will be set to the directory we want to save 5836 * the first time we change to a different directory. 5837 */ 5838 5839/**/ 5840mod_export void 5841init_dirsav(Dirsav d) 5842{ 5843 d->ino = d->dev = 0; 5844 d->dirname = NULL; 5845 d->dirfd = d->level = -1; 5846} 5847 5848/* Change directory, without following symlinks. Returns 0 on success, -1 * 5849 * on failure. Sets errno to ENOTDIR if any symlinks are encountered. If * 5850 * fchdir() fails, or the current directory is unreadable, we might end up * 5851 * in an unwanted directory in case of failure. */ 5852 5853/**/ 5854mod_export int 5855lchdir(char const *path, struct dirsav *d, int hard) 5856{ 5857 char const *pptr; 5858 int level; 5859 struct stat st1; 5860 struct dirsav ds; 5861#ifdef HAVE_LSTAT 5862 char buf[PATH_MAX + 1], *ptr; 5863 int err; 5864 struct stat st2; 5865#endif 5866#ifdef HAVE_FCHDIR 5867 int close_dir = 0; 5868#endif 5869 5870 if (!d) { 5871 init_dirsav(&ds); 5872 d = &ds; 5873 } 5874#ifdef HAVE_LSTAT 5875 if ((*path == '/' || !hard) && 5876 (d != &ds || hard)){ 5877#else 5878 if (*path == '/') { 5879#endif 5880 level = -1; 5881#ifndef HAVE_FCHDIR 5882 if (!d->dirname) 5883 zgetdir(d); 5884#endif 5885 } else { 5886 level = 0; 5887 if (!d->dev && !d->ino) { 5888 stat(".", &st1); 5889 d->dev = st1.st_dev; 5890 d->ino = st1.st_ino; 5891 } 5892 } 5893 5894#ifdef HAVE_LSTAT 5895 if (!hard) 5896#endif 5897 { 5898 if (d != &ds) { 5899 for (pptr = path; *pptr; level++) { 5900 while (*pptr && *pptr++ != '/'); 5901 while (*pptr == '/') 5902 pptr++; 5903 } 5904 d->level = level; 5905 } 5906 return zchdir((char *) path); 5907 } 5908 5909#ifdef HAVE_LSTAT 5910#ifdef HAVE_FCHDIR 5911 if (d->dirfd < 0) { 5912 close_dir = 1; 5913 if ((d->dirfd = open(".", O_RDONLY | O_NOCTTY)) < 0 && 5914 zgetdir(d) && *d->dirname != '/') 5915 d->dirfd = open("..", O_RDONLY | O_NOCTTY); 5916 } 5917#endif 5918 if (*path == '/') 5919 if (chdir("/") < 0) 5920 zwarn("failed to chdir(/): %e", errno); 5921 for(;;) { 5922 while(*path == '/') 5923 path++; 5924 if(!*path) { 5925 if (d == &ds) 5926 zsfree(ds.dirname); 5927 else 5928 d->level = level; 5929#ifdef HAVE_FCHDIR 5930 if (d->dirfd >=0 && close_dir) { 5931 close(d->dirfd); 5932 d->dirfd = -1; 5933 } 5934#endif 5935 return 0; 5936 } 5937 for(pptr = path; *++pptr && *pptr != '/'; ) ; 5938 if(pptr - path > PATH_MAX) { 5939 err = ENAMETOOLONG; 5940 break; 5941 } 5942 for(ptr = buf; path != pptr; ) 5943 *ptr++ = *path++; 5944 *ptr = 0; 5945 if(lstat(buf, &st1)) { 5946 err = errno; 5947 break; 5948 } 5949 if(!S_ISDIR(st1.st_mode)) { 5950 err = ENOTDIR; 5951 break; 5952 } 5953 if(chdir(buf)) { 5954 err = errno; 5955 break; 5956 } 5957 if (level >= 0) 5958 level++; 5959 if(lstat(".", &st2)) { 5960 err = errno; 5961 break; 5962 } 5963 if(st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) { 5964 err = ENOTDIR; 5965 break; 5966 } 5967 } 5968 if (restoredir(d)) { 5969 int restoreerr = errno; 5970 int i; 5971 /* 5972 * Failed to restore the directory. 5973 * Just be definite, cd to root and report the result. 5974 */ 5975 for (i = 0; i < 2; i++) { 5976 const char *cdest; 5977 if (i) 5978 cdest = "/"; 5979 else { 5980 if (!home) 5981 continue; 5982 cdest = home; 5983 } 5984 zsfree(pwd); 5985 pwd = ztrdup(cdest); 5986 if (chdir(pwd) == 0) 5987 break; 5988 } 5989 if (i == 2) 5990 zerr("lost current directory, failed to cd to /: %e", errno); 5991 else 5992 zerr("lost current directory: %e: changed to `%s'", restoreerr, 5993 pwd); 5994 if (d == &ds) 5995 zsfree(ds.dirname); 5996#ifdef HAVE_FCHDIR 5997 if (d->dirfd >=0 && close_dir) { 5998 close(d->dirfd); 5999 d->dirfd = -1; 6000 } 6001#endif 6002 errno = err; 6003 return -2; 6004 } 6005 if (d == &ds) 6006 zsfree(ds.dirname); 6007#ifdef HAVE_FCHDIR 6008 if (d->dirfd >=0 && close_dir) { 6009 close(d->dirfd); 6010 d->dirfd = -1; 6011 } 6012#endif 6013 errno = err; 6014 return -1; 6015#endif /* HAVE_LSTAT */ 6016} 6017 6018/**/ 6019mod_export int 6020restoredir(struct dirsav *d) 6021{ 6022 int err = 0; 6023 struct stat sbuf; 6024 6025 if (d->dirname && *d->dirname == '/') 6026 return chdir(d->dirname); 6027#ifdef HAVE_FCHDIR 6028 if (d->dirfd >= 0) { 6029 if (!fchdir(d->dirfd)) { 6030 if (!d->dirname) { 6031 return 0; 6032 } else if (chdir(d->dirname)) { 6033 close(d->dirfd); 6034 d->dirfd = -1; 6035 err = -2; 6036 } 6037 } else { 6038 close(d->dirfd); 6039 d->dirfd = err = -1; 6040 } 6041 } else 6042#endif 6043 if (d->level > 0) 6044 err = upchdir(d->level); 6045 else if (d->level < 0) 6046 err = -1; 6047 if (d->dev || d->ino) { 6048 stat(".", &sbuf); 6049 if (sbuf.st_ino != d->ino || sbuf.st_dev != d->dev) 6050 err = -2; 6051 } 6052 return err; 6053} 6054 6055 6056/* Check whether the shell is running with privileges in effect. * 6057 * This is the case if EITHER the euid is zero, OR (if the system * 6058 * supports POSIX.1e (POSIX.6) capability sets) the process' * 6059 * Effective or Inheritable capability sets are non-empty. */ 6060 6061/**/ 6062int 6063privasserted(void) 6064{ 6065 if(!geteuid()) 6066 return 1; 6067#ifdef HAVE_CAP_GET_PROC 6068 { 6069 cap_t caps = cap_get_proc(); 6070 if(caps) { 6071 /* POSIX doesn't define a way to test whether a capability set * 6072 * is empty or not. Typical. I hope this is conforming... */ 6073 cap_flag_value_t val; 6074 cap_value_t n; 6075 for(n = 0; !cap_get_flag(caps, n, CAP_EFFECTIVE, &val); n++) 6076 if(val) { 6077 cap_free(caps); 6078 return 1; 6079 } 6080 } 6081 cap_free(caps); 6082 } 6083#endif /* HAVE_CAP_GET_PROC */ 6084 return 0; 6085} 6086 6087/**/ 6088mod_export int 6089mode_to_octal(mode_t mode) 6090{ 6091 int m = 0; 6092 6093 if(mode & S_ISUID) 6094 m |= 04000; 6095 if(mode & S_ISGID) 6096 m |= 02000; 6097 if(mode & S_ISVTX) 6098 m |= 01000; 6099 if(mode & S_IRUSR) 6100 m |= 00400; 6101 if(mode & S_IWUSR) 6102 m |= 00200; 6103 if(mode & S_IXUSR) 6104 m |= 00100; 6105 if(mode & S_IRGRP) 6106 m |= 00040; 6107 if(mode & S_IWGRP) 6108 m |= 00020; 6109 if(mode & S_IXGRP) 6110 m |= 00010; 6111 if(mode & S_IROTH) 6112 m |= 00004; 6113 if(mode & S_IWOTH) 6114 m |= 00002; 6115 if(mode & S_IXOTH) 6116 m |= 00001; 6117 return m; 6118} 6119 6120#ifdef MAILDIR_SUPPORT 6121/* 6122 * Stat a file. If it's a maildir, check all messages 6123 * in the maildir and present the grand total as a file. 6124 * The fields in the 'struct stat' are from the mail directory. 6125 * The following fields are emulated: 6126 * 6127 * st_nlink always 1 6128 * st_size total number of bytes in all files 6129 * st_blocks total number of messages 6130 * st_atime access time of newest file in maildir 6131 * st_mtime modify time of newest file in maildir 6132 * st_mode S_IFDIR changed to S_IFREG 6133 * 6134 * This is good enough for most mail-checking applications. 6135 */ 6136 6137/**/ 6138int 6139mailstat(char *path, struct stat *st) 6140{ 6141 DIR *dd; 6142 struct dirent *fn; 6143 struct stat st_ret, st_tmp; 6144 static struct stat st_ret_last; 6145 char *dir, *file = 0; 6146 int i; 6147 time_t atime = 0, mtime = 0; 6148 size_t plen = strlen(path), dlen; 6149 6150 /* First see if it's a directory. */ 6151 if ((i = stat(path, st)) != 0 || !S_ISDIR(st->st_mode)) 6152 return i; 6153 6154 st_ret = *st; 6155 st_ret.st_nlink = 1; 6156 st_ret.st_size = 0; 6157 st_ret.st_blocks = 0; 6158 st_ret.st_mode &= ~S_IFDIR; 6159 st_ret.st_mode |= S_IFREG; 6160 6161 /* See if cur/ is present */ 6162 dir = appstr(ztrdup(path), "/cur"); 6163 if (stat(dir, &st_tmp) || !S_ISDIR(st_tmp.st_mode)) return 0; 6164 st_ret.st_atime = st_tmp.st_atime; 6165 6166 /* See if tmp/ is present */ 6167 dir[plen] = 0; 6168 dir = appstr(dir, "/tmp"); 6169 if (stat(dir, &st_tmp) || !S_ISDIR(st_tmp.st_mode)) return 0; 6170 st_ret.st_mtime = st_tmp.st_mtime; 6171 6172 /* And new/ */ 6173 dir[plen] = 0; 6174 dir = appstr(dir, "/new"); 6175 if (stat(dir, &st_tmp) || !S_ISDIR(st_tmp.st_mode)) return 0; 6176 st_ret.st_mtime = st_tmp.st_mtime; 6177 6178#if THERE_IS_EXACTLY_ONE_MAILDIR_IN_MAILPATH 6179 { 6180 static struct stat st_new_last; 6181 /* Optimization - if new/ didn't change, nothing else did. */ 6182 if (st_tmp.st_dev == st_new_last.st_dev && 6183 st_tmp.st_ino == st_new_last.st_ino && 6184 st_tmp.st_atime == st_new_last.st_atime && 6185 st_tmp.st_mtime == st_new_last.st_mtime) { 6186 *st = st_ret_last; 6187 return 0; 6188 } 6189 st_new_last = st_tmp; 6190 } 6191#endif 6192 6193 /* Loop over new/ and cur/ */ 6194 for (i = 0; i < 2; i++) { 6195 dir[plen] = 0; 6196 dir = appstr(dir, i ? "/cur" : "/new"); 6197 if ((dd = opendir(dir)) == NULL) { 6198 zsfree(file); 6199 zsfree(dir); 6200 return 0; 6201 } 6202 dlen = strlen(dir) + 1; /* include the "/" */ 6203 while ((fn = readdir(dd)) != NULL) { 6204 if (fn->d_name[0] == '.') 6205 continue; 6206 if (file) { 6207 file[dlen] = 0; 6208 file = appstr(file, fn->d_name); 6209 } else { 6210 file = tricat(dir, "/", fn->d_name); 6211 } 6212 if (stat(file, &st_tmp) != 0) 6213 continue; 6214 st_ret.st_size += st_tmp.st_size; 6215 st_ret.st_blocks++; 6216 if (st_tmp.st_atime != st_tmp.st_mtime && 6217 st_tmp.st_atime > atime) 6218 atime = st_tmp.st_atime; 6219 if (st_tmp.st_mtime > mtime) 6220 mtime = st_tmp.st_mtime; 6221 } 6222 closedir(dd); 6223 } 6224 zsfree(file); 6225 zsfree(dir); 6226 6227 if (atime) st_ret.st_atime = atime; 6228 if (mtime) st_ret.st_mtime = mtime; 6229 6230 *st = st_ret_last = st_ret; 6231 return 0; 6232} 6233#endif 6234