diff options
author | Axel Beckert <abe@deuxchevaux.org> | 2015-08-22 01:55:58 +0200 |
---|---|---|
committer | Axel Beckert <abe@deuxchevaux.org> | 2015-08-22 01:55:58 +0200 |
commit | 02f6e25bfcd5feb9a093377dda0dd549cdf5c309 (patch) | |
tree | 9a25e61122b3fa0d0a1ff68b5ef05c775ff78b1e /Src/utils.c | |
parent | e04a19735ffc8523b93b33074f685ad4e2c92e0c (diff) | |
parent | 881474edcb223ac22a08d81a824809c33ca3a9c9 (diff) | |
download | zsh-02f6e25bfcd5feb9a093377dda0dd549cdf5c309.tar.gz zsh-02f6e25bfcd5feb9a093377dda0dd549cdf5c309.zip |
Merge tag 'zsh-5.0.8-test-2' into debian
Diffstat (limited to 'Src/utils.c')
-rw-r--r-- | Src/utils.c | 387 |
1 files changed, 342 insertions, 45 deletions
diff --git a/Src/utils.c b/Src/utils.c index 271c800fd..4c4dc55cd 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -82,7 +82,7 @@ set_widearray(char *mb_array, Widechar_array wca) wchar_t *wcptr = tmpwcs; wint_t wci; - mb_metacharinit(); + mb_charinit(); while (*mb_array) { int mblen = mb_metacharlenconv(mb_array, &wci); @@ -248,7 +248,7 @@ VA_DCL VA_START(ap, message); VA_GET_ARG(ap, message, const char *); - if ((filename = getsparam("ZSH_DEBUG_LOG")) != NULL && + if ((filename = getsparam_u("ZSH_DEBUG_LOG")) != NULL && (file = fopen(filename, "a")) != NULL) { zerrmsg(file, message, ap); fclose(file); @@ -332,7 +332,7 @@ zerrmsg(FILE *file, const char *fmt, va_list ap) case 'c': num = va_arg(ap, int); #ifdef MULTIBYTE_SUPPORT - mb_metacharinit(); + mb_charinit(); zputs(wcs_nicechar(num, NULL, NULL), file); #else zputs(nicechar(num), file); @@ -461,12 +461,13 @@ static mbstate_t mb_shiftstate; /* * Initialise multibyte state: called before a sequence of - * wcs_nicechar() or mb_metacharlenconv(). + * wcs_nicechar(), mb_metacharlenconv(), or + * mb_charlenconv(). */ /**/ mod_export void -mb_metacharinit(void) +mb_charinit(void) { memset(&mb_shiftstate, 0, sizeof(mb_shiftstate)); } @@ -500,7 +501,7 @@ mb_metacharinit(void) * (but not both). (Note the complication that the wide character * part may contain metafied characters.) * - * The caller needs to call mb_metacharinit() before the first call, to + * The caller needs to call mb_charinit() before the first call, to * set up the multibyte shift state for a range of characters. */ @@ -1948,7 +1949,8 @@ extern char *_mktemp(char *); /* Get a unique filename for use as a temporary file. If "prefix" is * NULL, the name is relative to $TMPPREFIX; If it is non-NULL, the * unique suffix includes a prefixed '.' for improved readability. If - * "use_heap" is true, we allocate the returned name on the heap. */ + * "use_heap" is true, we allocate the returned name on the heap. + * The string passed as "prefix" is expected to be metafied. */ /**/ mod_export char * @@ -1975,6 +1977,9 @@ gettempname(const char *prefix, int use_heap) return ret; } +/* The gettempfile() "prefix" is expected to be metafied, see hist.c + * and gettempname(). */ + /**/ mod_export int gettempfile(const char *prefix, int use_heap, char **tempname) @@ -2873,6 +2878,10 @@ ztrftimebuf(int *bufsizeptr, int decr) * not enough memory --- and return -1. Not guaranteed to be portable, * since the strftime() interface doesn't make any guarantees about * the state of the buffer if it returns zero. + * + * fmt is metafied, but we need to unmetafy it on the fly to + * pass into strftime / combine with the output from strftime. + * The return value in buf is not metafied. */ /**/ @@ -2882,7 +2891,7 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) int hr12; #ifdef HAVE_STRFTIME int decr; - char tmp[4]; + char *fmtstart; #else static char *astr[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; @@ -2893,12 +2902,22 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) char *origbuf = buf; - while (*fmt) - if (*fmt == '%') { + while (*fmt) { + if (*fmt == Meta) { + int chr = fmt[1] ^ 32; + if (ztrftimebuf(&bufsize, 1)) + return -1; + *buf++ = chr; + fmt += 2; + } else if (*fmt == '%') { int strip; int digs = 3; +#ifdef HAVE_STRFTIME + fmtstart = +#endif fmt++; + if (*fmt == '-') { strip = 1; fmt++; @@ -2923,6 +2942,21 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) */ if (ztrftimebuf(&bufsize, 2)) return -1; +#ifdef HAVE_STRFTIME + /* Our internal handling doesn't handle padding and other gnu extensions, + * so here we detect them and pass over to strftime(). We don't want + * to do this unconditionally though, as we have some extensions that + * strftime() doesn't have (%., %f, %L and %K) */ +morefmt: + if (!((fmt - fmtstart == 1) || (fmt - fmtstart == 2 && strip) || *fmt == '.')) { + while (*fmt && strchr("OE^#_-0123456789", *fmt)) + fmt++; + if (*fmt) { + fmt++; + goto strftimehandling; + } + } +#endif switch (*fmt++) { case '.': if (ztrftimebuf(&bufsize, digs)) @@ -2938,10 +2972,10 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) sprintf(buf, "%0*ld", digs, usec); buf += digs; break; - case 'd': - if (tm->tm_mday > 9 || !strip) - *buf++ = '0' + tm->tm_mday / 10; - *buf++ = '0' + tm->tm_mday % 10; + case '\0': + /* Guard against premature end of string */ + *buf++ = '%'; + fmt--; break; case 'f': strip = 1; @@ -2982,6 +3016,11 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) *buf++ = '0' + (hr12 % 10); break; + case 'd': + if (tm->tm_mday > 9 || !strip) + *buf++ = '0' + tm->tm_mday / 10; + *buf++ = '0' + tm->tm_mday % 10; + break; case 'm': if (tm->tm_mon > 8 || !strip) *buf++ = '0' + (tm->tm_mon + 1) / 10; @@ -3002,18 +3041,9 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) *buf++ = '0' + (tm->tm_year / 10) % 10; *buf++ = '0' + tm->tm_year % 10; break; - case '\0': - /* Guard against premature end of string */ - *buf++ = '%'; - fmt--; - break; #ifndef HAVE_STRFTIME case 'Y': { - /* - * Not worth handling this natively if - * strftime has it. - */ int year, digits, testyear; year = tm->tm_year + 1900; digits = 1; @@ -3047,24 +3077,51 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) if (fmt[-1] != '%') *buf++ = fmt[-1]; #else + case 'E': + case 'O': + case '^': + case '#': + case '_': + case '-': + case '0' ... '9': + goto morefmt; +strftimehandling: default: /* * Remember we've already allowed for two characters * in the accounting in bufsize (but nowhere else). */ - *buf = '\1'; - sprintf(tmp, strip ? "%%-%c" : "%%%c", fmt[-1]); - if (!strftime(buf, bufsize + 2, tmp, tm)) { - if (*buf) { - buf[0] = '\0'; - return -1; + int size = fmt - fmtstart; + char *tmp, *last; + tmp = zhalloc(size + 1); + strncpy(tmp, fmtstart, size); + last = fmt-1; + if (*last == Meta) { + /* + * This is for consistency in counting: + * a metafiable character isn't actually + * a valid strftime descriptor. + * + * Previous characters were explicitly checked, + * so can't be metafied. + */ + *last = *++fmt ^ 32; + } + tmp[size] = '\0'; + *buf = '\1'; + if (!strftime(buf, bufsize + 2, tmp, tm)) + { + if (*buf) { + buf[0] = '\0'; + return -1; + } + return 0; } - return 0; + decr = strlen(buf); + buf += decr; + bufsize -= decr - 2; } - decr = strlen(buf); - buf += decr; - bufsize -= decr - 2; #endif break; } @@ -3073,6 +3130,7 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec) return -1; *buf++ = *fmt++; } + } *buf = '\0'; return buf - origbuf; } @@ -3555,7 +3613,7 @@ zbeep(void) { char *vb; queue_signals(); - if ((vb = getsparam("ZBEEP"))) { + if ((vb = getsparam_u("ZBEEP"))) { int len; vb = getkeystring(vb, &len, GETKEYS_BINDKEY, NULL); write_loop(SHTTY, vb, len); @@ -3832,7 +3890,7 @@ itype_end(const char *ptr, int itype, int once) #ifdef MULTIBYTE_SUPPORT if (isset(MULTIBYTE) && (itype != IIDENT || !isset(POSIXIDENTIFIERS))) { - mb_metacharinit(); + mb_charinit(); while (*ptr) { wint_t wc; int len = mb_metacharlenconv(ptr, &wc); @@ -4367,7 +4425,10 @@ unmeta(const char *file_name) char *p; const char *t; int newsz, meta; - + + if (!file_name) + return NULL; + meta = 0; for (t = file_name; *t; t++) { if (*t == Meta) @@ -4471,9 +4532,37 @@ ztrlen(char const *s) for (l = 0; *s; l++) { if (*s++ == Meta) { #ifdef DEBUG - if (! *s) + if (! *s) { fprintf(stderr, "BUG: unexpected end of string in ztrlen()\n"); - else + break; + } else +#endif + s++; + } + } + return l; +} + +#ifndef MULTIBYTE_SUPPORT +/* + * ztrlen() but with explicit end point for non-null-terminated + * segments. eptr may not be NULL. + */ + +/**/ +mod_export int +ztrlenend(char const *s, char const *eptr) +{ + int l; + + for (l = 0; s < eptr; l++) { + if (*s++ == Meta) { +#ifdef DEBUG + if (! *s) { + fprintf(stderr, + "BUG: unexpected end of string in ztrlenend()\n"); + break; + } else #endif s++; } @@ -4481,6 +4570,8 @@ ztrlen(char const *s) return l; } +#endif /* MULTIBYTE_SUPPORT */ + /* Subtract two pointers in a metafied string. */ /**/ @@ -4879,11 +4970,16 @@ mb_metacharlenconv(const char *s, wint_t *wcp) * If width is 1, return total character width rather than number. * If width is greater than 1, return 1 if character has non-zero width, * else 0. + * + * Ends if either *ptr is '\0', the normal case (eptr may be NULL for + * this), or ptr is eptr (i.e. *eptr is where the null would be if null + * terminated) for strings not delimited by nulls --- note these are + * still metafied. */ /**/ mod_export int -mb_metastrlen(char *ptr, int width) +mb_metastrlenend(char *ptr, int width, char *eptr) { char inchar, *laststart; size_t ret; @@ -4898,7 +4994,7 @@ mb_metastrlen(char *ptr, int width) num = num_in_char = 0; memset(&mb_shiftstate, 0, sizeof(mb_shiftstate)); - while (*ptr) { + while (*ptr && !(eptr && ptr >= eptr)) { if (*ptr == Meta) inchar = *++ptr ^ 32; else @@ -4937,6 +5033,65 @@ mb_metastrlen(char *ptr, int width) return num + num_in_char; } +/* + * The equivalent of mb_metacharlenconv_r() for + * strings that aren't metafied and hence have + * explicit lengths. + */ + +/**/ +mod_export int +mb_charlenconv_r(const char *s, int slen, wint_t *wcp, mbstate_t *mbsp) +{ + size_t ret = MB_INVALID; + char inchar; + const char *ptr; + wchar_t wc; + + for (ptr = s; slen; ) { + inchar = *ptr; + ptr++; + slen--; + ret = mbrtowc(&wc, &inchar, 1, mbsp); + + if (ret == MB_INVALID) + break; + if (ret == MB_INCOMPLETE) + continue; + if (wcp) + *wcp = wc; + return ptr - s; + } + + if (wcp) + *wcp = WEOF; + /* No valid multibyte sequence */ + memset(mbsp, 0, sizeof(*mbsp)); + if (ptr > s) { + return 1; /* Treat as single byte character */ + } else + return 0; /* Probably shouldn't happen */ +} + +/* + * The equivalent of mb_metacharlenconv() for + * strings that aren't metafied and hence have + * explicit lengths; + */ + +/**/ +mod_export int +mb_charlenconv(const char *s, int slen, wint_t *wcp) +{ + if (!isset(MULTIBYTE)) { + if (wcp) + *wcp = (wint_t)*s; + return 1; + } + + return mb_charlenconv_r(s, slen, wcp, &mb_shiftstate); +} + /**/ #else @@ -4961,8 +5116,127 @@ metacharlenconv(const char *x, int *c) return 1; } +/* Simple replacement for mb_charlenconv */ + /**/ +mod_export int +charlenconv(const char *x, int len, int *c) +{ + if (!len) { + if (c) + *c = '\0'; + return 0; + } + + if (c) + *c = (char)*x; + return 1; +} + +/**/ +#endif /* MULTIBYTE_SUPPORT */ + +/* + * Expand tabs to given width, with given starting position on line. + * len is length of unmetafied string in bytes. + * Output to fout. + * Return the end position on the line, i.e. if this is 0 modulo width + * the next character is aligned with a tab stop. + * + * If all is set, all tabs are expanded, else only leading tabs. + */ + +/**/ +mod_export int +zexpandtabs(const char *s, int len, int width, int startpos, FILE *fout, + int all) +{ + int at_start = 1; + +#ifdef MULTIBYTE_SUPPORT + mbstate_t mbs; + size_t ret; + wchar_t wc; + + memset(&mbs, 0, sizeof(mbs)); +#endif + + while (len) { + if (*s == '\t') { + if (all || at_start) { + s++; + len--; + if (width <= 0 || !(startpos % width)) { + /* always output at least one space */ + fputc(' ', fout); + startpos++; + } + if (width <= 0) + continue; /* paranoia */ + while (startpos % width) { + fputc(' ', fout); + startpos++; + } + } else { + /* + * Leave tab alone. + * Guess width to apply... we might get this wrong. + * This is only needed if there's a following string + * that needs tabs expanding, which is unusual. + */ + startpos += width - startpos % width; + s++; + len--; + fputc('\t', fout); + } + continue; + } else if (*s == '\n' || *s == '\r') { + fputc(*s, fout); + s++; + len--; + startpos = 0; + at_start = 1; + continue; + } + + at_start = 0; +#ifdef MULTIBYTE_SUPPORT + if (isset(MULTIBYTE)) { + const char *sstart = s; + ret = mbrtowc(&wc, s, len, &mbs); + if (ret == MB_INVALID) { + /* Assume single character per character */ + memset(&mbs, 0, sizeof(mbs)); + s++; + len--; + } else if (ret == MB_INCOMPLETE) { + /* incomplete at end --- assume likewise, best we've got */ + s++; + len--; + } else { + s += ret; + len -= (int)ret; + } + if (ret == MB_INVALID || ret == MB_INCOMPLETE) { + startpos++; + } else { + int wcw = WCWIDTH(wc); + if (wcw > 0) /* paranoia */ + startpos += wcw; + } + fwrite(sstart, s - sstart, 1, fout); + + continue; + } #endif /* MULTIBYTE_SUPPORT */ + fputc(*s, fout); + s++; + len--; + startpos++; + } + + return startpos; +} /* check for special characters in the string */ @@ -5301,7 +5575,25 @@ quotestring(const char *s, char **e, int instring) /* Needs to be passed straight through. */ if (dobackslash) *v++ = '\\'; - *v++ = *u++; + if (*u == Inparmath) { + /* + * Already syntactically quoted: don't + * add more. + */ + int inmath = 1; + *v++ = *u++; + for (;;) { + char uc = *u; + *v++ = *u++; + if (uc == '\0') + break; + else if (uc == Outparmath && !--inmath) + break; + else if (uc == Inparmath) + ++inmath; + } + } else + *v++ = *u++; continue; } @@ -6148,10 +6440,15 @@ init_dirsav(Dirsav d) d->dirfd = d->level = -1; } -/* Change directory, without following symlinks. Returns 0 on success, -1 * - * on failure. Sets errno to ENOTDIR if any symlinks are encountered. If * - * fchdir() fails, or the current directory is unreadable, we might end up * - * in an unwanted directory in case of failure. */ +/* + * Change directory, without following symlinks. Returns 0 on success, -1 + * on failure. Sets errno to ENOTDIR if any symlinks are encountered. If + * fchdir() fails, or the current directory is unreadable, we might end up + * in an unwanted directory in case of failure. + * + * path is an unmetafied but null-terminated string, as needed by system + * calls. + */ /**/ mod_export int |