doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
urlglob.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * $Id: urlglob.c,v 1.31 2004/03/08 12:51:13 bagder Exp $
22  ***************************************************************************/
23 
24 /* client-local setup.h */
25 #include "setup.h"
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <curl/curl.h>
32 
33 #define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
34 #include <curl/mprintf.h>
35 
36 #include "urlglob.h"
37 
38 
39 #ifdef CURLDEBUG
40 #include "../lib/memdebug.h"
41 #endif
42 
43 typedef enum {
46 } GlobCode;
47 
48 /*
49  * glob_word()
50  *
51  * Input a full globbed string, set the forth argument to the amount of
52  * strings we get out of this. Return GlobCode.
53  */
54 static GlobCode glob_word(URLGlob *, /* object anchor */
55  char *, /* globbed string */
56  int, /* position */
57  int *); /* returned number of strings */
58 
59 static GlobCode glob_set(URLGlob *glob, char *pattern, int pos, int *amount)
60 {
61  /* processes a set expression with the point behind the opening '{'
62  ','-separated elements are collected until the next closing '}'
63  */
64  char* buf = glob->glob_buffer;
65  URLPattern *pat;
66 
67  pat = (URLPattern*)&glob->pattern[glob->size / 2];
68  /* patterns 0,1,2,... correspond to size=1,3,5,... */
69  pat->type = UPTSet;
70  pat->content.Set.size = 0;
71  pat->content.Set.ptr_s = 0;
72  pat->content.Set.elements = (char**)malloc(0);
73  ++glob->size;
74 
75  while (1) {
76  switch (*pattern) {
77  case '\0': /* URL ended while set was still open */
78  snprintf(glob->errormsg, sizeof(glob->errormsg),
79  "unmatched brace at pos %d\n", pos);
80  return GLOB_ERROR;
81 
82  case '{':
83  case '[': /* no nested expressions at this time */
84  snprintf(glob->errormsg, sizeof(glob->errormsg),
85  "nested braces not supported at pos %d\n", pos);
86  return GLOB_ERROR;
87 
88  case ',':
89  case '}': /* set element completed */
90  *buf = '\0';
91  pat->content.Set.elements =
92  realloc(pat->content.Set.elements,
93  (pat->content.Set.size + 1) * sizeof(char*));
94  if (!pat->content.Set.elements) {
95  snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory");
96  return GLOB_ERROR;
97  }
98  pat->content.Set.elements[pat->content.Set.size] =
99  strdup(glob->glob_buffer);
100  ++pat->content.Set.size;
101 
102  if (*pattern == '}') {
103  /* entire set pattern completed */
104  int wordamount;
105 
106  /* always check for a literal (may be "") between patterns */
107  if(GLOB_ERROR == glob_word(glob, ++pattern, ++pos, &wordamount))
108  wordamount=1;
109  *amount = pat->content.Set.size * wordamount;
110 
111  return GLOB_OK;
112  }
113 
114  buf = glob->glob_buffer;
115  ++pattern;
116  ++pos;
117  break;
118 
119  case ']': /* illegal closing bracket */
120  snprintf(glob->errormsg, sizeof(glob->errormsg),
121  "illegal pattern at pos %d\n", pos);
122  return GLOB_ERROR;
123 
124  case '\\': /* escaped character, skip '\' */
125  if (*(buf+1) == '\0') { /* but no escaping of '\0'! */
126  snprintf(glob->errormsg, sizeof(glob->errormsg),
127  "illegal pattern at pos %d\n", pos);
128  return GLOB_ERROR;
129  }
130  ++pattern;
131  ++pos; /* intentional fallthrough */
132 
133  default:
134  *buf++ = *pattern++; /* copy character to set element */
135  ++pos;
136  }
137  }
138  /* we never reach this point */
139 }
140 
141 static GlobCode glob_range(URLGlob *glob, char *pattern, int pos, int *amount)
142 {
143  /* processes a range expression with the point behind the opening '['
144  - char range: e.g. "a-z]", "B-Q]"
145  - num range: e.g. "0-9]", "17-2000]"
146  - num range with leading zeros: e.g. "001-999]"
147  expression is checked for well-formedness and collected until the next ']'
148  */
149  URLPattern *pat;
150  char *c;
151  int wordamount=1;
152 
153  pat = (URLPattern*)&glob->pattern[glob->size / 2];
154  /* patterns 0,1,2,... correspond to size=1,3,5,... */
155  ++glob->size;
156 
157  if (isalpha((int)*pattern)) { /* character range detected */
158  pat->type = UPTCharRange;
159  if (sscanf(pattern, "%c-%c]", &pat->content.CharRange.min_c,
160  &pat->content.CharRange.max_c) != 2 ||
161  pat->content.CharRange.min_c >= pat->content.CharRange.max_c ||
162  pat->content.CharRange.max_c - pat->content.CharRange.min_c > 'z' - 'a') {
163  /* the pattern is not well-formed */
164  snprintf(glob->errormsg, sizeof(glob->errormsg),
165  "illegal pattern or range specification after pos %d\n", pos);
166  return GLOB_ERROR;
167  }
168  pat->content.CharRange.ptr_c = pat->content.CharRange.min_c;
169  /* always check for a literal (may be "") between patterns */
170 
171  if(GLOB_ERROR == glob_word(glob, pattern + 4, pos + 4, &wordamount))
172  wordamount=1;
173 
174  *amount = (pat->content.CharRange.max_c -
175  pat->content.CharRange.min_c + 1) *
176  wordamount;
177 
178  return GLOB_OK;
179  }
180 
181  if (isdigit((int)*pattern)) { /* numeric range detected */
182 
183  pat->type = UPTNumRange;
184  pat->content.NumRange.padlength = 0;
185  if (sscanf(pattern, "%d-%d]",
186  &pat->content.NumRange.min_n,
187  &pat->content.NumRange.max_n) != 2 ||
188  pat->content.NumRange.min_n >= pat->content.NumRange.max_n) {
189  /* the pattern is not well-formed */
190  snprintf(glob->errormsg, sizeof(glob->errormsg),
191  "error: illegal pattern or range specification after pos %d\n",
192  pos);
193  return GLOB_ERROR;
194  }
195  if (*pattern == '0') { /* leading zero specified */
196  c = pattern;
197  while (isdigit((int)*c++))
198  ++pat->content.NumRange.padlength; /* padding length is set for all
199  instances of this pattern */
200  }
201  pat->content.NumRange.ptr_n = pat->content.NumRange.min_n;
202  c = (char*)strchr(pattern, ']'); /* continue after next ']' */
203  if(c)
204  c++;
205  else {
206  snprintf(glob->errormsg, sizeof(glob->errormsg), "missing ']'");
207  return GLOB_ERROR; /* missing ']' */
208  }
209 
210  /* always check for a literal (may be "") between patterns */
211 
212  if(GLOB_ERROR == glob_word(glob, c, pos + (c - pattern), &wordamount))
213  wordamount = 1;
214 
215  *amount = (pat->content.NumRange.max_n -
216  pat->content.NumRange.min_n + 1) *
217  wordamount;
218 
219  return GLOB_OK;
220  }
221  snprintf(glob->errormsg, sizeof(glob->errormsg),
222  "illegal character in range specification at pos %d\n", pos);
223  return GLOB_ERROR;
224 }
225 
226 static GlobCode glob_word(URLGlob *glob, char *pattern, int pos, int *amount)
227 {
228  /* processes a literal string component of a URL
229  special characters '{' and '[' branch to set/range processing functions
230  */
231  char* buf = glob->glob_buffer;
232  int litindex;
233  GlobCode res = GLOB_OK;
234 
235  *amount = 1; /* default is one single string */
236 
237  while (*pattern != '\0' && *pattern != '{' && *pattern != '[') {
238  if (*pattern == '}' || *pattern == ']')
239  return GLOB_ERROR;
240 
241  /* only allow \ to escape known "special letters" */
242  if (*pattern == '\\' &&
243  (*(pattern+1) == '{' || *(pattern+1) == '[' ||
244  *(pattern+1) == '}' || *(pattern+1) == ']') ) {
245 
246  /* escape character, skip '\' */
247  ++pattern;
248  ++pos;
249  if (*pattern == '\0') /* but no escaping of '\0'! */
250  return GLOB_ERROR;
251  }
252  *buf++ = *pattern++; /* copy character to literal */
253  ++pos;
254  }
255  *buf = '\0';
256  litindex = glob->size / 2;
257  /* literals 0,1,2,... correspond to size=0,2,4,... */
258  glob->literal[litindex] = strdup(glob->glob_buffer);
259  if(!glob->literal[litindex])
260  return GLOB_ERROR;
261  ++glob->size;
262 
263  switch (*pattern) {
264  case '\0':
265  break; /* singular URL processed */
266 
267  case '{':
268  /* process set pattern */
269  res = glob_set(glob, ++pattern, ++pos, amount);
270  break;
271 
272  case '[':
273  /* process range pattern */
274  res= glob_range(glob, ++pattern, ++pos, amount);
275  break;
276  }
277 
278  if(GLOB_OK != res)
279  /* free that strdup'ed string again */
280  free(glob->literal[litindex]);
281 
282  return res; /* something got wrong */
283 }
284 
285 int glob_url(URLGlob** glob, char* url, int *urlnum, FILE *error)
286 {
287  /*
288  * We can deal with any-size, just make a buffer with the same length
289  * as the specified URL!
290  */
291  URLGlob *glob_expand;
292  int amount;
293  char *glob_buffer=(char *)malloc(strlen(url)+1);
294 
295  *glob = NULL;
296  if(NULL == glob_buffer)
297  return CURLE_OUT_OF_MEMORY;
298 
299  glob_expand = (URLGlob*)malloc(sizeof(URLGlob));
300  if(NULL == glob_expand) {
301  free(glob_buffer);
302  return CURLE_OUT_OF_MEMORY;
303  }
304  glob_expand->size = 0;
305  glob_expand->urllen = strlen(url);
306  glob_expand->glob_buffer = glob_buffer;
307  glob_expand->beenhere=0;
308  if(GLOB_OK == glob_word(glob_expand, url, 1, &amount))
309  *urlnum = amount;
310  else {
311  if(error && glob_expand->errormsg[0]) {
312  /* send error description to the error-stream */
313  fprintf(error, "curl: (%d) [globbing] %s\n",
314  CURLE_URL_MALFORMAT, glob_expand->errormsg);
315  }
316  /* it failed, we cleanup */
317  free(glob_buffer);
318  free(glob_expand);
319  glob_expand = NULL;
320  *urlnum = 1;
321  return CURLE_URL_MALFORMAT;
322  }
323 
324  *glob = glob_expand;
325  return CURLE_OK;
326 }
327 
329 {
330  int i, elem;
331 
332  for (i = glob->size - 1; i >= 0; --i) {
333  if (!(i & 1)) { /* even indexes contain literals */
334  free(glob->literal[i/2]);
335  }
336  else { /* odd indexes contain sets or ranges */
337  if (glob->pattern[i/2].type == UPTSet) {
338  for (elem = glob->pattern[i/2].content.Set.size - 1;
339  elem >= 0;
340  --elem) {
341  free(glob->pattern[i/2].content.Set.elements[elem]);
342  }
343  free(glob->pattern[i/2].content.Set.elements);
344  }
345  }
346  }
347  free(glob->glob_buffer);
348  free(glob);
349 }
350 
351 char *glob_next_url(URLGlob *glob)
352 {
353  char *buf = glob->glob_buffer;
354  URLPattern *pat;
355  char *lit;
356  signed int i;
357  int carry;
358 
359  if (!glob->beenhere)
360  glob->beenhere = 1;
361  else {
362  carry = 1;
363 
364  /* implement a counter over the index ranges of all patterns,
365  starting with the rightmost pattern */
366  for (i = glob->size / 2 - 1; carry && i >= 0; --i) {
367  carry = 0;
368  pat = &glob->pattern[i];
369  switch (pat->type) {
370  case UPTSet:
371  if (++pat->content.Set.ptr_s == pat->content.Set.size) {
372  pat->content.Set.ptr_s = 0;
373  carry = 1;
374  }
375  break;
376  case UPTCharRange:
377  if (++pat->content.CharRange.ptr_c > pat->content.CharRange.max_c) {
378  pat->content.CharRange.ptr_c = pat->content.CharRange.min_c;
379  carry = 1;
380  }
381  break;
382  case UPTNumRange:
383  if (++pat->content.NumRange.ptr_n > pat->content.NumRange.max_n) {
384  pat->content.NumRange.ptr_n = pat->content.NumRange.min_n;
385  carry = 1;
386  }
387  break;
388  default:
389  printf("internal error: invalid pattern type (%d)\n", pat->type);
390  exit (CURLE_FAILED_INIT);
391  }
392  }
393  if (carry) /* first pattern ptr has run into overflow, done! */
394  return NULL;
395  }
396 
397  for (i = 0; i < glob->size; ++i) {
398  if (!(i % 2)) { /* every other term (i even) is a literal */
399  lit = glob->literal[i/2];
400  strcpy(buf, lit);
401  buf += strlen(lit);
402  }
403  else { /* the rest (i odd) are patterns */
404  pat = &glob->pattern[i/2];
405  switch(pat->type) {
406  case UPTSet:
407  strcpy(buf, pat->content.Set.elements[pat->content.Set.ptr_s]);
408  buf += strlen(pat->content.Set.elements[pat->content.Set.ptr_s]);
409  break;
410  case UPTCharRange:
411  *buf++ = pat->content.CharRange.ptr_c;
412  break;
413  case UPTNumRange:
414  sprintf(buf, "%0*d",
415  pat->content.NumRange.padlength, pat->content.NumRange.ptr_n);
416  buf += strlen(buf); /* make no sprint() return code assumptions */
417  break;
418  default:
419  printf("internal error: invalid pattern type (%d)\n", pat->type);
420  exit (CURLE_FAILED_INIT);
421  }
422  }
423  }
424  *buf = '\0';
425  return strdup(glob->glob_buffer);
426 }
427 
428 char *glob_match_url(char *filename, URLGlob *glob)
429 {
430  char *target;
431  int allocsize;
432  int stringlen=0;
433  char numbuf[18];
434  char *appendthis = NULL;
435  int appendlen = 0;
436 
437  /* We cannot use the glob_buffer for storage here since the filename may
438  * be longer than the URL we use. We allocate a good start size, then
439  * we need to realloc in case of need.
440  */
441  allocsize=strlen(filename);
442  target = malloc(allocsize);
443  if(NULL == target)
444  return NULL; /* major failure */
445 
446  while (*filename) {
447  if (*filename == '#' && isdigit((int)filename[1])) {
448  /* only '#1' ... '#9' allowed */
449  int i;
450  unsigned long num = strtoul(&filename[1], &filename, 10);
451 
452  i = num-1;
453 
454  if (num && (i <= glob->size / 2)) {
455  URLPattern pat = glob->pattern[i];
456  switch (pat.type) {
457  case UPTSet:
458  appendthis = pat.content.Set.elements[pat.content.Set.ptr_s];
459  appendlen =
460  (int)strlen(pat.content.Set.elements[pat.content.Set.ptr_s]);
461  break;
462  case UPTCharRange:
463  numbuf[0]=pat.content.CharRange.ptr_c;
464  numbuf[1]=0;
465  appendthis=numbuf;
466  appendlen=1;
467  break;
468  case UPTNumRange:
469  sprintf(numbuf, "%0*d",
470  pat.content.NumRange.padlength,
471  pat.content.NumRange.ptr_n);
472  appendthis = numbuf;
473  appendlen = (int)strlen(numbuf);
474  break;
475  default:
476  printf("internal error: invalid pattern type (%d)\n",
477  (int)pat.type);
478  free(target);
479  return NULL;
480  }
481  }
482  }
483  else {
484  appendthis=filename++;
485  appendlen=1;
486  }
487  if(appendlen + stringlen >= allocsize) {
488  char *newstr;
489  allocsize = (appendlen + stringlen)*2;
490  newstr=realloc(target, allocsize);
491  if(NULL ==newstr) {
492  free(target);
493  return NULL;
494  }
495  target=newstr;
496  }
497  memcpy(&target[stringlen], appendthis, appendlen);
498  stringlen += appendlen;
499  }
500  target[stringlen]= '\0';
501  return target;
502 }
char * glob_match_url(char *filename, URLGlob *glob)
Definition: urlglob.c:428
case const int
Definition: Callbacks.cpp:52
int urllen
Definition: urlglob.h:55
int i
Definition: process.py:33
GLuint GLuint num
Definition: glext.h:5390
char * glob_buffer
Definition: urlglob.h:56
const GLubyte * c
Definition: glext.h:4677
char errormsg[80]
Definition: urlglob.h:58
char beenhere
Definition: urlglob.h:57
#define NULL
Definition: Lib.h:88
void glob_cleanup(URLGlob *glob)
Definition: urlglob.c:328
char * glob_next_url(URLGlob *glob)
Definition: urlglob.c:351
struct URLPattern::@13::@14 Set
char * literal[10]
Definition: urlglob.h:52
Definition: curl.h:210
struct URLPattern::@13::@16 NumRange
char * strdup(char *s1)
Definition: main.c:183
int size
Definition: urlglob.h:54
int glob_url(URLGlob **glob, char *url, int *urlnum, FILE *error)
Definition: urlglob.c:285
GlobCode
Definition: urlglob.c:43
#define snprintf
Definition: Str.h:70
GLsizeiptr size
Definition: glext.h:3112
GLushort pattern
Definition: qgl.h:331
URLPatternType type
Definition: urlglob.h:32
GLuint res
Definition: glext.h:5385
URLPattern pattern[9]
Definition: urlglob.h:53
if(!ValidDisplayID(prefInfo.prefDisplayID)) prefInfo.prefDisplayID
struct URLPattern::@13::@15 CharRange
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
union URLPattern::@13 content
Definition: urlglob.h:26