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, &umlen);
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, &umlen);
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