1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker *
14*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker *
18*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker *
23*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker #include "tool_setup.h"
25*6236dae4SAndroid Build Coastguard Worker
26*6236dae4SAndroid Build Coastguard Worker #include "curlx.h"
27*6236dae4SAndroid Build Coastguard Worker #include "tool_cfgable.h"
28*6236dae4SAndroid Build Coastguard Worker #include "tool_doswin.h"
29*6236dae4SAndroid Build Coastguard Worker #include "tool_urlglob.h"
30*6236dae4SAndroid Build Coastguard Worker #include "tool_vms.h"
31*6236dae4SAndroid Build Coastguard Worker #include "dynbuf.h"
32*6236dae4SAndroid Build Coastguard Worker
33*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h" /* keep this as LAST include */
34*6236dae4SAndroid Build Coastguard Worker
35*6236dae4SAndroid Build Coastguard Worker #define GLOBERROR(string, column, code) \
36*6236dae4SAndroid Build Coastguard Worker glob->error = string, glob->pos = column, code
37*6236dae4SAndroid Build Coastguard Worker
glob_fixed(struct URLGlob * glob,char * fixed,size_t len)38*6236dae4SAndroid Build Coastguard Worker static CURLcode glob_fixed(struct URLGlob *glob, char *fixed, size_t len)
39*6236dae4SAndroid Build Coastguard Worker {
40*6236dae4SAndroid Build Coastguard Worker struct URLPattern *pat = &glob->pattern[glob->size];
41*6236dae4SAndroid Build Coastguard Worker pat->type = UPTSet;
42*6236dae4SAndroid Build Coastguard Worker pat->content.Set.size = 1;
43*6236dae4SAndroid Build Coastguard Worker pat->content.Set.ptr_s = 0;
44*6236dae4SAndroid Build Coastguard Worker pat->globindex = -1;
45*6236dae4SAndroid Build Coastguard Worker
46*6236dae4SAndroid Build Coastguard Worker pat->content.Set.elements = malloc(sizeof(char *));
47*6236dae4SAndroid Build Coastguard Worker
48*6236dae4SAndroid Build Coastguard Worker if(!pat->content.Set.elements)
49*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY);
50*6236dae4SAndroid Build Coastguard Worker
51*6236dae4SAndroid Build Coastguard Worker pat->content.Set.elements[0] = malloc(len + 1);
52*6236dae4SAndroid Build Coastguard Worker if(!pat->content.Set.elements[0])
53*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY);
54*6236dae4SAndroid Build Coastguard Worker
55*6236dae4SAndroid Build Coastguard Worker memcpy(pat->content.Set.elements[0], fixed, len);
56*6236dae4SAndroid Build Coastguard Worker pat->content.Set.elements[0][len] = 0;
57*6236dae4SAndroid Build Coastguard Worker
58*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
59*6236dae4SAndroid Build Coastguard Worker }
60*6236dae4SAndroid Build Coastguard Worker
61*6236dae4SAndroid Build Coastguard Worker /* multiply
62*6236dae4SAndroid Build Coastguard Worker *
63*6236dae4SAndroid Build Coastguard Worker * Multiplies and checks for overflow.
64*6236dae4SAndroid Build Coastguard Worker */
multiply(curl_off_t * amount,curl_off_t with)65*6236dae4SAndroid Build Coastguard Worker static int multiply(curl_off_t *amount, curl_off_t with)
66*6236dae4SAndroid Build Coastguard Worker {
67*6236dae4SAndroid Build Coastguard Worker curl_off_t sum;
68*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(*amount >= 0);
69*6236dae4SAndroid Build Coastguard Worker DEBUGASSERT(with >= 0);
70*6236dae4SAndroid Build Coastguard Worker if((with <= 0) || (*amount <= 0)) {
71*6236dae4SAndroid Build Coastguard Worker sum = 0;
72*6236dae4SAndroid Build Coastguard Worker }
73*6236dae4SAndroid Build Coastguard Worker else {
74*6236dae4SAndroid Build Coastguard Worker #if defined(__GNUC__) && \
75*6236dae4SAndroid Build Coastguard Worker ((__GNUC__ > 5) || ((__GNUC__ == 5) && (__GNUC_MINOR__ >= 1)))
76*6236dae4SAndroid Build Coastguard Worker if(__builtin_mul_overflow(*amount, with, &sum))
77*6236dae4SAndroid Build Coastguard Worker return 1;
78*6236dae4SAndroid Build Coastguard Worker #else
79*6236dae4SAndroid Build Coastguard Worker sum = *amount * with;
80*6236dae4SAndroid Build Coastguard Worker if(sum/with != *amount)
81*6236dae4SAndroid Build Coastguard Worker return 1; /* did not fit, bail out */
82*6236dae4SAndroid Build Coastguard Worker #endif
83*6236dae4SAndroid Build Coastguard Worker }
84*6236dae4SAndroid Build Coastguard Worker *amount = sum;
85*6236dae4SAndroid Build Coastguard Worker return 0;
86*6236dae4SAndroid Build Coastguard Worker }
87*6236dae4SAndroid Build Coastguard Worker
glob_set(struct URLGlob * glob,char ** patternp,size_t * posp,curl_off_t * amount,int globindex)88*6236dae4SAndroid Build Coastguard Worker static CURLcode glob_set(struct URLGlob *glob, char **patternp,
89*6236dae4SAndroid Build Coastguard Worker size_t *posp, curl_off_t *amount,
90*6236dae4SAndroid Build Coastguard Worker int globindex)
91*6236dae4SAndroid Build Coastguard Worker {
92*6236dae4SAndroid Build Coastguard Worker /* processes a set expression with the point behind the opening '{'
93*6236dae4SAndroid Build Coastguard Worker ','-separated elements are collected until the next closing '}'
94*6236dae4SAndroid Build Coastguard Worker */
95*6236dae4SAndroid Build Coastguard Worker struct URLPattern *pat;
96*6236dae4SAndroid Build Coastguard Worker bool done = FALSE;
97*6236dae4SAndroid Build Coastguard Worker char *buf = glob->glob_buffer;
98*6236dae4SAndroid Build Coastguard Worker char *pattern = *patternp;
99*6236dae4SAndroid Build Coastguard Worker char *opattern = pattern;
100*6236dae4SAndroid Build Coastguard Worker size_t opos = *posp-1;
101*6236dae4SAndroid Build Coastguard Worker
102*6236dae4SAndroid Build Coastguard Worker pat = &glob->pattern[glob->size];
103*6236dae4SAndroid Build Coastguard Worker /* patterns 0,1,2,... correspond to size=1,3,5,... */
104*6236dae4SAndroid Build Coastguard Worker pat->type = UPTSet;
105*6236dae4SAndroid Build Coastguard Worker pat->content.Set.size = 0;
106*6236dae4SAndroid Build Coastguard Worker pat->content.Set.ptr_s = 0;
107*6236dae4SAndroid Build Coastguard Worker pat->content.Set.elements = NULL;
108*6236dae4SAndroid Build Coastguard Worker pat->globindex = globindex;
109*6236dae4SAndroid Build Coastguard Worker
110*6236dae4SAndroid Build Coastguard Worker while(!done) {
111*6236dae4SAndroid Build Coastguard Worker switch(*pattern) {
112*6236dae4SAndroid Build Coastguard Worker case '\0': /* URL ended while set was still open */
113*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("unmatched brace", opos, CURLE_URL_MALFORMAT);
114*6236dae4SAndroid Build Coastguard Worker
115*6236dae4SAndroid Build Coastguard Worker case '{':
116*6236dae4SAndroid Build Coastguard Worker case '[': /* no nested expressions at this time */
117*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("nested brace", *posp, CURLE_URL_MALFORMAT);
118*6236dae4SAndroid Build Coastguard Worker
119*6236dae4SAndroid Build Coastguard Worker case '}': /* set element completed */
120*6236dae4SAndroid Build Coastguard Worker if(opattern == pattern)
121*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("empty string within braces", *posp,
122*6236dae4SAndroid Build Coastguard Worker CURLE_URL_MALFORMAT);
123*6236dae4SAndroid Build Coastguard Worker
124*6236dae4SAndroid Build Coastguard Worker /* add 1 to size since it will be incremented below */
125*6236dae4SAndroid Build Coastguard Worker if(multiply(amount, pat->content.Set.size + 1))
126*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("range overflow", 0, CURLE_URL_MALFORMAT);
127*6236dae4SAndroid Build Coastguard Worker
128*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
129*6236dae4SAndroid Build Coastguard Worker case ',':
130*6236dae4SAndroid Build Coastguard Worker
131*6236dae4SAndroid Build Coastguard Worker *buf = '\0';
132*6236dae4SAndroid Build Coastguard Worker if(pat->content.Set.elements) {
133*6236dae4SAndroid Build Coastguard Worker char **new_arr = realloc(pat->content.Set.elements,
134*6236dae4SAndroid Build Coastguard Worker (size_t)(pat->content.Set.size + 1) *
135*6236dae4SAndroid Build Coastguard Worker sizeof(char *));
136*6236dae4SAndroid Build Coastguard Worker if(!new_arr)
137*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY);
138*6236dae4SAndroid Build Coastguard Worker
139*6236dae4SAndroid Build Coastguard Worker pat->content.Set.elements = new_arr;
140*6236dae4SAndroid Build Coastguard Worker }
141*6236dae4SAndroid Build Coastguard Worker else
142*6236dae4SAndroid Build Coastguard Worker pat->content.Set.elements = malloc(sizeof(char *));
143*6236dae4SAndroid Build Coastguard Worker
144*6236dae4SAndroid Build Coastguard Worker if(!pat->content.Set.elements)
145*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY);
146*6236dae4SAndroid Build Coastguard Worker
147*6236dae4SAndroid Build Coastguard Worker pat->content.Set.elements[pat->content.Set.size] =
148*6236dae4SAndroid Build Coastguard Worker strdup(glob->glob_buffer);
149*6236dae4SAndroid Build Coastguard Worker if(!pat->content.Set.elements[pat->content.Set.size])
150*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("out of memory", 0, CURLE_OUT_OF_MEMORY);
151*6236dae4SAndroid Build Coastguard Worker ++pat->content.Set.size;
152*6236dae4SAndroid Build Coastguard Worker
153*6236dae4SAndroid Build Coastguard Worker if(*pattern == '}') {
154*6236dae4SAndroid Build Coastguard Worker pattern++; /* pass the closing brace */
155*6236dae4SAndroid Build Coastguard Worker done = TRUE;
156*6236dae4SAndroid Build Coastguard Worker continue;
157*6236dae4SAndroid Build Coastguard Worker }
158*6236dae4SAndroid Build Coastguard Worker
159*6236dae4SAndroid Build Coastguard Worker buf = glob->glob_buffer;
160*6236dae4SAndroid Build Coastguard Worker ++pattern;
161*6236dae4SAndroid Build Coastguard Worker ++(*posp);
162*6236dae4SAndroid Build Coastguard Worker break;
163*6236dae4SAndroid Build Coastguard Worker
164*6236dae4SAndroid Build Coastguard Worker case ']': /* illegal closing bracket */
165*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("unexpected close bracket", *posp, CURLE_URL_MALFORMAT);
166*6236dae4SAndroid Build Coastguard Worker
167*6236dae4SAndroid Build Coastguard Worker case '\\': /* escaped character, skip '\' */
168*6236dae4SAndroid Build Coastguard Worker if(pattern[1]) {
169*6236dae4SAndroid Build Coastguard Worker ++pattern;
170*6236dae4SAndroid Build Coastguard Worker ++(*posp);
171*6236dae4SAndroid Build Coastguard Worker }
172*6236dae4SAndroid Build Coastguard Worker FALLTHROUGH();
173*6236dae4SAndroid Build Coastguard Worker default:
174*6236dae4SAndroid Build Coastguard Worker *buf++ = *pattern++; /* copy character to set element */
175*6236dae4SAndroid Build Coastguard Worker ++(*posp);
176*6236dae4SAndroid Build Coastguard Worker }
177*6236dae4SAndroid Build Coastguard Worker }
178*6236dae4SAndroid Build Coastguard Worker
179*6236dae4SAndroid Build Coastguard Worker *patternp = pattern; /* return with the new position */
180*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
181*6236dae4SAndroid Build Coastguard Worker }
182*6236dae4SAndroid Build Coastguard Worker
glob_range(struct URLGlob * glob,char ** patternp,size_t * posp,curl_off_t * amount,int globindex)183*6236dae4SAndroid Build Coastguard Worker static CURLcode glob_range(struct URLGlob *glob, char **patternp,
184*6236dae4SAndroid Build Coastguard Worker size_t *posp, curl_off_t *amount,
185*6236dae4SAndroid Build Coastguard Worker int globindex)
186*6236dae4SAndroid Build Coastguard Worker {
187*6236dae4SAndroid Build Coastguard Worker /* processes a range expression with the point behind the opening '['
188*6236dae4SAndroid Build Coastguard Worker - char range: e.g. "a-z]", "B-Q]"
189*6236dae4SAndroid Build Coastguard Worker - num range: e.g. "0-9]", "17-2000]"
190*6236dae4SAndroid Build Coastguard Worker - num range with leading zeros: e.g. "001-999]"
191*6236dae4SAndroid Build Coastguard Worker expression is checked for well-formedness and collected until the next ']'
192*6236dae4SAndroid Build Coastguard Worker */
193*6236dae4SAndroid Build Coastguard Worker struct URLPattern *pat;
194*6236dae4SAndroid Build Coastguard Worker int rc;
195*6236dae4SAndroid Build Coastguard Worker char *pattern = *patternp;
196*6236dae4SAndroid Build Coastguard Worker char *c;
197*6236dae4SAndroid Build Coastguard Worker
198*6236dae4SAndroid Build Coastguard Worker pat = &glob->pattern[glob->size];
199*6236dae4SAndroid Build Coastguard Worker pat->globindex = globindex;
200*6236dae4SAndroid Build Coastguard Worker
201*6236dae4SAndroid Build Coastguard Worker if(ISALPHA(*pattern)) {
202*6236dae4SAndroid Build Coastguard Worker /* character range detected */
203*6236dae4SAndroid Build Coastguard Worker char min_c;
204*6236dae4SAndroid Build Coastguard Worker char max_c;
205*6236dae4SAndroid Build Coastguard Worker char end_c;
206*6236dae4SAndroid Build Coastguard Worker unsigned long step = 1;
207*6236dae4SAndroid Build Coastguard Worker
208*6236dae4SAndroid Build Coastguard Worker pat->type = UPTCharRange;
209*6236dae4SAndroid Build Coastguard Worker
210*6236dae4SAndroid Build Coastguard Worker rc = sscanf(pattern, "%c-%c%c", &min_c, &max_c, &end_c);
211*6236dae4SAndroid Build Coastguard Worker
212*6236dae4SAndroid Build Coastguard Worker if(rc == 3) {
213*6236dae4SAndroid Build Coastguard Worker if(end_c == ':') {
214*6236dae4SAndroid Build Coastguard Worker char *endp;
215*6236dae4SAndroid Build Coastguard Worker errno = 0;
216*6236dae4SAndroid Build Coastguard Worker step = strtoul(&pattern[4], &endp, 10);
217*6236dae4SAndroid Build Coastguard Worker if(errno || &pattern[4] == endp || *endp != ']')
218*6236dae4SAndroid Build Coastguard Worker step = 0;
219*6236dae4SAndroid Build Coastguard Worker else
220*6236dae4SAndroid Build Coastguard Worker pattern = endp + 1;
221*6236dae4SAndroid Build Coastguard Worker }
222*6236dae4SAndroid Build Coastguard Worker else if(end_c != ']')
223*6236dae4SAndroid Build Coastguard Worker /* then this is wrong */
224*6236dae4SAndroid Build Coastguard Worker rc = 0;
225*6236dae4SAndroid Build Coastguard Worker else
226*6236dae4SAndroid Build Coastguard Worker /* end_c == ']' */
227*6236dae4SAndroid Build Coastguard Worker pattern += 4;
228*6236dae4SAndroid Build Coastguard Worker }
229*6236dae4SAndroid Build Coastguard Worker
230*6236dae4SAndroid Build Coastguard Worker *posp += (pattern - *patternp);
231*6236dae4SAndroid Build Coastguard Worker
232*6236dae4SAndroid Build Coastguard Worker if(rc != 3 || !step || step > (unsigned)INT_MAX ||
233*6236dae4SAndroid Build Coastguard Worker (min_c == max_c && step != 1) ||
234*6236dae4SAndroid Build Coastguard Worker (min_c != max_c && (min_c > max_c || step > (unsigned)(max_c - min_c) ||
235*6236dae4SAndroid Build Coastguard Worker (max_c - min_c) > ('z' - 'a'))))
236*6236dae4SAndroid Build Coastguard Worker /* the pattern is not well-formed */
237*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("bad range", *posp, CURLE_URL_MALFORMAT);
238*6236dae4SAndroid Build Coastguard Worker
239*6236dae4SAndroid Build Coastguard Worker /* if there was a ":[num]" thing, use that as step or else use 1 */
240*6236dae4SAndroid Build Coastguard Worker pat->content.CharRange.step = (int)step;
241*6236dae4SAndroid Build Coastguard Worker pat->content.CharRange.ptr_c = pat->content.CharRange.min_c = min_c;
242*6236dae4SAndroid Build Coastguard Worker pat->content.CharRange.max_c = max_c;
243*6236dae4SAndroid Build Coastguard Worker
244*6236dae4SAndroid Build Coastguard Worker if(multiply(amount, ((pat->content.CharRange.max_c -
245*6236dae4SAndroid Build Coastguard Worker pat->content.CharRange.min_c) /
246*6236dae4SAndroid Build Coastguard Worker pat->content.CharRange.step + 1)))
247*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("range overflow", *posp, CURLE_URL_MALFORMAT);
248*6236dae4SAndroid Build Coastguard Worker }
249*6236dae4SAndroid Build Coastguard Worker else if(ISDIGIT(*pattern)) {
250*6236dae4SAndroid Build Coastguard Worker /* numeric range detected */
251*6236dae4SAndroid Build Coastguard Worker unsigned long min_n;
252*6236dae4SAndroid Build Coastguard Worker unsigned long max_n = 0;
253*6236dae4SAndroid Build Coastguard Worker unsigned long step_n = 0;
254*6236dae4SAndroid Build Coastguard Worker char *endp;
255*6236dae4SAndroid Build Coastguard Worker
256*6236dae4SAndroid Build Coastguard Worker pat->type = UPTNumRange;
257*6236dae4SAndroid Build Coastguard Worker pat->content.NumRange.padlength = 0;
258*6236dae4SAndroid Build Coastguard Worker
259*6236dae4SAndroid Build Coastguard Worker if(*pattern == '0') {
260*6236dae4SAndroid Build Coastguard Worker /* leading zero specified, count them! */
261*6236dae4SAndroid Build Coastguard Worker c = pattern;
262*6236dae4SAndroid Build Coastguard Worker while(ISDIGIT(*c)) {
263*6236dae4SAndroid Build Coastguard Worker c++;
264*6236dae4SAndroid Build Coastguard Worker ++pat->content.NumRange.padlength; /* padding length is set for all
265*6236dae4SAndroid Build Coastguard Worker instances of this pattern */
266*6236dae4SAndroid Build Coastguard Worker }
267*6236dae4SAndroid Build Coastguard Worker }
268*6236dae4SAndroid Build Coastguard Worker
269*6236dae4SAndroid Build Coastguard Worker errno = 0;
270*6236dae4SAndroid Build Coastguard Worker min_n = strtoul(pattern, &endp, 10);
271*6236dae4SAndroid Build Coastguard Worker if(errno || (endp == pattern))
272*6236dae4SAndroid Build Coastguard Worker endp = NULL;
273*6236dae4SAndroid Build Coastguard Worker else {
274*6236dae4SAndroid Build Coastguard Worker if(*endp != '-')
275*6236dae4SAndroid Build Coastguard Worker endp = NULL;
276*6236dae4SAndroid Build Coastguard Worker else {
277*6236dae4SAndroid Build Coastguard Worker pattern = endp + 1;
278*6236dae4SAndroid Build Coastguard Worker while(*pattern && ISBLANK(*pattern))
279*6236dae4SAndroid Build Coastguard Worker pattern++;
280*6236dae4SAndroid Build Coastguard Worker if(!ISDIGIT(*pattern)) {
281*6236dae4SAndroid Build Coastguard Worker endp = NULL;
282*6236dae4SAndroid Build Coastguard Worker goto fail;
283*6236dae4SAndroid Build Coastguard Worker }
284*6236dae4SAndroid Build Coastguard Worker errno = 0;
285*6236dae4SAndroid Build Coastguard Worker max_n = strtoul(pattern, &endp, 10);
286*6236dae4SAndroid Build Coastguard Worker if(errno)
287*6236dae4SAndroid Build Coastguard Worker /* overflow */
288*6236dae4SAndroid Build Coastguard Worker endp = NULL;
289*6236dae4SAndroid Build Coastguard Worker else if(*endp == ':') {
290*6236dae4SAndroid Build Coastguard Worker pattern = endp + 1;
291*6236dae4SAndroid Build Coastguard Worker errno = 0;
292*6236dae4SAndroid Build Coastguard Worker step_n = strtoul(pattern, &endp, 10);
293*6236dae4SAndroid Build Coastguard Worker if(errno)
294*6236dae4SAndroid Build Coastguard Worker /* over/underflow situation */
295*6236dae4SAndroid Build Coastguard Worker endp = NULL;
296*6236dae4SAndroid Build Coastguard Worker }
297*6236dae4SAndroid Build Coastguard Worker else
298*6236dae4SAndroid Build Coastguard Worker step_n = 1;
299*6236dae4SAndroid Build Coastguard Worker if(endp && (*endp == ']')) {
300*6236dae4SAndroid Build Coastguard Worker pattern = endp + 1;
301*6236dae4SAndroid Build Coastguard Worker }
302*6236dae4SAndroid Build Coastguard Worker else
303*6236dae4SAndroid Build Coastguard Worker endp = NULL;
304*6236dae4SAndroid Build Coastguard Worker }
305*6236dae4SAndroid Build Coastguard Worker }
306*6236dae4SAndroid Build Coastguard Worker
307*6236dae4SAndroid Build Coastguard Worker fail:
308*6236dae4SAndroid Build Coastguard Worker *posp += (pattern - *patternp);
309*6236dae4SAndroid Build Coastguard Worker
310*6236dae4SAndroid Build Coastguard Worker if(!endp || !step_n ||
311*6236dae4SAndroid Build Coastguard Worker (min_n == max_n && step_n != 1) ||
312*6236dae4SAndroid Build Coastguard Worker (min_n != max_n && (min_n > max_n || step_n > (max_n - min_n))))
313*6236dae4SAndroid Build Coastguard Worker /* the pattern is not well-formed */
314*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("bad range", *posp, CURLE_URL_MALFORMAT);
315*6236dae4SAndroid Build Coastguard Worker
316*6236dae4SAndroid Build Coastguard Worker /* typecasting to ints are fine here since we make sure above that we
317*6236dae4SAndroid Build Coastguard Worker are within 31 bits */
318*6236dae4SAndroid Build Coastguard Worker pat->content.NumRange.ptr_n = pat->content.NumRange.min_n = min_n;
319*6236dae4SAndroid Build Coastguard Worker pat->content.NumRange.max_n = max_n;
320*6236dae4SAndroid Build Coastguard Worker pat->content.NumRange.step = step_n;
321*6236dae4SAndroid Build Coastguard Worker
322*6236dae4SAndroid Build Coastguard Worker if(multiply(amount, ((pat->content.NumRange.max_n -
323*6236dae4SAndroid Build Coastguard Worker pat->content.NumRange.min_n) /
324*6236dae4SAndroid Build Coastguard Worker pat->content.NumRange.step + 1)))
325*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("range overflow", *posp, CURLE_URL_MALFORMAT);
326*6236dae4SAndroid Build Coastguard Worker }
327*6236dae4SAndroid Build Coastguard Worker else
328*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("bad range specification", *posp, CURLE_URL_MALFORMAT);
329*6236dae4SAndroid Build Coastguard Worker
330*6236dae4SAndroid Build Coastguard Worker *patternp = pattern;
331*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
332*6236dae4SAndroid Build Coastguard Worker }
333*6236dae4SAndroid Build Coastguard Worker
334*6236dae4SAndroid Build Coastguard Worker #define MAX_IP6LEN 128
335*6236dae4SAndroid Build Coastguard Worker
peek_ipv6(const char * str,size_t * skip)336*6236dae4SAndroid Build Coastguard Worker static bool peek_ipv6(const char *str, size_t *skip)
337*6236dae4SAndroid Build Coastguard Worker {
338*6236dae4SAndroid Build Coastguard Worker /*
339*6236dae4SAndroid Build Coastguard Worker * Scan for a potential IPv6 literal.
340*6236dae4SAndroid Build Coastguard Worker * - Valid globs contain a hyphen and <= 1 colon.
341*6236dae4SAndroid Build Coastguard Worker * - IPv6 literals contain no hyphens and >= 2 colons.
342*6236dae4SAndroid Build Coastguard Worker */
343*6236dae4SAndroid Build Coastguard Worker char hostname[MAX_IP6LEN];
344*6236dae4SAndroid Build Coastguard Worker CURLU *u;
345*6236dae4SAndroid Build Coastguard Worker char *endbr = strchr(str, ']');
346*6236dae4SAndroid Build Coastguard Worker size_t hlen;
347*6236dae4SAndroid Build Coastguard Worker CURLUcode rc;
348*6236dae4SAndroid Build Coastguard Worker if(!endbr)
349*6236dae4SAndroid Build Coastguard Worker return FALSE;
350*6236dae4SAndroid Build Coastguard Worker
351*6236dae4SAndroid Build Coastguard Worker hlen = endbr - str + 1;
352*6236dae4SAndroid Build Coastguard Worker if(hlen >= MAX_IP6LEN)
353*6236dae4SAndroid Build Coastguard Worker return FALSE;
354*6236dae4SAndroid Build Coastguard Worker
355*6236dae4SAndroid Build Coastguard Worker u = curl_url();
356*6236dae4SAndroid Build Coastguard Worker if(!u)
357*6236dae4SAndroid Build Coastguard Worker return FALSE;
358*6236dae4SAndroid Build Coastguard Worker
359*6236dae4SAndroid Build Coastguard Worker memcpy(hostname, str, hlen);
360*6236dae4SAndroid Build Coastguard Worker hostname[hlen] = 0;
361*6236dae4SAndroid Build Coastguard Worker
362*6236dae4SAndroid Build Coastguard Worker /* ask to "guess scheme" as then it works without an https:// prefix */
363*6236dae4SAndroid Build Coastguard Worker rc = curl_url_set(u, CURLUPART_URL, hostname, CURLU_GUESS_SCHEME);
364*6236dae4SAndroid Build Coastguard Worker
365*6236dae4SAndroid Build Coastguard Worker curl_url_cleanup(u);
366*6236dae4SAndroid Build Coastguard Worker if(!rc)
367*6236dae4SAndroid Build Coastguard Worker *skip = hlen;
368*6236dae4SAndroid Build Coastguard Worker return rc ? FALSE : TRUE;
369*6236dae4SAndroid Build Coastguard Worker }
370*6236dae4SAndroid Build Coastguard Worker
glob_parse(struct URLGlob * glob,char * pattern,size_t pos,curl_off_t * amount)371*6236dae4SAndroid Build Coastguard Worker static CURLcode glob_parse(struct URLGlob *glob, char *pattern,
372*6236dae4SAndroid Build Coastguard Worker size_t pos, curl_off_t *amount)
373*6236dae4SAndroid Build Coastguard Worker {
374*6236dae4SAndroid Build Coastguard Worker /* processes a literal string component of a URL
375*6236dae4SAndroid Build Coastguard Worker special characters '{' and '[' branch to set/range processing functions
376*6236dae4SAndroid Build Coastguard Worker */
377*6236dae4SAndroid Build Coastguard Worker CURLcode res = CURLE_OK;
378*6236dae4SAndroid Build Coastguard Worker int globindex = 0; /* count "actual" globs */
379*6236dae4SAndroid Build Coastguard Worker
380*6236dae4SAndroid Build Coastguard Worker *amount = 1;
381*6236dae4SAndroid Build Coastguard Worker
382*6236dae4SAndroid Build Coastguard Worker while(*pattern && !res) {
383*6236dae4SAndroid Build Coastguard Worker char *buf = glob->glob_buffer;
384*6236dae4SAndroid Build Coastguard Worker size_t sublen = 0;
385*6236dae4SAndroid Build Coastguard Worker while(*pattern && *pattern != '{') {
386*6236dae4SAndroid Build Coastguard Worker if(*pattern == '[') {
387*6236dae4SAndroid Build Coastguard Worker /* skip over IPv6 literals and [] */
388*6236dae4SAndroid Build Coastguard Worker size_t skip = 0;
389*6236dae4SAndroid Build Coastguard Worker if(!peek_ipv6(pattern, &skip) && (pattern[1] == ']'))
390*6236dae4SAndroid Build Coastguard Worker skip = 2;
391*6236dae4SAndroid Build Coastguard Worker if(skip) {
392*6236dae4SAndroid Build Coastguard Worker memcpy(buf, pattern, skip);
393*6236dae4SAndroid Build Coastguard Worker buf += skip;
394*6236dae4SAndroid Build Coastguard Worker pattern += skip;
395*6236dae4SAndroid Build Coastguard Worker sublen += skip;
396*6236dae4SAndroid Build Coastguard Worker continue;
397*6236dae4SAndroid Build Coastguard Worker }
398*6236dae4SAndroid Build Coastguard Worker break;
399*6236dae4SAndroid Build Coastguard Worker }
400*6236dae4SAndroid Build Coastguard Worker if(*pattern == '}' || *pattern == ']')
401*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("unmatched close brace/bracket", pos,
402*6236dae4SAndroid Build Coastguard Worker CURLE_URL_MALFORMAT);
403*6236dae4SAndroid Build Coastguard Worker
404*6236dae4SAndroid Build Coastguard Worker /* only allow \ to escape known "special letters" */
405*6236dae4SAndroid Build Coastguard Worker if(*pattern == '\\' &&
406*6236dae4SAndroid Build Coastguard Worker (*(pattern + 1) == '{' || *(pattern + 1) == '[' ||
407*6236dae4SAndroid Build Coastguard Worker *(pattern + 1) == '}' || *(pattern + 1) == ']') ) {
408*6236dae4SAndroid Build Coastguard Worker
409*6236dae4SAndroid Build Coastguard Worker /* escape character, skip '\' */
410*6236dae4SAndroid Build Coastguard Worker ++pattern;
411*6236dae4SAndroid Build Coastguard Worker ++pos;
412*6236dae4SAndroid Build Coastguard Worker }
413*6236dae4SAndroid Build Coastguard Worker *buf++ = *pattern++; /* copy character to literal */
414*6236dae4SAndroid Build Coastguard Worker ++pos;
415*6236dae4SAndroid Build Coastguard Worker sublen++;
416*6236dae4SAndroid Build Coastguard Worker }
417*6236dae4SAndroid Build Coastguard Worker if(sublen) {
418*6236dae4SAndroid Build Coastguard Worker /* we got a literal string, add it as a single-item list */
419*6236dae4SAndroid Build Coastguard Worker *buf = '\0';
420*6236dae4SAndroid Build Coastguard Worker res = glob_fixed(glob, glob->glob_buffer, sublen);
421*6236dae4SAndroid Build Coastguard Worker }
422*6236dae4SAndroid Build Coastguard Worker else {
423*6236dae4SAndroid Build Coastguard Worker switch(*pattern) {
424*6236dae4SAndroid Build Coastguard Worker case '\0': /* done */
425*6236dae4SAndroid Build Coastguard Worker break;
426*6236dae4SAndroid Build Coastguard Worker
427*6236dae4SAndroid Build Coastguard Worker case '{':
428*6236dae4SAndroid Build Coastguard Worker /* process set pattern */
429*6236dae4SAndroid Build Coastguard Worker pattern++;
430*6236dae4SAndroid Build Coastguard Worker pos++;
431*6236dae4SAndroid Build Coastguard Worker res = glob_set(glob, &pattern, &pos, amount, globindex++);
432*6236dae4SAndroid Build Coastguard Worker break;
433*6236dae4SAndroid Build Coastguard Worker
434*6236dae4SAndroid Build Coastguard Worker case '[':
435*6236dae4SAndroid Build Coastguard Worker /* process range pattern */
436*6236dae4SAndroid Build Coastguard Worker pattern++;
437*6236dae4SAndroid Build Coastguard Worker pos++;
438*6236dae4SAndroid Build Coastguard Worker res = glob_range(glob, &pattern, &pos, amount, globindex++);
439*6236dae4SAndroid Build Coastguard Worker break;
440*6236dae4SAndroid Build Coastguard Worker }
441*6236dae4SAndroid Build Coastguard Worker }
442*6236dae4SAndroid Build Coastguard Worker
443*6236dae4SAndroid Build Coastguard Worker if(++glob->size >= GLOB_PATTERN_NUM)
444*6236dae4SAndroid Build Coastguard Worker return GLOBERROR("too many globs", pos, CURLE_URL_MALFORMAT);
445*6236dae4SAndroid Build Coastguard Worker }
446*6236dae4SAndroid Build Coastguard Worker return res;
447*6236dae4SAndroid Build Coastguard Worker }
448*6236dae4SAndroid Build Coastguard Worker
glob_url(struct URLGlob ** glob,char * url,curl_off_t * urlnum,FILE * error)449*6236dae4SAndroid Build Coastguard Worker CURLcode glob_url(struct URLGlob **glob, char *url, curl_off_t *urlnum,
450*6236dae4SAndroid Build Coastguard Worker FILE *error)
451*6236dae4SAndroid Build Coastguard Worker {
452*6236dae4SAndroid Build Coastguard Worker /*
453*6236dae4SAndroid Build Coastguard Worker * We can deal with any-size, just make a buffer with the same length
454*6236dae4SAndroid Build Coastguard Worker * as the specified URL!
455*6236dae4SAndroid Build Coastguard Worker */
456*6236dae4SAndroid Build Coastguard Worker struct URLGlob *glob_expand;
457*6236dae4SAndroid Build Coastguard Worker curl_off_t amount = 0;
458*6236dae4SAndroid Build Coastguard Worker char *glob_buffer;
459*6236dae4SAndroid Build Coastguard Worker CURLcode res;
460*6236dae4SAndroid Build Coastguard Worker
461*6236dae4SAndroid Build Coastguard Worker *glob = NULL;
462*6236dae4SAndroid Build Coastguard Worker
463*6236dae4SAndroid Build Coastguard Worker glob_buffer = malloc(strlen(url) + 1);
464*6236dae4SAndroid Build Coastguard Worker if(!glob_buffer)
465*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
466*6236dae4SAndroid Build Coastguard Worker glob_buffer[0] = 0;
467*6236dae4SAndroid Build Coastguard Worker
468*6236dae4SAndroid Build Coastguard Worker glob_expand = calloc(1, sizeof(struct URLGlob));
469*6236dae4SAndroid Build Coastguard Worker if(!glob_expand) {
470*6236dae4SAndroid Build Coastguard Worker Curl_safefree(glob_buffer);
471*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
472*6236dae4SAndroid Build Coastguard Worker }
473*6236dae4SAndroid Build Coastguard Worker glob_expand->urllen = strlen(url);
474*6236dae4SAndroid Build Coastguard Worker glob_expand->glob_buffer = glob_buffer;
475*6236dae4SAndroid Build Coastguard Worker
476*6236dae4SAndroid Build Coastguard Worker res = glob_parse(glob_expand, url, 1, &amount);
477*6236dae4SAndroid Build Coastguard Worker if(!res)
478*6236dae4SAndroid Build Coastguard Worker *urlnum = amount;
479*6236dae4SAndroid Build Coastguard Worker else {
480*6236dae4SAndroid Build Coastguard Worker if(error && glob_expand->error) {
481*6236dae4SAndroid Build Coastguard Worker char text[512];
482*6236dae4SAndroid Build Coastguard Worker const char *t;
483*6236dae4SAndroid Build Coastguard Worker if(glob_expand->pos) {
484*6236dae4SAndroid Build Coastguard Worker msnprintf(text, sizeof(text), "%s in URL position %zu:\n%s\n%*s^",
485*6236dae4SAndroid Build Coastguard Worker glob_expand->error,
486*6236dae4SAndroid Build Coastguard Worker glob_expand->pos, url, (int)glob_expand->pos - 1, " ");
487*6236dae4SAndroid Build Coastguard Worker t = text;
488*6236dae4SAndroid Build Coastguard Worker }
489*6236dae4SAndroid Build Coastguard Worker else
490*6236dae4SAndroid Build Coastguard Worker t = glob_expand->error;
491*6236dae4SAndroid Build Coastguard Worker
492*6236dae4SAndroid Build Coastguard Worker /* send error description to the error-stream */
493*6236dae4SAndroid Build Coastguard Worker fprintf(error, "curl: (%d) %s\n", res, t);
494*6236dae4SAndroid Build Coastguard Worker }
495*6236dae4SAndroid Build Coastguard Worker /* it failed, we cleanup */
496*6236dae4SAndroid Build Coastguard Worker glob_cleanup(&glob_expand);
497*6236dae4SAndroid Build Coastguard Worker *urlnum = 1;
498*6236dae4SAndroid Build Coastguard Worker return res;
499*6236dae4SAndroid Build Coastguard Worker }
500*6236dae4SAndroid Build Coastguard Worker
501*6236dae4SAndroid Build Coastguard Worker *glob = glob_expand;
502*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
503*6236dae4SAndroid Build Coastguard Worker }
504*6236dae4SAndroid Build Coastguard Worker
glob_cleanup(struct URLGlob ** globp)505*6236dae4SAndroid Build Coastguard Worker void glob_cleanup(struct URLGlob **globp)
506*6236dae4SAndroid Build Coastguard Worker {
507*6236dae4SAndroid Build Coastguard Worker size_t i;
508*6236dae4SAndroid Build Coastguard Worker curl_off_t elem;
509*6236dae4SAndroid Build Coastguard Worker struct URLGlob *glob = *globp;
510*6236dae4SAndroid Build Coastguard Worker
511*6236dae4SAndroid Build Coastguard Worker if(!glob)
512*6236dae4SAndroid Build Coastguard Worker return;
513*6236dae4SAndroid Build Coastguard Worker
514*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < glob->size; i++) {
515*6236dae4SAndroid Build Coastguard Worker if((glob->pattern[i].type == UPTSet) &&
516*6236dae4SAndroid Build Coastguard Worker (glob->pattern[i].content.Set.elements)) {
517*6236dae4SAndroid Build Coastguard Worker for(elem = glob->pattern[i].content.Set.size - 1;
518*6236dae4SAndroid Build Coastguard Worker elem >= 0;
519*6236dae4SAndroid Build Coastguard Worker --elem) {
520*6236dae4SAndroid Build Coastguard Worker Curl_safefree(glob->pattern[i].content.Set.elements[elem]);
521*6236dae4SAndroid Build Coastguard Worker }
522*6236dae4SAndroid Build Coastguard Worker Curl_safefree(glob->pattern[i].content.Set.elements);
523*6236dae4SAndroid Build Coastguard Worker }
524*6236dae4SAndroid Build Coastguard Worker }
525*6236dae4SAndroid Build Coastguard Worker Curl_safefree(glob->glob_buffer);
526*6236dae4SAndroid Build Coastguard Worker Curl_safefree(glob);
527*6236dae4SAndroid Build Coastguard Worker *globp = NULL;
528*6236dae4SAndroid Build Coastguard Worker }
529*6236dae4SAndroid Build Coastguard Worker
glob_next_url(char ** globbed,struct URLGlob * glob)530*6236dae4SAndroid Build Coastguard Worker CURLcode glob_next_url(char **globbed, struct URLGlob *glob)
531*6236dae4SAndroid Build Coastguard Worker {
532*6236dae4SAndroid Build Coastguard Worker struct URLPattern *pat;
533*6236dae4SAndroid Build Coastguard Worker size_t i;
534*6236dae4SAndroid Build Coastguard Worker size_t len;
535*6236dae4SAndroid Build Coastguard Worker size_t buflen = glob->urllen + 1;
536*6236dae4SAndroid Build Coastguard Worker char *buf = glob->glob_buffer;
537*6236dae4SAndroid Build Coastguard Worker
538*6236dae4SAndroid Build Coastguard Worker *globbed = NULL;
539*6236dae4SAndroid Build Coastguard Worker
540*6236dae4SAndroid Build Coastguard Worker if(!glob->beenhere)
541*6236dae4SAndroid Build Coastguard Worker glob->beenhere = 1;
542*6236dae4SAndroid Build Coastguard Worker else {
543*6236dae4SAndroid Build Coastguard Worker bool carry = TRUE;
544*6236dae4SAndroid Build Coastguard Worker
545*6236dae4SAndroid Build Coastguard Worker /* implement a counter over the index ranges of all patterns, starting
546*6236dae4SAndroid Build Coastguard Worker with the rightmost pattern */
547*6236dae4SAndroid Build Coastguard Worker for(i = 0; carry && (i < glob->size); i++) {
548*6236dae4SAndroid Build Coastguard Worker carry = FALSE;
549*6236dae4SAndroid Build Coastguard Worker pat = &glob->pattern[glob->size - 1 - i];
550*6236dae4SAndroid Build Coastguard Worker switch(pat->type) {
551*6236dae4SAndroid Build Coastguard Worker case UPTSet:
552*6236dae4SAndroid Build Coastguard Worker if((pat->content.Set.elements) &&
553*6236dae4SAndroid Build Coastguard Worker (++pat->content.Set.ptr_s == pat->content.Set.size)) {
554*6236dae4SAndroid Build Coastguard Worker pat->content.Set.ptr_s = 0;
555*6236dae4SAndroid Build Coastguard Worker carry = TRUE;
556*6236dae4SAndroid Build Coastguard Worker }
557*6236dae4SAndroid Build Coastguard Worker break;
558*6236dae4SAndroid Build Coastguard Worker case UPTCharRange:
559*6236dae4SAndroid Build Coastguard Worker pat->content.CharRange.ptr_c =
560*6236dae4SAndroid Build Coastguard Worker (char)(pat->content.CharRange.step +
561*6236dae4SAndroid Build Coastguard Worker (int)((unsigned char)pat->content.CharRange.ptr_c));
562*6236dae4SAndroid Build Coastguard Worker if(pat->content.CharRange.ptr_c > pat->content.CharRange.max_c) {
563*6236dae4SAndroid Build Coastguard Worker pat->content.CharRange.ptr_c = pat->content.CharRange.min_c;
564*6236dae4SAndroid Build Coastguard Worker carry = TRUE;
565*6236dae4SAndroid Build Coastguard Worker }
566*6236dae4SAndroid Build Coastguard Worker break;
567*6236dae4SAndroid Build Coastguard Worker case UPTNumRange:
568*6236dae4SAndroid Build Coastguard Worker pat->content.NumRange.ptr_n += pat->content.NumRange.step;
569*6236dae4SAndroid Build Coastguard Worker if(pat->content.NumRange.ptr_n > pat->content.NumRange.max_n) {
570*6236dae4SAndroid Build Coastguard Worker pat->content.NumRange.ptr_n = pat->content.NumRange.min_n;
571*6236dae4SAndroid Build Coastguard Worker carry = TRUE;
572*6236dae4SAndroid Build Coastguard Worker }
573*6236dae4SAndroid Build Coastguard Worker break;
574*6236dae4SAndroid Build Coastguard Worker default:
575*6236dae4SAndroid Build Coastguard Worker printf("internal error: invalid pattern type (%d)\n", (int)pat->type);
576*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
577*6236dae4SAndroid Build Coastguard Worker }
578*6236dae4SAndroid Build Coastguard Worker }
579*6236dae4SAndroid Build Coastguard Worker if(carry) { /* first pattern ptr has run into overflow, done! */
580*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
581*6236dae4SAndroid Build Coastguard Worker }
582*6236dae4SAndroid Build Coastguard Worker }
583*6236dae4SAndroid Build Coastguard Worker
584*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < glob->size; ++i) {
585*6236dae4SAndroid Build Coastguard Worker pat = &glob->pattern[i];
586*6236dae4SAndroid Build Coastguard Worker switch(pat->type) {
587*6236dae4SAndroid Build Coastguard Worker case UPTSet:
588*6236dae4SAndroid Build Coastguard Worker if(pat->content.Set.elements) {
589*6236dae4SAndroid Build Coastguard Worker msnprintf(buf, buflen, "%s",
590*6236dae4SAndroid Build Coastguard Worker pat->content.Set.elements[pat->content.Set.ptr_s]);
591*6236dae4SAndroid Build Coastguard Worker len = strlen(buf);
592*6236dae4SAndroid Build Coastguard Worker buf += len;
593*6236dae4SAndroid Build Coastguard Worker buflen -= len;
594*6236dae4SAndroid Build Coastguard Worker }
595*6236dae4SAndroid Build Coastguard Worker break;
596*6236dae4SAndroid Build Coastguard Worker case UPTCharRange:
597*6236dae4SAndroid Build Coastguard Worker if(buflen) {
598*6236dae4SAndroid Build Coastguard Worker *buf++ = pat->content.CharRange.ptr_c;
599*6236dae4SAndroid Build Coastguard Worker *buf = '\0';
600*6236dae4SAndroid Build Coastguard Worker buflen--;
601*6236dae4SAndroid Build Coastguard Worker }
602*6236dae4SAndroid Build Coastguard Worker break;
603*6236dae4SAndroid Build Coastguard Worker case UPTNumRange:
604*6236dae4SAndroid Build Coastguard Worker msnprintf(buf, buflen, "%0*" CURL_FORMAT_CURL_OFF_T,
605*6236dae4SAndroid Build Coastguard Worker pat->content.NumRange.padlength,
606*6236dae4SAndroid Build Coastguard Worker pat->content.NumRange.ptr_n);
607*6236dae4SAndroid Build Coastguard Worker len = strlen(buf);
608*6236dae4SAndroid Build Coastguard Worker buf += len;
609*6236dae4SAndroid Build Coastguard Worker buflen -= len;
610*6236dae4SAndroid Build Coastguard Worker break;
611*6236dae4SAndroid Build Coastguard Worker default:
612*6236dae4SAndroid Build Coastguard Worker printf("internal error: invalid pattern type (%d)\n", (int)pat->type);
613*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
614*6236dae4SAndroid Build Coastguard Worker }
615*6236dae4SAndroid Build Coastguard Worker }
616*6236dae4SAndroid Build Coastguard Worker
617*6236dae4SAndroid Build Coastguard Worker *globbed = strdup(glob->glob_buffer);
618*6236dae4SAndroid Build Coastguard Worker if(!*globbed)
619*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
620*6236dae4SAndroid Build Coastguard Worker
621*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
622*6236dae4SAndroid Build Coastguard Worker }
623*6236dae4SAndroid Build Coastguard Worker
624*6236dae4SAndroid Build Coastguard Worker #define MAX_OUTPUT_GLOB_LENGTH (10*1024)
625*6236dae4SAndroid Build Coastguard Worker
glob_match_url(char ** result,char * filename,struct URLGlob * glob)626*6236dae4SAndroid Build Coastguard Worker CURLcode glob_match_url(char **result, char *filename, struct URLGlob *glob)
627*6236dae4SAndroid Build Coastguard Worker {
628*6236dae4SAndroid Build Coastguard Worker char numbuf[18];
629*6236dae4SAndroid Build Coastguard Worker char *appendthis = (char *)"";
630*6236dae4SAndroid Build Coastguard Worker size_t appendlen = 0;
631*6236dae4SAndroid Build Coastguard Worker struct curlx_dynbuf dyn;
632*6236dae4SAndroid Build Coastguard Worker
633*6236dae4SAndroid Build Coastguard Worker *result = NULL;
634*6236dae4SAndroid Build Coastguard Worker
635*6236dae4SAndroid Build Coastguard Worker /* We cannot use the glob_buffer for storage since the filename may be
636*6236dae4SAndroid Build Coastguard Worker * longer than the URL we use.
637*6236dae4SAndroid Build Coastguard Worker */
638*6236dae4SAndroid Build Coastguard Worker curlx_dyn_init(&dyn, MAX_OUTPUT_GLOB_LENGTH);
639*6236dae4SAndroid Build Coastguard Worker
640*6236dae4SAndroid Build Coastguard Worker while(*filename) {
641*6236dae4SAndroid Build Coastguard Worker if(*filename == '#' && ISDIGIT(filename[1])) {
642*6236dae4SAndroid Build Coastguard Worker char *ptr = filename;
643*6236dae4SAndroid Build Coastguard Worker unsigned long num = strtoul(&filename[1], &filename, 10);
644*6236dae4SAndroid Build Coastguard Worker struct URLPattern *pat = NULL;
645*6236dae4SAndroid Build Coastguard Worker
646*6236dae4SAndroid Build Coastguard Worker if(num && (num < glob->size)) {
647*6236dae4SAndroid Build Coastguard Worker unsigned long i;
648*6236dae4SAndroid Build Coastguard Worker num--; /* make it zero based */
649*6236dae4SAndroid Build Coastguard Worker /* find the correct glob entry */
650*6236dae4SAndroid Build Coastguard Worker for(i = 0; i < glob->size; i++) {
651*6236dae4SAndroid Build Coastguard Worker if(glob->pattern[i].globindex == (int)num) {
652*6236dae4SAndroid Build Coastguard Worker pat = &glob->pattern[i];
653*6236dae4SAndroid Build Coastguard Worker break;
654*6236dae4SAndroid Build Coastguard Worker }
655*6236dae4SAndroid Build Coastguard Worker }
656*6236dae4SAndroid Build Coastguard Worker }
657*6236dae4SAndroid Build Coastguard Worker
658*6236dae4SAndroid Build Coastguard Worker if(pat) {
659*6236dae4SAndroid Build Coastguard Worker switch(pat->type) {
660*6236dae4SAndroid Build Coastguard Worker case UPTSet:
661*6236dae4SAndroid Build Coastguard Worker if(pat->content.Set.elements) {
662*6236dae4SAndroid Build Coastguard Worker appendthis = pat->content.Set.elements[pat->content.Set.ptr_s];
663*6236dae4SAndroid Build Coastguard Worker appendlen =
664*6236dae4SAndroid Build Coastguard Worker strlen(pat->content.Set.elements[pat->content.Set.ptr_s]);
665*6236dae4SAndroid Build Coastguard Worker }
666*6236dae4SAndroid Build Coastguard Worker break;
667*6236dae4SAndroid Build Coastguard Worker case UPTCharRange:
668*6236dae4SAndroid Build Coastguard Worker numbuf[0] = pat->content.CharRange.ptr_c;
669*6236dae4SAndroid Build Coastguard Worker numbuf[1] = 0;
670*6236dae4SAndroid Build Coastguard Worker appendthis = numbuf;
671*6236dae4SAndroid Build Coastguard Worker appendlen = 1;
672*6236dae4SAndroid Build Coastguard Worker break;
673*6236dae4SAndroid Build Coastguard Worker case UPTNumRange:
674*6236dae4SAndroid Build Coastguard Worker msnprintf(numbuf, sizeof(numbuf), "%0*" CURL_FORMAT_CURL_OFF_T,
675*6236dae4SAndroid Build Coastguard Worker pat->content.NumRange.padlength,
676*6236dae4SAndroid Build Coastguard Worker pat->content.NumRange.ptr_n);
677*6236dae4SAndroid Build Coastguard Worker appendthis = numbuf;
678*6236dae4SAndroid Build Coastguard Worker appendlen = strlen(numbuf);
679*6236dae4SAndroid Build Coastguard Worker break;
680*6236dae4SAndroid Build Coastguard Worker default:
681*6236dae4SAndroid Build Coastguard Worker fprintf(tool_stderr, "internal error: invalid pattern type (%d)\n",
682*6236dae4SAndroid Build Coastguard Worker (int)pat->type);
683*6236dae4SAndroid Build Coastguard Worker curlx_dyn_free(&dyn);
684*6236dae4SAndroid Build Coastguard Worker return CURLE_FAILED_INIT;
685*6236dae4SAndroid Build Coastguard Worker }
686*6236dae4SAndroid Build Coastguard Worker }
687*6236dae4SAndroid Build Coastguard Worker else {
688*6236dae4SAndroid Build Coastguard Worker /* #[num] out of range, use the #[num] in the output */
689*6236dae4SAndroid Build Coastguard Worker filename = ptr;
690*6236dae4SAndroid Build Coastguard Worker appendthis = filename++;
691*6236dae4SAndroid Build Coastguard Worker appendlen = 1;
692*6236dae4SAndroid Build Coastguard Worker }
693*6236dae4SAndroid Build Coastguard Worker }
694*6236dae4SAndroid Build Coastguard Worker else {
695*6236dae4SAndroid Build Coastguard Worker appendthis = filename++;
696*6236dae4SAndroid Build Coastguard Worker appendlen = 1;
697*6236dae4SAndroid Build Coastguard Worker }
698*6236dae4SAndroid Build Coastguard Worker if(curlx_dyn_addn(&dyn, appendthis, appendlen))
699*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
700*6236dae4SAndroid Build Coastguard Worker }
701*6236dae4SAndroid Build Coastguard Worker
702*6236dae4SAndroid Build Coastguard Worker if(curlx_dyn_addn(&dyn, "", 0))
703*6236dae4SAndroid Build Coastguard Worker return CURLE_OUT_OF_MEMORY;
704*6236dae4SAndroid Build Coastguard Worker
705*6236dae4SAndroid Build Coastguard Worker #if defined(_WIN32) || defined(MSDOS)
706*6236dae4SAndroid Build Coastguard Worker {
707*6236dae4SAndroid Build Coastguard Worker char *sanitized;
708*6236dae4SAndroid Build Coastguard Worker SANITIZEcode sc = sanitize_file_name(&sanitized, curlx_dyn_ptr(&dyn),
709*6236dae4SAndroid Build Coastguard Worker (SANITIZE_ALLOW_PATH |
710*6236dae4SAndroid Build Coastguard Worker SANITIZE_ALLOW_RESERVED));
711*6236dae4SAndroid Build Coastguard Worker curlx_dyn_free(&dyn);
712*6236dae4SAndroid Build Coastguard Worker if(sc)
713*6236dae4SAndroid Build Coastguard Worker return CURLE_URL_MALFORMAT;
714*6236dae4SAndroid Build Coastguard Worker *result = sanitized;
715*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
716*6236dae4SAndroid Build Coastguard Worker }
717*6236dae4SAndroid Build Coastguard Worker #else
718*6236dae4SAndroid Build Coastguard Worker *result = curlx_dyn_ptr(&dyn);
719*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
720*6236dae4SAndroid Build Coastguard Worker #endif /* _WIN32 || MSDOS */
721*6236dae4SAndroid Build Coastguard Worker }
722