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