diff options
Diffstat (limited to 'Src/utils.c')
-rw-r--r-- | Src/utils.c | 321 |
1 files changed, 233 insertions, 88 deletions
diff --git a/Src/utils.c b/Src/utils.c index 28e78c149..579ab3be8 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -84,7 +84,15 @@ set_widearray(char *mb_array, Widechar_array wca) mb_charinit(); while (*mb_array) { - int mblen = mb_metacharlenconv(mb_array, &wci); + int mblen; + + if (STOUC(*mb_array) <= 0x7f) { + mb_array++; + *wcptr++ = (wchar_t)*mb_array; + continue; + } + + mblen = mb_metacharlenconv(mb_array, &wci); if (!mblen) break; @@ -621,7 +629,7 @@ wcs_nicechar_sel(wchar_t c, size_t *widthp, char **swidep, int quotable) } s = buf; - if (!iswprint(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) { + if (!WC_ISPRINT(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) { if (c == 0x7f) { if (quotable) { *s++ = '\\'; @@ -726,7 +734,7 @@ wcs_nicechar(wchar_t c, size_t *widthp, char **swidep) /**/ mod_export int is_wcs_nicechar(wchar_t c) { - if (!iswprint(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) { + if (!WC_ISPRINT(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) { if (c == 0x7f || c == L'\n' || c == L'\t' || c < 0x20) return 1; if (c >= 0x80) { @@ -801,9 +809,9 @@ findpwd(char *s) char *t; if (*s == '/') - return xsymlink(s); + return xsymlink(s, 0); s = tricat((pwd[1]) ? pwd : "", "/", s); - t = xsymlink(s); + t = xsymlink(s, 0); zsfree(s); return t; } @@ -837,7 +845,7 @@ ispwd(char *s) return 0; } -static char xbuf[PATH_MAX*2]; +static char xbuf[PATH_MAX*2+1]; /**/ static char ** @@ -876,9 +884,9 @@ static int xsymlinks(char *s, int full) { char **pp, **opp; - char xbuf2[PATH_MAX*3], xbuf3[PATH_MAX*2]; + char xbuf2[PATH_MAX*3+1], xbuf3[PATH_MAX*2+1]; int t0, ret = 0; - zulong xbuflen = strlen(xbuf); + zulong xbuflen = strlen(xbuf), pplen; opp = pp = slashsplit(s); for (; xbuflen < sizeof(xbuf) && *pp && ret >= 0; pp++) { @@ -899,10 +907,18 @@ xsymlinks(char *s, int full) xbuflen--; continue; } - sprintf(xbuf2, "%s/%s", xbuf, *pp); + /* Includes null byte. */ + pplen = strlen(*pp) + 1; + if (xbuflen + pplen + 1 > sizeof(xbuf2)) { + *xbuf = 0; + ret = -1; + break; + } + memcpy(xbuf2, xbuf, xbuflen); + xbuf2[xbuflen] = '/'; + memcpy(xbuf2 + xbuflen + 1, *pp, pplen); t0 = readlink(unmeta(xbuf2), xbuf3, PATH_MAX); if (t0 == -1) { - zulong pplen = strlen(*pp) + 1; if ((xbuflen += pplen) < sizeof(xbuf)) { strcat(xbuf, "/"); strcat(xbuf, *pp); @@ -969,11 +985,13 @@ xsymlinks(char *s, int full) /* * expand symlinks in s, and remove other weird things: * note that this always expands symlinks. + * + * 'heap' indicates whether to malloc() or allocate on the heap. */ /**/ char * -xsymlink(char *s) +xsymlink(char *s, int heap) { if (*s != '/') return NULL; @@ -981,8 +999,8 @@ xsymlink(char *s) if (xsymlinks(s + 1, 1) < 0) zwarn("path expansion failed, using root directory"); if (!*xbuf) - return ztrdup("/"); - return ztrdup(xbuf); + return heap ? dupstring("/") : ztrdup("/"); + return heap ? dupstring(xbuf) : ztrdup(xbuf); } /**/ @@ -993,7 +1011,7 @@ print_if_link(char *s, int all) *xbuf = '\0'; if (all) { char *start = s + 1; - char xbuflink[PATH_MAX]; + char xbuflink[PATH_MAX+1]; for (;;) { if (xsymlinks(start, 0) > 0) { printf(" -> "); @@ -1045,9 +1063,9 @@ substnamedir(char *s) Nameddir d = finddir(s); if (!d) - return quotestring(s, NULL, QT_BACKSLASH); + return quotestring(s, QT_BACKSLASH); return zhtricat("~", d->node.nam, quotestring(s + strlen(d->dir), - NULL, QT_BACKSLASH)); + QT_BACKSLASH)); } @@ -1130,7 +1148,7 @@ finddir(char *s) if(homenode.diff==1) homenode.diff = 0; if(!finddir_full) - finddir_full = zalloc(ffsz = PATH_MAX); + finddir_full = zalloc(ffsz = PATH_MAX+1); finddir_full[0] = 0; return finddir_last = NULL; } @@ -1157,7 +1175,7 @@ finddir(char *s) scanhashtable(nameddirtab, 0, 0, 0, finddir_scan, 0); ares = subst_string_by_hook("zsh_directory_name", "d", finddir_full); - if (ares && arrlen(ares) >= 2 && + if (ares && arrlen_ge(ares, 2) && (len = (int)zstrtol(ares[1], NULL, 10)) > finddir_best) { /* better duplicate this string since it's come from REPLY */ finddir_last = (Nameddir)hcalloc(sizeof(struct nameddir)); @@ -1220,13 +1238,13 @@ adduserdir(char *s, char *t, int flags, int always) * named directory, since these are sometimes used for * special purposes. */ - nd->dir = ztrdup(t); + nd->dir = metafy(t, -1, META_DUP); } else - nd->dir = ztrduppfx(t, eptr - t); + nd->dir = metafy(t, eptr - t, META_DUP); /* The variables PWD and OLDPWD are not to be displayed as ~PWD etc. */ if (!strcmp(s, "PWD") || !strcmp(s, "OLDPWD")) nd->node.flags |= ND_NOABBREV; - nameddirtab->addnode(nameddirtab, ztrdup(s), nd); + nameddirtab->addnode(nameddirtab, metafy(s, -1, META_DUP), nd); } /* Get a named directory: this function can cause a directory name * @@ -1260,7 +1278,7 @@ getnameddir(char *name) /* Retrieve an entry from the password table/database for this user. */ struct passwd *pw; if ((pw = getpwnam(name))) { - char *dir = isset(CHASELINKS) ? xsymlink(pw->pw_dir) + char *dir = isset(CHASELINKS) ? xsymlink(pw->pw_dir, 0) : ztrdup(pw->pw_dir); if (dir) { adduserdir(name, dir, ND_USERNAME, 1); @@ -1634,7 +1652,7 @@ checkmailpath(char **s) } else if (S_ISDIR(st.st_mode)) { LinkList l; DIR *lock = opendir(unmeta(*s)); - char buf[PATH_MAX * 2], **arr, **ap; + char buf[PATH_MAX * 2 + 1], **arr, **ap; int ct = 1; if (lock) { @@ -2162,6 +2180,7 @@ gettempfile(const char *prefix, int use_heap, char **tempname) #if HAVE_MKSTEMP char *suffix = prefix ? ".XXXXXX" : "XXXXXX"; + queue_signals(); if (!prefix && !(prefix = getsparam("TMPPREFIX"))) prefix = DEFAULT_TMPPREFIX; if (use_heap) @@ -2178,6 +2197,7 @@ gettempfile(const char *prefix, int use_heap, char **tempname) #else int failures = 0; + queue_signals(); do { if (!(fn = gettempname(prefix, use_heap))) { fd = -1; @@ -2191,6 +2211,8 @@ gettempfile(const char *prefix, int use_heap, char **tempname) } while (errno == EEXIST && ++failures < 16); #endif *tempname = fn; + + unqueue_signals(); return fd; } @@ -2280,6 +2302,46 @@ arrlen(char **s) return count; } +/* Return TRUE iff arrlen(s) >= lower_bound, but more efficiently. */ + +/**/ +mod_export char +arrlen_ge(char **s, unsigned lower_bound) +{ + while (lower_bound--) + if (!*s++) + return 0 /* FALSE */; + + return 1 /* TRUE */; +} + +/* Return TRUE iff arrlen(s) > lower_bound, but more efficiently. */ + +/**/ +mod_export char +arrlen_gt(char **s, unsigned lower_bound) +{ + return arrlen_ge(s, 1+lower_bound); +} + +/* Return TRUE iff arrlen(s) <= upper_bound, but more efficiently. */ + +/**/ +mod_export char +arrlen_le(char **s, unsigned upper_bound) +{ + return arrlen_lt(s, 1+upper_bound); +} + +/* Return TRUE iff arrlen(s) < upper_bound, but more efficiently. */ + +/**/ +mod_export char +arrlen_lt(char **s, unsigned upper_bound) +{ + return !arrlen_ge(s, upper_bound); +} + /* Skip over a balanced pair of parenthesis. */ /**/ @@ -2322,7 +2384,7 @@ zstrtol_underscore(const char *s, char **t, int base, int underscore) while (inblank(*s)) s++; - if ((neg = (*s == '-'))) + if ((neg = IS_DASH(*s))) s++; else if (*s == '+') s++; @@ -2534,7 +2596,7 @@ read_poll(int fd, int *readchar, int polltty, zlong microseconds) #endif #endif - if (fd >= 0 && ret < 0) { + if (fd >= 0 && ret < 0 && !errflag) { /* * Final attempt: set non-blocking read and try to read a character. * Praise Bill, this works under Cygwin (nothing else seems to). @@ -2890,9 +2952,7 @@ mod_export void spckword(char **s, int hist, int cmd, int ask) { char *t, *correct_ignore; - int x; char ic = '\0'; - int ne; int preflen = 0; int autocd = cmd && isset(AUTOCD) && strcmp(*s, ".") && strcmp(*s, ".."); @@ -2961,6 +3021,7 @@ spckword(char **s, int hist, int cmd, int ask) } else { guess = *s; if (*guess == Tilde || *guess == String) { + int ne; ic = *guess; if (!*++t) return; @@ -3005,6 +3066,7 @@ spckword(char **s, int hist, int cmd, int ask) if (errflag) return; if (best && (int)strlen(best) > 1 && strcmp(best, guess)) { + int x; if (ic) { char *u; if (preflen) { @@ -3034,14 +3096,14 @@ spckword(char **s, int hist, int cmd, int ask) free(pptbuf); fflush(shout); zbeep(); - x = getquery("nyae \t", 0); + x = getquery("nyae", 0); if (cmd && x == 'n') pathchecked = path; } else x = 'n'; } else x = 'y'; - if (x == 'y' || x == ' ' || x == '\t') { + if (x == 'y') { *s = dupstring(best); if (hist) hwrep(best); @@ -3905,7 +3967,7 @@ inittyptab(void) #endif /* typtab['.'] |= IIDENT; */ /* Allow '.' in variable names - broken */ typtab['_'] = IIDENT | IUSER; - typtab['-'] = typtab['.'] = IUSER; + typtab['-'] = typtab['.'] = typtab[STOUC(Dash)] = IUSER; typtab[' '] |= IBLANK | INBLANK; typtab['\t'] |= IBLANK | INBLANK; typtab['\n'] |= INBLANK; @@ -4103,42 +4165,50 @@ itype_end(const char *ptr, int itype, int once) (itype != IIDENT || !isset(POSIXIDENTIFIERS))) { mb_charinit(); while (*ptr) { - wint_t wc; - int len = mb_metacharlenconv(ptr, &wc); - - if (!len) - break; - - if (wc == WEOF) { - /* invalid, treat as single character */ - int chr = STOUC(*ptr == Meta ? ptr[1] ^ 32 : *ptr); - /* in this case non-ASCII characters can't match */ - if (chr > 127 || !zistype(chr,itype)) - break; - } else if (len == 1 && isascii(*ptr)) { - /* ASCII: can't be metafied, use standard test */ + int len; + if (itok(*ptr)) { + /* Not untokenised yet --- can happen in raw command line */ + len = 1; if (!zistype(*ptr,itype)) break; } else { - /* - * Valid non-ASCII character. - */ - switch (itype) { - case IWORD: - if (!iswalnum(wc) && - !wmemchr(wordchars_wide.chars, wc, - wordchars_wide.len)) - return (char *)ptr; - break; + wint_t wc; + len = mb_metacharlenconv(ptr, &wc); - case ISEP: - if (!wmemchr(ifs_wide.chars, wc, ifs_wide.len)) - return (char *)ptr; + if (!len) break; - default: - if (!iswalnum(wc)) - return (char *)ptr; + if (wc == WEOF) { + /* invalid, treat as single character */ + int chr = STOUC(*ptr == Meta ? ptr[1] ^ 32 : *ptr); + /* in this case non-ASCII characters can't match */ + if (chr > 127 || !zistype(chr,itype)) + break; + } else if (len == 1 && isascii(*ptr)) { + /* ASCII: can't be metafied, use standard test */ + if (!zistype(*ptr,itype)) + break; + } else { + /* + * Valid non-ASCII character. + */ + switch (itype) { + case IWORD: + if (!iswalnum(wc) && + !wmemchr(wordchars_wide.chars, wc, + wordchars_wide.len)) + return (char *)ptr; + break; + + case ISEP: + if (!wmemchr(ifs_wide.chars, wc, ifs_wide.len)) + return (char *)ptr; + break; + + default: + if (!iswalnum(wc)) + return (char *)ptr; + } } } ptr += len; @@ -4183,6 +4253,32 @@ arrdup(char **s) return y; } +/* Duplicate at most max elements of the array s with heap memory */ + +/**/ +mod_export char ** +arrdup_max(char **s, unsigned max) +{ + char **x, **y, **send; + int len = 0; + + if (max) + len = arrlen(s); + + /* Limit has sense only if not equal to len */ + if (max > len) + max = len; + + y = x = (char **) zhalloc(sizeof(char *) * (max + 1)); + + send = s + max; + while (s < send) + *x++ = dupstring(*s++); + *x = NULL; + + return y; +} + /**/ mod_export char ** zarrdup(char **s) @@ -4700,6 +4796,41 @@ unmeta(const char *file_name) } /* + * Unmetafy just one character and store the number of bytes it occupied. + */ +/**/ +mod_export convchar_t +unmeta_one(const char *in, int *sz) +{ + convchar_t wc; + int newsz; +#ifdef MULTIBYTE_SUPPORT + mbstate_t wstate; +#endif + + if (!sz) + sz = &newsz; + *sz = 0; + + if (!in || !*in) + return 0; + +#ifdef MULTIBYTE_SUPPORT + memset(&wstate, 0, sizeof(wstate)); + *sz = mb_metacharlenconv_r(in, &wc, &wstate); +#else + if (in[0] == Meta) { + *sz = 2; + wc = STOUC(in[1] ^ 32); + } else { + *sz = 1; + wc = STOUC(in[0]); + } +#endif + return wc; +} + +/* * Unmetafy and compare two strings, comparing unsigned character values. * "a\0" sorts after "a". * @@ -5040,8 +5171,10 @@ mb_niceformat(const char *s, FILE *stream, char **outstrp, int flags) cnt = 1; /* FALL THROUGH */ default: - if (c == L'\'' && (flags & NICEFLAG_QUOTE)) + if (c == L'\'' && (flags & NICEFLAG_QUOTE)) { fmt = "\\'"; + newl = 2; + } else fmt = wcs_nicechar_sel(c, &newl, NULL, flags & NICEFLAG_QUOTE); break; @@ -5176,6 +5309,12 @@ mb_metacharlenconv_r(const char *s, wint_t *wcp, mbstate_t *mbsp) const char *ptr; wchar_t wc; + if (STOUC(*s) <= 0x7f) { + if (wcp) + *wcp = (wint_t)*s; + return 1; + } + for (ptr = s; *ptr; ) { if (*ptr == Meta) { inchar = *++ptr ^ 32; @@ -5228,7 +5367,7 @@ mb_metacharlenconv_r(const char *s, wint_t *wcp, mbstate_t *mbsp) mod_export int mb_metacharlenconv(const char *s, wint_t *wcp) { - if (!isset(MULTIBYTE)) { + if (!isset(MULTIBYTE) || STOUC(*s) <= 0x7f) { /* treat as single byte, possibly metafied */ if (wcp) *wcp = (wint_t)(*s == Meta ? s[1] ^ 32 : *s); @@ -5275,7 +5414,7 @@ mb_metastrlenend(char *ptr, int width, char *eptr) char inchar, *laststart; size_t ret; wchar_t wc; - int num, num_in_char; + int num, num_in_char, complete; if (!isset(MULTIBYTE)) return ztrlen(ptr); @@ -5283,6 +5422,7 @@ mb_metastrlenend(char *ptr, int width, char *eptr) laststart = ptr; ret = MB_INVALID; num = num_in_char = 0; + complete = 1; memset(&mb_shiftstate, 0, sizeof(mb_shiftstate)); while (*ptr && !(eptr && ptr >= eptr)) { @@ -5291,6 +5431,18 @@ mb_metastrlenend(char *ptr, int width, char *eptr) else inchar = *ptr; ptr++; + + if (complete && STOUC(inchar) <= STOUC(0x7f)) { + /* + * We rely on 7-bit US-ASCII as a subset, so skip + * multibyte handling if we have such a character. + */ + num++; + laststart = ptr; + num_in_char = 0; + continue; + } + ret = mbrtowc(&wc, &inchar, 1, &mb_shiftstate); if (ret == MB_INCOMPLETE) { @@ -5310,6 +5462,7 @@ mb_metastrlenend(char *ptr, int width, char *eptr) * so we don't count characters twice. */ num_in_char++; + complete = 0; } else { if (ret == MB_INVALID) { /* Reset, treat as single character */ @@ -5332,6 +5485,7 @@ mb_metastrlenend(char *ptr, int width, char *eptr) num++; laststart = ptr; num_in_char = 0; + complete = 1; } } @@ -5354,6 +5508,12 @@ mb_charlenconv_r(const char *s, int slen, wint_t *wcp, mbstate_t *mbsp) const char *ptr; wchar_t wc; + if (slen && STOUC(*s) <= 0x7f) { + if (wcp) + *wcp = (wint_t)*s; + return 1; + } + for (ptr = s; slen; ) { inchar = *ptr; ptr++; @@ -5389,7 +5549,7 @@ mb_charlenconv_r(const char *s, int slen, wint_t *wcp, mbstate_t *mbsp) mod_export int mb_charlenconv(const char *s, int slen, wint_t *wcp) { - if (!isset(MULTIBYTE)) { + if (!isset(MULTIBYTE) || STOUC(*s) <= 0x7f) { if (wcp) *wcp = (wint_t)*s; return 1; @@ -5605,10 +5765,6 @@ addunprintable(char *v, const char *u, const char *uend) /* * Quote the string s and return the result as a string from the heap. * - * If e is non-zero, the - * pointer it points to may point to a position in s and in e the position - * of the corresponding character in the quoted string is returned. - * * The last argument is a QT_ value defined in zsh.h other than QT_NONE. * * Most quote styles other than backslash assume the quotes are to @@ -5621,13 +5777,13 @@ addunprintable(char *v, const char *u, const char *uend) /**/ mod_export char * -quotestring(const char *s, char **e, int instring) +quotestring(const char *s, int instring) { const char *u; char *v; int alloclen; char *buf; - int sf = 0, shownull = 0; + int shownull = 0; /* * quotesub is used with QT_SINGLE_OPTIONAL. * quotesub = 0: mechanism not active @@ -5698,10 +5854,6 @@ quotestring(const char *s, char **e, int instring) while (*u) { uend = u + MB_METACHARLENCONV(u, &cc); - if (e && !sf && *e <= u) { - *e = v; - sf = 1; - } if ( #ifdef MULTIBYTE_SUPPORT cc != WEOF && @@ -5728,11 +5880,6 @@ quotestring(const char *s, char **e, int instring) } } else if (instring == QT_BACKSLASH_PATTERN) { while (*u) { - if (e && !sf && *e == u) { - *e = v; - sf = 1; - } - if (ipattern(*u)) *v++ = '\\'; *v++ = *u++; @@ -5751,8 +5898,6 @@ quotestring(const char *s, char **e, int instring) */ while (*u) { int dobackslash = 0; - if (e && *e == u) - *e = v, sf = 1; if (*u == Tick || *u == Qtick) { char c = *u++; @@ -5940,10 +6085,6 @@ quotestring(const char *s, char **e, int instring) *v++ = '\''; *v = '\0'; - if (e && *e == u) - *e = v, sf = 1; - DPUTS(e && !sf, "BUG: Wild pointer *e in quotestring()"); - v = dupstring(buf); zfree(buf, alloclen); return v; @@ -6020,7 +6161,9 @@ quotedzputs(char const *s, FILE *stream) } else *ptr++ = '\''; while(*s) { - if (*s == Meta) + if (*s == Dash) + c = '-'; + else if (*s == Meta) c = *++s ^ 32; else c = *s; @@ -6057,7 +6200,9 @@ quotedzputs(char const *s, FILE *stream) } else { /* use Bourne-style quoting, avoiding empty quoted strings */ while (*s) { - if (*s == Meta) + if (*s == Dash) + c = '-'; + else if (*s == Meta) c = *++s ^ 32; else c = *s; @@ -6818,7 +6963,7 @@ strsfx(char *s, char *t) static int upchdir(int n) { - char buf[PATH_MAX]; + char buf[PATH_MAX+1]; char *s; int err = -1; |