static CURLcode glob_fixed(struct URLGlob *glob, char *fixed, size_t len)
{
- struct URLPattern *pat = &glob->pattern[glob->size];
+ struct URLPattern *pat = &glob->pattern[glob->pnum];
pat->type = GLOB_SET;
- pat->c.set.size = 1;
- pat->c.set.idx = 0;
pat->globindex = -1;
-
+ pat->c.set.size = 0;
+ pat->c.set.idx = 0;
pat->c.set.elem = malloc(sizeof(char *));
if(!pat->c.set.elem)
return globerror(glob, NULL, 0, CURLE_OUT_OF_MEMORY);
pat->c.set.elem[0] = memdup0(fixed, len);
- if(!pat->c.set.elem[0])
+ if(!pat->c.set.elem[0]) {
+ tool_safefree(pat->c.set.elem);
return globerror(glob, NULL, 0, CURLE_OUT_OF_MEMORY);
+ }
+ pat->c.set.palloc = 1;
+ pat->c.set.size = 1;
return CURLE_OK;
}
const char *pattern = *patternp;
const char *opattern = pattern;
size_t opos = *posp-1;
-
- pat = &glob->pattern[glob->size];
- /* patterns 0,1,2,... correspond to size=1,3,5,... */
- pat->type = GLOB_SET;
- pat->c.set.size = 0;
- pat->c.set.idx = 0;
- pat->c.set.elem = NULL;
- pat->globindex = globindex;
+ CURLcode result = CURLE_OK;
+ size_t size = 0;
+ char **elem = NULL;
+ size_t palloc = 0; /* start with this */
while(!done) {
switch(*pattern) {
case '\0': /* URL ended while set was still open */
- return globerror(glob, "unmatched brace", opos, CURLE_URL_MALFORMAT);
+ result = globerror(glob, "unmatched brace", opos, CURLE_URL_MALFORMAT);
+ goto error;
case '{':
case '[': /* no nested expressions at this time */
- return globerror(glob, "nested brace", *posp, CURLE_URL_MALFORMAT);
+ result = globerror(glob, "nested brace", *posp, CURLE_URL_MALFORMAT);
+ goto error;
case '}': /* set element completed */
- if(opattern == pattern)
- return globerror(glob, "empty string within braces", *posp,
- CURLE_URL_MALFORMAT);
+ if(opattern == pattern) {
+ result = globerror(glob, "empty string within braces", *posp,
+ CURLE_URL_MALFORMAT);
+ goto error;
+ }
/* add 1 to size since it will be incremented below */
- if(multiply(amount, pat->c.set.size + 1))
- return globerror(glob, "range overflow", 0, CURLE_URL_MALFORMAT);
+ if(multiply(amount, size + 1)) {
+ result = globerror(glob, "range overflow", 0, CURLE_URL_MALFORMAT);
+ goto error;
+ }
done = TRUE;
FALLTHROUGH();
case ',':
- if(pat->c.set.elem) {
- char **arr;
-
- if(pat->c.set.size >= (curl_off_t)(SIZE_MAX/(sizeof(char *))))
- return globerror(glob, "range overflow", 0, CURLE_URL_MALFORMAT);
-
- arr = realloc(pat->c.set.elem, (size_t)(pat->c.set.size + 1) *
- sizeof(char *));
- if(!arr)
- return globerror(glob, NULL, 0, CURLE_OUT_OF_MEMORY);
+ if(size >= 100000)
+ return globerror(glob, "range overflow", 0, CURLE_URL_MALFORMAT);
- pat->c.set.elem = arr;
+ if(!palloc) {
+ palloc = 5; /* a reasonable default */
+ elem = malloc(palloc * sizeof(char *));
+ }
+ else if(size >= palloc) {
+ char **arr = realloc(elem, palloc * 2 * sizeof(char *));
+ if(!arr) {
+ result = globerror(glob, NULL, 0, CURLE_OUT_OF_MEMORY);
+ goto error;
+ }
+ elem = arr;
+ palloc *= 2;
}
- else
- pat->c.set.elem = malloc(sizeof(char *));
- if(!pat->c.set.elem)
- return globerror(glob, NULL, 0, CURLE_OUT_OF_MEMORY);
+ if(!elem) {
+ result = globerror(glob, NULL, 0, CURLE_OUT_OF_MEMORY);
+ goto error;
+ }
- pat->c.set.elem[pat->c.set.size] = strdup(curlx_dyn_ptr(&glob->buf) ?
- curlx_dyn_ptr(&glob->buf): "");
- if(!pat->c.set.elem[pat->c.set.size])
- return globerror(glob, NULL, 0, CURLE_OUT_OF_MEMORY);
- ++pat->c.set.size;
+ elem[size] =
+ strdup(curlx_dyn_ptr(&glob->buf) ? curlx_dyn_ptr(&glob->buf) : "");
+ if(!elem[size]) {
+ result = globerror(glob, NULL, 0, CURLE_OUT_OF_MEMORY);
+ goto error;
+ }
+ ++size;
curlx_dyn_reset(&glob->buf);
++pattern;
break;
case ']': /* illegal closing bracket */
- return globerror(glob, "unexpected close bracket", *posp,
- CURLE_URL_MALFORMAT);
+ result = globerror(glob, "unexpected close bracket", *posp,
+ CURLE_URL_MALFORMAT);
+ goto error;
case '\\': /* escaped character, skip '\' */
if(pattern[1]) {
FALLTHROUGH();
default:
/* copy character to set element */
- if(curlx_dyn_addn(&glob->buf, pattern++, 1))
- return CURLE_OUT_OF_MEMORY;
+ if(curlx_dyn_addn(&glob->buf, pattern++, 1)) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
++(*posp);
}
}
*patternp = pattern; /* return with the new position */
+
+ pat = &glob->pattern[glob->pnum];
+ pat->type = GLOB_SET;
+ pat->globindex = globindex;
+ pat->c.set.elem = elem;
+ pat->c.set.size = size;
+ pat->c.set.idx = 0;
+ pat->c.set.palloc = palloc;
+
return CURLE_OK;
+error:
+ {
+ size_t i;
+ for(i = 0; i < size; i++)
+ tool_safefree(elem[i]);
+ }
+ free(elem);
+ return result;
}
static CURLcode glob_range(struct URLGlob *glob, const char **patternp,
const char *pattern = *patternp;
const char *c;
- pat = &glob->pattern[glob->size];
+ pat = &glob->pattern[glob->pnum];
pat->globindex = globindex;
if(ISALPHA(*pattern)) {
return rc ? FALSE : TRUE;
}
+static CURLcode add_glob(struct URLGlob *glob, size_t pos)
+{
+ DEBUGASSERT(glob->pattern[glob->pnum].type);
+
+ if(++glob->pnum >= glob->palloc) {
+ struct URLPattern *np = NULL;
+ glob->palloc *= 2;
+ if(glob->pnum < 255) { /* avoid ridiculous amounts */
+ np = realloc(glob->pattern, glob->palloc * sizeof(struct URLPattern));
+ if(!np)
+ return globerror(glob, NULL, pos, CURLE_OUT_OF_MEMORY);
+ }
+ else
+ return globerror(glob, "too many {} sets", pos, CURLE_URL_MALFORMAT);
+ glob->pattern = np;
+ }
+ return CURLE_OK;
+}
+
static CURLcode glob_parse(struct URLGlob *glob, const char *pattern,
size_t pos, curl_off_t *amount)
{
/* only allow \ to escape known "special letters" */
if(*pattern == '\\' &&
- (*(pattern + 1) == '{' || *(pattern + 1) == '[' ||
- *(pattern + 1) == '}' || *(pattern + 1) == ']') ) {
+ (pattern[1] == '{' || pattern[1] == '[' ||
+ pattern[1] == '}' || pattern[1] == ']') ) {
/* escape character, skip '\' */
++pattern;
/* we got a literal string, add it as a single-item list */
res = glob_fixed(glob, curlx_dyn_ptr(&glob->buf),
curlx_dyn_len(&glob->buf));
+ if(!res)
+ res = add_glob(glob, pos);
curlx_dyn_reset(&glob->buf);
}
else {
- switch(*pattern) {
- case '\0': /* done */
+ if(!*pattern) /* done */
break;
-
- case '{':
+ else if(*pattern =='{') {
/* process set pattern */
pattern++;
pos++;
res = glob_set(glob, &pattern, &pos, amount, globindex++);
- break;
-
- case '[':
+ if(!res)
+ res = add_glob(glob, pos);
+ }
+ else if(*pattern == '[') {
/* process range pattern */
pattern++;
pos++;
res = glob_range(glob, &pattern, &pos, amount, globindex++);
- break;
+ if(!res)
+ res = add_glob(glob, pos);
}
}
-
- if(++glob->size >= glob->palloc) {
- struct URLPattern *np = NULL;
- glob->palloc *= 2;
- if(glob->size < 255) { /* avoid ridiculous amounts */
- np = realloc(glob->pattern, glob->palloc * sizeof(struct URLPattern));
- if(!np)
- return globerror(glob, NULL, pos, CURLE_OUT_OF_MEMORY);
- }
- else
- return globerror(glob, "too many {} sets", pos, CURLE_URL_MALFORMAT);
- glob->pattern = np;
- }
}
return res;
}
glob->palloc = 2;
res = glob_parse(glob, url, 1, &amount);
- if(!res)
- *urlnum = amount;
- else {
+ if(res) {
if(error && glob->error) {
char text[512];
const char *t;
/* send error description to the error-stream */
curl_mfprintf(error, "curl: (%d) %s\n", res, t);
}
- /* it failed, we cleanup */
- glob_cleanup(glob);
*urlnum = 1;
return res;
}
-
+ *urlnum = amount;
return CURLE_OK;
}
void glob_cleanup(struct URLGlob *glob)
{
size_t i;
- curl_off_t elem;
if(glob->pattern) {
- for(i = 0; i < glob->size; i++) {
+ for(i = 0; i < glob->pnum; i++) {
+ DEBUGASSERT(glob->pattern[i].type);
if((glob->pattern[i].type == GLOB_SET) &&
(glob->pattern[i].c.set.elem)) {
- for(elem = glob->pattern[i].c.set.size - 1; elem >= 0; --elem)
+ curl_off_t elem;
+ for(elem = 0; elem < glob->pattern[i].c.set.size; elem++)
tool_safefree(glob->pattern[i].c.set.elem[elem]);
tool_safefree(glob->pattern[i].c.set.elem);
}
/* implement a counter over the index ranges of all patterns, starting
with the rightmost pattern */
- for(i = 0; carry && (i < glob->size); i++) {
+ for(i = 0; carry && (i < glob->pnum); i++) {
carry = FALSE;
- pat = &glob->pattern[glob->size - 1 - i];
+ pat = &glob->pattern[glob->pnum - 1 - i];
switch(pat->type) {
case GLOB_SET:
if((pat->c.set.elem) && (++pat->c.set.idx == pat->c.set.size)) {
}
}
- for(i = 0; i < glob->size; ++i) {
+ for(i = 0; i < glob->pnum; ++i) {
pat = &glob->pattern[i];
switch(pat->type) {
case GLOB_SET:
}
}
- *globbed = strdup(curlx_dyn_ptr(&glob->buf));
+ *globbed =
+ strdup(curlx_dyn_ptr(&glob->buf) ? curlx_dyn_ptr(&glob->buf) : "");
if(!*globbed)
return CURLE_OUT_OF_MEMORY;
curl_off_t num;
struct URLPattern *pat = NULL;
filename++;
- if(!curlx_str_number(&filename, &num, glob->size) && num) {
+ if(!curlx_str_number(&filename, &num, glob->pnum) && num) {
size_t i;
num--; /* make it zero based */
/* find the correct glob entry */
- for(i = 0; i < glob->size; i++) {
+ for(i = 0; i < glob->pnum; i++) {
if(glob->pattern[i].globindex == (int)num) {
pat = &glob->pattern[i];
break;