diff options
author | Peter Stephenson <pws@users.sourceforge.net> | 2009-01-05 21:56:53 +0000 |
---|---|---|
committer | Peter Stephenson <pws@users.sourceforge.net> | 2009-01-05 21:56:53 +0000 |
commit | d388995eed7a13eae05dc3236908c96a1ccc7016 (patch) | |
tree | a633d448022ba8eb8688c5609956a897d746e160 /Src/utils.c | |
parent | a8ca1046132aef61d0d6cf88d9b749bc5d87dab8 (diff) | |
download | zsh-d388995eed7a13eae05dc3236908c96a1ccc7016.tar.gz zsh-d388995eed7a13eae05dc3236908c96a1ccc7016.tar.xz zsh-d388995eed7a13eae05dc3236908c96a1ccc7016.zip |
26249: remove arbitrary string length limit in unmeta()
Diffstat (limited to 'Src/utils.c')
-rw-r--r-- | Src/utils.c | 61 |
1 files changed, 51 insertions, 10 deletions
diff --git a/Src/utils.c b/Src/utils.c index d66de8d2f..05732abb7 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -3704,26 +3704,67 @@ metalen(const char *s, int len) return mlen; } -/* This function converts a zsh internal string to a form which can be * - * passed to a system call as a filename. The result is stored in a * - * single static area. NULL returned if the result is longer than * - * 4 * PATH_MAX. */ +/* + * This function converts a zsh internal string to a form which can be + * passed to a system call as a filename. The result is stored in a + * single static area, sized to fit. If there is no Meta character + * the original string is returned. + */ /**/ mod_export char * unmeta(const char *file_name) { - static char fn[4 * PATH_MAX]; + static char *fn; + static int sz; char *p; const char *t; + int newsz, meta; + + meta = 0; + for (t = file_name; *t; t++) { + if (*t == Meta) + meta = 1; + } + if (!meta) { + /* + * don't need allocation... free if it's long, see below + */ + if (sz > 4 * PATH_MAX) { + zfree(fn, sz); + fn = NULL; + sz = 0; + } + return (char *) file_name; + } + + newsz = (t - file_name) + 1; + /* + * Optimisation: don't resize if we don't have to. + * We need a new allocation if + * - nothing was allocated before + * - the new string is larger than the old one + * - the old string was larger than an arbitrary limit but the + * new string isn't so that we free up significant space by resizing. + */ + if (!fn || newsz > sz || (sz > 4 * PATH_MAX && newsz <= 4 * PATH_MAX)) + { + if (fn) + zfree(fn, sz); + sz = newsz; + fn = (char *)zalloc(sz); + if (!fn) { + sz = 0; + /* + * will quite likely crash in the caller anyway... + */ + return NULL; + } + } - for (t = file_name, p = fn; *t && p < fn + 4 * PATH_MAX - 1; p++) + for (t = file_name, p = fn; *t; p++) if ((*p = *t++) == Meta) *p = *t++ ^ 32; - if (*t) - return NULL; - if (p - fn == t - file_name) - return (char *) file_name; *p = '\0'; return fn; } |