xref: /aosp_15_r20/external/curl/src/tool_urlglob.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
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