诸暨麻将添加redis
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

615 lines
18 KiB

  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2012, 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. ***************************************************************************/
  22. #include "tool_setup.h"
  23. #define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
  24. #include <curl/mprintf.h>
  25. #include "tool_urlglob.h"
  26. #include "tool_vms.h"
  27. #include "memdebug.h" /* keep this as LAST include */
  28. typedef enum {
  29. GLOB_OK,
  30. GLOB_NO_MEM,
  31. GLOB_ERROR
  32. } GlobCode;
  33. /*
  34. * glob_word()
  35. *
  36. * Input a full globbed string, set the forth argument to the amount of
  37. * strings we get out of this. Return GlobCode.
  38. */
  39. static GlobCode glob_word(URLGlob *, /* object anchor */
  40. char *, /* globbed string */
  41. size_t, /* position */
  42. int *); /* returned number of strings */
  43. static GlobCode glob_set(URLGlob *glob, char *pattern,
  44. size_t pos, int *amount)
  45. {
  46. /* processes a set expression with the point behind the opening '{'
  47. ','-separated elements are collected until the next closing '}'
  48. */
  49. URLPattern *pat;
  50. GlobCode res;
  51. bool done = FALSE;
  52. char* buf = glob->glob_buffer;
  53. pat = &glob->pattern[glob->size / 2];
  54. /* patterns 0,1,2,... correspond to size=1,3,5,... */
  55. pat->type = UPTSet;
  56. pat->content.Set.size = 0;
  57. pat->content.Set.ptr_s = 0;
  58. pat->content.Set.elements = NULL;
  59. if(++glob->size > (GLOB_PATTERN_NUM*2)) {
  60. snprintf(glob->errormsg, sizeof(glob->errormsg), "too many globs used\n");
  61. return GLOB_ERROR;
  62. }
  63. while(!done) {
  64. switch (*pattern) {
  65. case '\0': /* URL ended while set was still open */
  66. snprintf(glob->errormsg, sizeof(glob->errormsg),
  67. "unmatched brace at pos %zu\n", pos);
  68. return GLOB_ERROR;
  69. case '{':
  70. case '[': /* no nested expressions at this time */
  71. snprintf(glob->errormsg, sizeof(glob->errormsg),
  72. "nested braces not supported at pos %zu\n", pos);
  73. return GLOB_ERROR;
  74. case ',':
  75. case '}': /* set element completed */
  76. *buf = '\0';
  77. if(pat->content.Set.elements) {
  78. char **new_arr = realloc(pat->content.Set.elements,
  79. (pat->content.Set.size + 1) * sizeof(char*));
  80. if(!new_arr) {
  81. short elem;
  82. for(elem = 0; elem < pat->content.Set.size; elem++)
  83. Curl_safefree(pat->content.Set.elements[elem]);
  84. Curl_safefree(pat->content.Set.elements);
  85. pat->content.Set.ptr_s = 0;
  86. pat->content.Set.size = 0;
  87. }
  88. pat->content.Set.elements = new_arr;
  89. }
  90. else
  91. pat->content.Set.elements = malloc(sizeof(char*));
  92. if(!pat->content.Set.elements) {
  93. snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n");
  94. return GLOB_NO_MEM;
  95. }
  96. pat->content.Set.elements[pat->content.Set.size] =
  97. strdup(glob->glob_buffer);
  98. if(!pat->content.Set.elements[pat->content.Set.size]) {
  99. short elem;
  100. for(elem = 0; elem < pat->content.Set.size; elem++)
  101. Curl_safefree(pat->content.Set.elements[elem]);
  102. Curl_safefree(pat->content.Set.elements);
  103. pat->content.Set.ptr_s = 0;
  104. pat->content.Set.size = 0;
  105. snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n");
  106. return GLOB_NO_MEM;
  107. }
  108. ++pat->content.Set.size;
  109. if(*pattern == '}') {
  110. /* entire set pattern completed */
  111. int wordamount;
  112. /* always check for a literal (may be "") between patterns */
  113. res = glob_word(glob, ++pattern, ++pos, &wordamount);
  114. if(res) {
  115. short elem;
  116. for(elem = 0; elem < pat->content.Set.size; elem++)
  117. Curl_safefree(pat->content.Set.elements[elem]);
  118. Curl_safefree(pat->content.Set.elements);
  119. pat->content.Set.ptr_s = 0;
  120. pat->content.Set.size = 0;
  121. return res;
  122. }
  123. *amount = pat->content.Set.size * wordamount;
  124. done = TRUE;
  125. continue;
  126. }
  127. buf = glob->glob_buffer;
  128. ++pattern;
  129. ++pos;
  130. break;
  131. case ']': /* illegal closing bracket */
  132. snprintf(glob->errormsg, sizeof(glob->errormsg),
  133. "illegal pattern at pos %zu\n", pos);
  134. return GLOB_ERROR;
  135. case '\\': /* escaped character, skip '\' */
  136. if(pattern[1]) {
  137. ++pattern;
  138. ++pos;
  139. }
  140. /* intentional fallthrough */
  141. default:
  142. *buf++ = *pattern++; /* copy character to set element */
  143. ++pos;
  144. }
  145. }
  146. return GLOB_OK;
  147. }
  148. static GlobCode glob_range(URLGlob *glob, char *pattern,
  149. size_t pos, int *amount)
  150. {
  151. /* processes a range expression with the point behind the opening '['
  152. - char range: e.g. "a-z]", "B-Q]"
  153. - num range: e.g. "0-9]", "17-2000]"
  154. - num range with leading zeros: e.g. "001-999]"
  155. expression is checked for well-formedness and collected until the next ']'
  156. */
  157. URLPattern *pat;
  158. char *c;
  159. char sep;
  160. char sep2;
  161. int step;
  162. int rc;
  163. GlobCode res;
  164. int wordamount = 1;
  165. pat = &glob->pattern[glob->size / 2];
  166. /* patterns 0,1,2,... correspond to size=1,3,5,... */
  167. if(++glob->size > (GLOB_PATTERN_NUM*2)) {
  168. snprintf(glob->errormsg, sizeof(glob->errormsg), "too many globs used\n");
  169. return GLOB_ERROR;
  170. }
  171. if(ISALPHA(*pattern)) {
  172. /* character range detected */
  173. char min_c;
  174. char max_c;
  175. pat->type = UPTCharRange;
  176. rc = sscanf(pattern, "%c-%c%c%d%c", &min_c, &max_c, &sep, &step, &sep2);
  177. if((rc < 3) || (min_c >= max_c) || ((max_c - min_c) > ('z' - 'a'))) {
  178. /* the pattern is not well-formed */
  179. snprintf(glob->errormsg, sizeof(glob->errormsg),
  180. "error: bad range specification after pos %zu\n", pos);
  181. return GLOB_ERROR;
  182. }
  183. /* check the (first) separating character */
  184. if((sep != ']') && (sep != ':')) {
  185. snprintf(glob->errormsg, sizeof(glob->errormsg),
  186. "error: unsupported character (%c) after range at pos %zu\n",
  187. sep, pos);
  188. return GLOB_ERROR;
  189. }
  190. /* if there was a ":[num]" thing, use that as step or else use 1 */
  191. pat->content.CharRange.step =
  192. ((sep == ':') && (rc == 5) && (sep2 == ']')) ? step : 1;
  193. pat->content.CharRange.ptr_c = pat->content.CharRange.min_c = min_c;
  194. pat->content.CharRange.max_c = max_c;
  195. }
  196. else if(ISDIGIT(*pattern)) {
  197. /* numeric range detected */
  198. int min_n;
  199. int max_n;
  200. pat->type = UPTNumRange;
  201. pat->content.NumRange.padlength = 0;
  202. rc = sscanf(pattern, "%d-%d%c%d%c", &min_n, &max_n, &sep, &step, &sep2);
  203. if((rc < 2) || (min_n > max_n)) {
  204. /* the pattern is not well-formed */
  205. snprintf(glob->errormsg, sizeof(glob->errormsg),
  206. "error: bad range specification after pos %zu\n", pos);
  207. return GLOB_ERROR;
  208. }
  209. pat->content.NumRange.ptr_n = pat->content.NumRange.min_n = min_n;
  210. pat->content.NumRange.max_n = max_n;
  211. /* if there was a ":[num]" thing, use that as step or else use 1 */
  212. pat->content.NumRange.step =
  213. ((sep == ':') && (rc == 5) && (sep2 == ']')) ? step : 1;
  214. if(*pattern == '0') {
  215. /* leading zero specified */
  216. c = pattern;
  217. while(ISDIGIT(*c)) {
  218. c++;
  219. ++pat->content.NumRange.padlength; /* padding length is set for all
  220. instances of this pattern */
  221. }
  222. }
  223. }
  224. else {
  225. snprintf(glob->errormsg, sizeof(glob->errormsg),
  226. "illegal character in range specification at pos %zu\n", pos);
  227. return GLOB_ERROR;
  228. }
  229. c = (char*)strchr(pattern, ']'); /* continue after next ']' */
  230. if(c)
  231. c++;
  232. else {
  233. snprintf(glob->errormsg, sizeof(glob->errormsg), "missing ']'");
  234. return GLOB_ERROR; /* missing ']' */
  235. }
  236. /* always check for a literal (may be "") between patterns */
  237. res = glob_word(glob, c, pos + (c - pattern), &wordamount);
  238. if(res == GLOB_ERROR) {
  239. wordamount = 1;
  240. res = GLOB_OK;
  241. }
  242. if(!res) {
  243. if(pat->type == UPTCharRange)
  244. *amount = wordamount * (pat->content.CharRange.max_c -
  245. pat->content.CharRange.min_c + 1);
  246. else
  247. *amount = wordamount * (pat->content.NumRange.max_n -
  248. pat->content.NumRange.min_n + 1);
  249. }
  250. return res; /* GLOB_OK or GLOB_NO_MEM */
  251. }
  252. static GlobCode glob_word(URLGlob *glob, char *pattern,
  253. size_t pos, int *amount)
  254. {
  255. /* processes a literal string component of a URL
  256. special characters '{' and '[' branch to set/range processing functions
  257. */
  258. char* buf = glob->glob_buffer;
  259. size_t litindex;
  260. GlobCode res = GLOB_OK;
  261. *amount = 1; /* default is one single string */
  262. while(*pattern != '\0' && *pattern != '{' && *pattern != '[') {
  263. if(*pattern == '}' || *pattern == ']') {
  264. snprintf(glob->errormsg, sizeof(glob->errormsg),
  265. "unmatched close brace/bracket at pos %zu\n", pos);
  266. return GLOB_ERROR;
  267. }
  268. /* only allow \ to escape known "special letters" */
  269. if(*pattern == '\\' &&
  270. (*(pattern+1) == '{' || *(pattern+1) == '[' ||
  271. *(pattern+1) == '}' || *(pattern+1) == ']') ) {
  272. /* escape character, skip '\' */
  273. ++pattern;
  274. ++pos;
  275. }
  276. *buf++ = *pattern++; /* copy character to literal */
  277. ++pos;
  278. }
  279. *buf = '\0';
  280. litindex = glob->size / 2;
  281. /* literals 0,1,2,... correspond to size=0,2,4,... */
  282. glob->literal[litindex] = strdup(glob->glob_buffer);
  283. if(!glob->literal[litindex]) {
  284. snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n");
  285. return GLOB_NO_MEM;
  286. }
  287. ++glob->size;
  288. switch (*pattern) {
  289. case '\0':
  290. /* singular URL processed */
  291. break;
  292. case '{':
  293. /* process set pattern */
  294. res = glob_set(glob, ++pattern, ++pos, amount);
  295. break;
  296. case '[':
  297. /* process range pattern */
  298. res = glob_range(glob, ++pattern, ++pos, amount);
  299. break;
  300. }
  301. if(res)
  302. Curl_safefree(glob->literal[litindex]);
  303. return res;
  304. }
  305. int glob_url(URLGlob** glob, char* url, int *urlnum, FILE *error)
  306. {
  307. /*
  308. * We can deal with any-size, just make a buffer with the same length
  309. * as the specified URL!
  310. */
  311. URLGlob *glob_expand;
  312. int amount;
  313. char *glob_buffer;
  314. GlobCode res;
  315. *glob = NULL;
  316. glob_buffer = malloc(strlen(url) + 1);
  317. if(!glob_buffer)
  318. return CURLE_OUT_OF_MEMORY;
  319. glob_expand = calloc(1, sizeof(URLGlob));
  320. if(!glob_expand) {
  321. Curl_safefree(glob_buffer);
  322. return CURLE_OUT_OF_MEMORY;
  323. }
  324. glob_expand->size = 0;
  325. glob_expand->urllen = strlen(url);
  326. glob_expand->glob_buffer = glob_buffer;
  327. glob_expand->beenhere = 0;
  328. res = glob_word(glob_expand, url, 1, &amount);
  329. if(!res)
  330. *urlnum = amount;
  331. else {
  332. if(error && glob_expand->errormsg[0]) {
  333. /* send error description to the error-stream */
  334. fprintf(error, "curl: (%d) [globbing] %s",
  335. (res == GLOB_NO_MEM) ? CURLE_OUT_OF_MEMORY : CURLE_URL_MALFORMAT,
  336. glob_expand->errormsg);
  337. }
  338. /* it failed, we cleanup */
  339. Curl_safefree(glob_buffer);
  340. Curl_safefree(glob_expand);
  341. *urlnum = 1;
  342. return (res == GLOB_NO_MEM) ? CURLE_OUT_OF_MEMORY : CURLE_URL_MALFORMAT;
  343. }
  344. *glob = glob_expand;
  345. return CURLE_OK;
  346. }
  347. void glob_cleanup(URLGlob* glob)
  348. {
  349. size_t i;
  350. int elem;
  351. for(i = glob->size - 1; i < glob->size; --i) {
  352. if(!(i & 1)) { /* even indexes contain literals */
  353. Curl_safefree(glob->literal[i/2]);
  354. }
  355. else { /* odd indexes contain sets or ranges */
  356. if((glob->pattern[i/2].type == UPTSet) &&
  357. (glob->pattern[i/2].content.Set.elements)) {
  358. for(elem = glob->pattern[i/2].content.Set.size - 1;
  359. elem >= 0;
  360. --elem) {
  361. Curl_safefree(glob->pattern[i/2].content.Set.elements[elem]);
  362. }
  363. Curl_safefree(glob->pattern[i/2].content.Set.elements);
  364. }
  365. }
  366. }
  367. Curl_safefree(glob->glob_buffer);
  368. Curl_safefree(glob);
  369. }
  370. int glob_next_url(char **globbed, URLGlob *glob)
  371. {
  372. URLPattern *pat;
  373. char *lit;
  374. size_t i;
  375. size_t j;
  376. size_t len;
  377. size_t buflen = glob->urllen + 1;
  378. char *buf = glob->glob_buffer;
  379. *globbed = NULL;
  380. if(!glob->beenhere)
  381. glob->beenhere = 1;
  382. else {
  383. bool carry = TRUE;
  384. /* implement a counter over the index ranges of all patterns,
  385. starting with the rightmost pattern */
  386. for(i = glob->size / 2 - 1; carry && (i < glob->size); --i) {
  387. carry = FALSE;
  388. pat = &glob->pattern[i];
  389. switch (pat->type) {
  390. case UPTSet:
  391. if((pat->content.Set.elements) &&
  392. (++pat->content.Set.ptr_s == pat->content.Set.size)) {
  393. pat->content.Set.ptr_s = 0;
  394. carry = TRUE;
  395. }
  396. break;
  397. case UPTCharRange:
  398. pat->content.CharRange.ptr_c = (char)(pat->content.CharRange.step +
  399. (int)((unsigned char)pat->content.CharRange.ptr_c));
  400. if(pat->content.CharRange.ptr_c > pat->content.CharRange.max_c) {
  401. pat->content.CharRange.ptr_c = pat->content.CharRange.min_c;
  402. carry = TRUE;
  403. }
  404. break;
  405. case UPTNumRange:
  406. pat->content.NumRange.ptr_n += pat->content.NumRange.step;
  407. if(pat->content.NumRange.ptr_n > pat->content.NumRange.max_n) {
  408. pat->content.NumRange.ptr_n = pat->content.NumRange.min_n;
  409. carry = TRUE;
  410. }
  411. break;
  412. default:
  413. printf("internal error: invalid pattern type (%d)\n", (int)pat->type);
  414. return CURLE_FAILED_INIT;
  415. }
  416. }
  417. if(carry) { /* first pattern ptr has run into overflow, done! */
  418. /* TODO: verify if this should actally return CURLE_OK. */
  419. return CURLE_OK; /* CURLE_OK to match previous behavior */
  420. }
  421. }
  422. for(j = 0; j < glob->size; ++j) {
  423. if(!(j&1)) { /* every other term (j even) is a literal */
  424. lit = glob->literal[j/2];
  425. len = snprintf(buf, buflen, "%s", lit);
  426. buf += len;
  427. buflen -= len;
  428. }
  429. else { /* the rest (i odd) are patterns */
  430. pat = &glob->pattern[j/2];
  431. switch(pat->type) {
  432. case UPTSet:
  433. if(pat->content.Set.elements) {
  434. len = strlen(pat->content.Set.elements[pat->content.Set.ptr_s]);
  435. snprintf(buf, buflen, "%s",
  436. pat->content.Set.elements[pat->content.Set.ptr_s]);
  437. buf += len;
  438. buflen -= len;
  439. }
  440. break;
  441. case UPTCharRange:
  442. *buf++ = pat->content.CharRange.ptr_c;
  443. break;
  444. case UPTNumRange:
  445. len = snprintf(buf, buflen, "%0*d",
  446. pat->content.NumRange.padlength,
  447. pat->content.NumRange.ptr_n);
  448. buf += len;
  449. buflen -= len;
  450. break;
  451. default:
  452. printf("internal error: invalid pattern type (%d)\n", (int)pat->type);
  453. return CURLE_FAILED_INIT;
  454. }
  455. }
  456. }
  457. *buf = '\0';
  458. *globbed = strdup(glob->glob_buffer);
  459. if(!*globbed)
  460. return CURLE_OUT_OF_MEMORY;
  461. return CURLE_OK;
  462. }
  463. int glob_match_url(char **result, char *filename, URLGlob *glob)
  464. {
  465. char *target;
  466. size_t allocsize;
  467. char numbuf[18];
  468. char *appendthis = NULL;
  469. size_t appendlen = 0;
  470. size_t stringlen = 0;
  471. *result = NULL;
  472. /* We cannot use the glob_buffer for storage here since the filename may
  473. * be longer than the URL we use. We allocate a good start size, then
  474. * we need to realloc in case of need.
  475. */
  476. allocsize = strlen(filename) + 1; /* make it at least one byte to store the
  477. trailing zero */
  478. target = malloc(allocsize);
  479. if(!target)
  480. return CURLE_OUT_OF_MEMORY;
  481. while(*filename) {
  482. if(*filename == '#' && ISDIGIT(filename[1])) {
  483. unsigned long i;
  484. char *ptr = filename;
  485. unsigned long num = strtoul(&filename[1], &filename, 10);
  486. i = num - 1UL;
  487. if(num && (i <= glob->size / 2)) {
  488. URLPattern pat = glob->pattern[i];
  489. switch (pat.type) {
  490. case UPTSet:
  491. if(pat.content.Set.elements) {
  492. appendthis = pat.content.Set.elements[pat.content.Set.ptr_s];
  493. appendlen =
  494. strlen(pat.content.Set.elements[pat.content.Set.ptr_s]);
  495. }
  496. break;
  497. case UPTCharRange:
  498. numbuf[0] = pat.content.CharRange.ptr_c;
  499. numbuf[1] = 0;
  500. appendthis = numbuf;
  501. appendlen = 1;
  502. break;
  503. case UPTNumRange:
  504. snprintf(numbuf, sizeof(numbuf), "%0*d",
  505. pat.content.NumRange.padlength,
  506. pat.content.NumRange.ptr_n);
  507. appendthis = numbuf;
  508. appendlen = strlen(numbuf);
  509. break;
  510. default:
  511. printf("internal error: invalid pattern type (%d)\n",
  512. (int)pat.type);
  513. Curl_safefree(target);
  514. return CURLE_FAILED_INIT;
  515. }
  516. }
  517. else {
  518. /* #[num] out of range, use the #[num] in the output */
  519. filename = ptr;
  520. appendthis = filename++;
  521. appendlen = 1;
  522. }
  523. }
  524. else {
  525. appendthis = filename++;
  526. appendlen = 1;
  527. }
  528. if(appendlen + stringlen >= allocsize) {
  529. char *newstr;
  530. /* we append a single byte to allow for the trailing byte to be appended
  531. at the end of this function outside the while() loop */
  532. allocsize = (appendlen + stringlen) * 2;
  533. newstr = realloc(target, allocsize + 1);
  534. if(!newstr) {
  535. Curl_safefree(target);
  536. return CURLE_OUT_OF_MEMORY;
  537. }
  538. target = newstr;
  539. }
  540. memcpy(&target[stringlen], appendthis, appendlen);
  541. stringlen += appendlen;
  542. }
  543. target[stringlen]= '\0';
  544. *result = target;
  545. return CURLE_OK;
  546. }