UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 5 * 6 * THE BSD LICENSE 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * Redistributions of source code must retain the above copyright notice, this 12 * list of conditions and the following disclaimer. 13 * Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 17 * Neither the name of the nor the names of its contributors may be 18 * used to endorse or promote products derived from this software without 19 * specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 25 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * util.c: A hodge podge of utility functions and standard functions which 36 * are unavailable on certain systems 37 * 38 * Rob McCool 39 */ 40 41 #ifdef XP_UNIX 42 #include <sys/types.h> 43 #include <sys/wait.h> 44 #include <stdlib.h> 45 #include <unistd.h> 46 #include <limits.h> 47 #include "prthread.h" 48 #endif /* XP_UNIX */ 49 50 51 //include "nspr.h" 52 #include <errno.h> 53 54 #include "../daemon/netsite.h" 55 #include "../public/nsapi.h" 56 #include <ucx/string.h> 57 #include <ucx/mempool.h> 58 59 #include "pblock.h" 60 #include "util.h" 61 62 #include <openssl/bio.h> 63 #include <openssl/buffer.h> 64 #include <openssl/evp.h> 65 66 67 /* ------------------------------ _uudecode ------------------------------- */ 68 69 static const unsigned char pr2six[256] = { 70 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 71 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63, 72 52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9, 73 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27, 74 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51, 75 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 76 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 77 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 78 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 79 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 80 64,64,64,64,64,64,64,64,64,64,64,64,64 81 }; 82 83 /** you MUST reserve at least 2 additional bytes for bufout */ 84 size_t util_base64decode(char *bufcoded, size_t codedbytes, char *bufout) { 85 register char *bufin = bufcoded; 86 register int nprbytes; 87 size_t nbytesdecoded; 88 89 /* Find the length */ 90 nprbytes = (int) codedbytes; 91 while(pr2six[(int)(bufin[nprbytes-1])] >= 64) { 92 nprbytes--; 93 } 94 nbytesdecoded = ((nprbytes+3)/4) * 3; 95 96 while (nprbytes > 0) { 97 *(bufout++) = (unsigned char) 98 (pr2six[(int)(*bufin)] << 2 | pr2six[(int)bufin[1]] >> 4); 99 *(bufout++) = (unsigned char) 100 (pr2six[(int)bufin[1]] << 4 | pr2six[(int)bufin[2]] >> 2); 101 *(bufout++) = (unsigned char) 102 (pr2six[(int)bufin[2]] << 6 | pr2six[(int)bufin[3]]); 103 bufin += 4; 104 nprbytes -= 4; 105 } 106 107 if(nprbytes & 03) { 108 if(pr2six[(int)bufin[-2]] > 63) 109 nbytesdecoded -= 2; 110 else 111 nbytesdecoded -= 1; 112 } 113 114 return nbytesdecoded; 115 } 116 117 char* util_base64encode(char *in, size_t len) { 118 BIO *b; 119 BIO *e; 120 BUF_MEM *mem; 121 122 e = BIO_new(BIO_f_base64()); 123 b = BIO_new(BIO_s_mem()); 124 BIO_set_flags(e, BIO_FLAGS_BASE64_NO_NL); 125 126 e = BIO_push(e, b); 127 BIO_write(e, in, len); 128 BIO_flush(e); 129 130 BIO_get_mem_ptr(e, &mem); 131 char *out = malloc(mem->length + 1); 132 memcpy(out, mem->data, mem->length); 133 out[mem->length] = '\0'; 134 135 BIO_free_all(e); 136 137 return out; 138 } 139 140 141 /* --------------------------- util_env_create ---------------------------- */ 142 143 144 NSAPI_PUBLIC char **util_env_create(char **env, int n, int *pos) 145 { 146 int x; 147 148 if(!env) { 149 *pos = 0; 150 return (char **) MALLOC((n + 1)*sizeof(char *)); 151 } 152 else { 153 for(x = 0; (env[x]); x++); 154 env = (char **) REALLOC(env, (n + x + 1)*(sizeof(char *))); 155 *pos = x; 156 return env; 157 } 158 } 159 160 161 /* ---------------------------- util_env_free ----------------------------- */ 162 163 164 NSAPI_PUBLIC void util_env_free(char **env) 165 { 166 register char **ep = env; 167 168 for(ep = env; *ep; ep++) 169 FREE(*ep); 170 FREE(env); 171 } 172 173 /* ----------------------------- util_env_str ----------------------------- */ 174 175 176 NSAPI_PUBLIC char *util_env_str(const char *name, const char *value) { 177 char *t; 178 179 size_t len = strlen(name) + strlen(value) + 2; 180 t = (char *) MALLOC(len); /* 2: '=' and '\0' */ 181 182 snprintf(t, len, "%s=%s", name, value); 183 184 return t; 185 } 186 187 188 /* --------------------------- util_env_replace --------------------------- */ 189 190 191 NSAPI_PUBLIC void util_env_replace(char **env, const char *name, const char *value) 192 { 193 int x, y, z; 194 char *i; 195 196 for(x = 0; env[x]; x++) { 197 i = strchr(env[x], '='); 198 *i = '\0'; 199 if(!strcmp(env[x], name)) { 200 y = strlen(env[x]); 201 z = strlen(value); 202 203 env[x] = (char *) REALLOC(env[x], y + z + 2); 204 util_sprintf(&env[x][y], "=%s", value); 205 return; 206 } 207 *i = '='; 208 } 209 } 210 211 212 /* ---------------------------- util_sh_escape ---------------------------- */ 213 214 215 NSAPI_PUBLIC char *util_sh_escape(char *s) 216 { 217 char *ns = (char *) MALLOC(strlen(s) * 2 + 1); /* worst case */ 218 register char *t, *u; 219 220 for(t = s, u = ns; *t; ++t, ++u) { 221 if(strchr("&;`''\"|*?~<>^()[]{}$\\ #!", *t)) 222 *u++ = '\\'; 223 *u = *t; 224 } 225 *u = '\0'; 226 return ns; 227 } 228 229 230 /* ---------------------------- util_env_find ----------------------------- */ 231 232 233 NSAPI_PUBLIC char *util_env_find(char **env, const char *name) 234 { 235 char *i; 236 int x, r; 237 238 for(x = 0; env[x]; x++) { 239 i = strchr(env[x], '='); 240 *i = '\0'; 241 r = !strcmp(env[x], name); 242 *i = '='; 243 if(r) 244 return i + 1; 245 } 246 return NULL; 247 } 248 249 250 /* ---------------------------- util_env_copy ----------------------------- */ 251 252 253 NSAPI_PUBLIC char **util_env_copy(char **src, char **dst) 254 { 255 char **src_ptr; 256 int src_cnt; 257 int index; 258 259 if (!src) 260 return NULL; 261 262 for (src_cnt = 0, src_ptr = src; *src_ptr; src_ptr++, src_cnt++); 263 264 if (!src_cnt) 265 return NULL; 266 267 dst = util_env_create(dst, src_cnt, &index); 268 269 for (src_ptr = src; *src_ptr; index++, src_ptr++) 270 dst[index] = STRDUP(*src_ptr); 271 dst[index] = NULL; 272 273 return dst; 274 } 275 276 /* ----------------------------- util_sprintf ----------------------------- */ 277 278 NSAPI_PUBLIC int util_vsnprintf(char *s, int n, register const char *fmt, 279 va_list args) 280 { 281 return vsnprintf(s, n, fmt, args); 282 } 283 284 NSAPI_PUBLIC int util_snprintf(char *s, int n, const char *fmt, ...) 285 { 286 va_list args; 287 va_start(args, fmt); 288 return vsnprintf(s, n, fmt, args); 289 } 290 291 NSAPI_PUBLIC int util_vsprintf(char *s, register const char *fmt, va_list args) 292 { 293 return vsprintf(s, fmt, args); 294 } 295 296 NSAPI_PUBLIC int util_sprintf(char *s, const char *fmt, ...) 297 { 298 va_list args; 299 va_start(args, fmt); 300 return vsprintf(s, fmt, args); 301 } 302 303 // TODO: asprintf 304 305 306 307 /* -------------------------- util_uri_unescape --------------------------- */ 308 309 NSAPI_PUBLIC void util_uri_unescape(char *s) 310 { 311 char *t, *u; 312 313 for(t = s, u = s; *t; ++t, ++u) { 314 if((*t == '%') && t[1] && t[2]) { 315 *u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A')+10 : (t[1] - '0'))*16) + 316 (t[2] >= 'A' ? ((t[2] & 0xdf) - 'A')+10 : (t[2] - '0')); 317 t += 2; 318 } 319 else 320 if(u != t) 321 *u = *t; 322 } 323 *u = *t; 324 } 325 326 /* 327 * Same as util_uri_unescape, but returns success/failure 328 */ 329 NSAPI_PUBLIC int util_uri_unescape_strict(char *s) 330 { 331 char *t, *u, t1, t2; 332 int rv = 1; 333 334 for(t = s, u = s; *t; ++t, ++u) { 335 if (*t == '%') { 336 t1 = t[1] & 0xdf; /* [a-f] -> [A-F] */ 337 if ((t1 < 'A' || t1 > 'F') && (t[1] < '0' || t[1] > '9')) 338 rv = 0; 339 340 t2 = t[2] & 0xdf; /* [a-f] -> [A-F] */ 341 if ((t2 < 'A' || t2 > 'F') && (t[2] < '0' || t[2] > '9')) 342 rv = 0; 343 344 *u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A')+10 : (t[1] - '0'))*16) + 345 (t[2] >= 'A' ? ((t[2] & 0xdf) - 'A')+10 : (t[2] - '0')); 346 t += 2; 347 } 348 else if (u != t) 349 *u = *t; 350 } 351 *u = *t; 352 353 return rv; 354 } 355 356 357 NSAPI_PUBLIC int 358 util_uri_unescape_plus (const char *src, char *trg, int len) 359 { 360 const char *t = src; 361 char *u = trg == NULL ? (char *)src : trg; 362 int rlen = 0; 363 364 if (len == -1) 365 len = strlen (src); 366 367 for( ; len && *t; ++t, ++u, len--, rlen++) 368 { 369 if((*t == '%') && t[1] && t[2]) 370 { 371 *u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A') + 10 : (t[1] - '0')) * 16) + 372 (t[2] >= 'A' ? ((t[2] & 0xdf) - 'A') + 10 : (t[2] - '0')); 373 t += 2; 374 len-= 2; 375 } 376 else 377 if (*t == '+') 378 *u = ' '; 379 else 380 *u = *t; 381 } 382 *u = 0; 383 return rlen; 384 } 385 386 387 NSAPI_PUBLIC int INTutil_getboolean(const char *v, int def) { 388 if(v[0] == 'T' || v[0] == 't') { 389 return 1; 390 } 391 if(v[0] == 'F' || v[0] == 'f') { 392 return 0; 393 } 394 return def; 395 } 396 397 int util_getboolean_s(sstr_t s, int def) { 398 if(s.length == 0) { 399 return def; 400 } 401 if(s.ptr[0] == 'T' || s.ptr[0] == 't') { 402 return 1; 403 } 404 if(s.ptr[0] == 'F' || s.ptr[0] == 'f') { 405 return 0; 406 } 407 return def; 408 } 409 410 NSAPI_PUBLIC int util_strtoint(char *str, int64_t *value) { 411 char *end; 412 errno = 0; 413 int64_t val = strtoll(str, &end, 0); 414 if(errno == 0) { 415 *value = val; 416 return 1; 417 } else { 418 return 0; 419 } 420 } 421 422 423 /* ------------------------------ util_itoa ------------------------------- */ 424 /* 425 NSAPI_PUBLIC int util_itoa(int i, char *a) 426 { 427 int len = util_i64toa(i, a); 428 429 PR_ASSERT(len < UTIL_ITOA_SIZE); 430 431 return len; 432 } 433 */ 434 NSAPI_PUBLIC int INTutil_itoa(int i, char *a) { 435 return INTutil_i64toa(i, a); 436 } 437 438 439 /* ----------------------------- util_i64toa ------------------------------ */ 440 441 /* 442 * Assumption: Reversing the digits will be faster in the general case 443 * than doing a log10 or some nasty trick to find the # of digits. 444 */ 445 446 NSAPI_PUBLIC int INTutil_i64toa(int64_t i, char *a) 447 { 448 register int x, y, p; 449 register char c; 450 int negative; 451 452 negative = 0; 453 if(i < 0) { 454 *a++ = '-'; 455 negative = 1; 456 i = -i; 457 } 458 p = 0; 459 while(i > 9) { 460 a[p++] = (i%10) + '0'; 461 i /= 10; 462 } 463 a[p++] = i + '0'; 464 465 if(p > 1) { 466 for(x = 0, y = p - 1; x < y; ++x, --y) { 467 c = a[x]; 468 a[x] = a[y]; 469 a[y] = c; 470 } 471 } 472 a[p] = '\0'; 473 474 //PR_ASSERT(p + negative < UTIL_I64TOA_SIZE); 475 476 return p + negative; 477 } 478 479 480 481 #ifndef XP_WIN32 482 NSAPI_PUBLIC struct passwd * 483 util_getpwnam(const char *name, struct passwd *result, char *buffer, 484 int buflen) 485 { 486 struct passwd *rv; 487 488 errno = getpwnam_r(name, result, buffer, buflen, &rv); 489 if (errno != 0) 490 rv = NULL; 491 492 return rv; 493 } 494 #endif 495 496 497 #ifndef XP_WIN32 498 NSAPI_PUBLIC struct passwd * 499 util_getpwuid(uid_t uid, struct passwd *result, char *buffer, int buflen) 500 { 501 struct passwd *rv; 502 503 errno = getpwuid_r(uid, result, buffer, buflen, &rv); 504 if (errno != 0) 505 rv = NULL; 506 507 return rv; 508 } 509 #endif 510 511 512 NSAPI_PUBLIC int util_errno2status(int errno_value) { 513 switch(errno_value) { 514 case 0: { 515 return 200; 516 } 517 case EACCES: { 518 return 403; 519 } 520 case ENOENT: { 521 return 404; 522 break; 523 } 524 } 525 return 500; 526 } 527 528 529 530 NSAPI_PUBLIC 531 sstr_t util_path_append(pool_handle_t *pool, char *path, char *ch) { 532 sstr_t parent = sstr(path); 533 sstr_t child = sstr(ch); 534 sstr_t newstr; 535 536 UcxAllocator a = util_pool_allocator(pool); 537 if(parent.ptr[parent.length-1] == '/') { 538 newstr = sstrcat_a(&a, 2, parent, child); 539 } else { 540 newstr = sstrcat_a(&a, 3, parent, S("/"), child); 541 } 542 543 return newstr; 544 } 545 546 sstr_t util_path_remove_last(sstr_t path) { 547 int i; 548 for(i=path.length-1;i>=0;i--) { 549 char c = path.ptr[i]; 550 if(c == '/') { 551 path.ptr[i] = 0; 552 path.length = i; 553 break; 554 } 555 } 556 if(i < 0) { 557 path.ptr = NULL; 558 path.length = 0; 559 } 560 return path; 561 } 562 563 void util_add_ppath(sstr_t root, sstr_t path, pblock *vars) { 564 // concat path 565 size_t length = root.length + path.length; 566 char *translated_path = alloca(length); 567 568 memcpy(translated_path, root.ptr, root.length); 569 memcpy(translated_path + root.length, path.ptr, path.length); 570 571 572 // add path to specified pblock 573 pblock_kvinsert( 574 pb_key_ppath, 575 translated_path, 576 length, 577 vars); 578 } 579 580 581 UcxAllocator util_pool_allocator(pool_handle_t *pool) { 582 UcxAllocator a; 583 a.malloc = (ucx_allocator_malloc)pool_malloc; 584 a.calloc = (ucx_allocator_calloc)pool_calloc; 585 a.realloc = (ucx_allocator_realloc)pool_realloc; 586 a.free = (ucx_allocator_free)pool_free; 587 a.pool = pool; 588 return a; 589 } 590 591 592 // new - code from params.cpp 593 NSAPI_PUBLIC pblock* util_parse_param(pool_handle_t *pool, char *query) { 594 pblock *pb = pblock_create_pool(pool, 32); 595 if(!pb) { 596 return NULL; 597 } 598 if(!query || !(*query)) { 599 return pb; 600 } 601 602 int loopFlag = 1; 603 int nl = 0; // size of the name substring 604 int vl = 0; // size of the value substring 605 int state = 0; 606 const char *np = query; 607 const char *vp = NULL; 608 609 while (loopFlag) { 610 char delim = *query++; 611 switch (delim) { 612 case '&': 613 case '\0': { 614 if(!delim) { 615 loopFlag = 0; 616 } 617 618 state = 0; 619 620 if(nl > 0) { 621 util_uri_unescape_plus(np, NULL, nl); 622 util_uri_unescape_plus(vp, NULL, vl); 623 pblock_nvlinsert(np, nl, vp, vl, pb); 624 } 625 626 nl = 0; 627 vl = 0; 628 vp = NULL; 629 np = query; 630 break; 631 } 632 case '=': { 633 state = 1; 634 vp = query; 635 break; 636 } 637 default: { 638 if(state) { 639 vl++; 640 } else { 641 nl++; 642 } 643 } 644 } /* switch */ 645 } /* while */ 646 647 return pb; 648 } 649 650 // TODO: remove 651 sstr_t sstrdup_mp(UcxMempool *pool, sstr_t s) { 652 sstr_t newstring; 653 newstring.ptr = (char*)ucx_mempool_malloc(pool, s.length + 1); 654 if (newstring.ptr != NULL) { 655 newstring.length = s.length; 656 newstring.ptr[newstring.length] = 0; 657 658 memcpy(newstring.ptr, s.ptr, s.length); 659 } 660 661 return newstring; 662 } 663 664 665 666 /* ---------------------------- util_mstr2num ----------------------------- */ 667 668 static const int MSTR2NUM_HT_MASK = 0xf; 669 670 struct mstr2num_ht { 671 unsigned ucmstr; // Uppercase 3 character month string in a machine word 672 int mnum; // 0-based month number for this month string 673 }; 674 675 struct mstr2num_ht MSTR2NUM_HT[] = { 676 { 'A' << 16 | 'P' << 8 | 'R', 3 }, 677 { 'S' << 16 | 'E' << 8 | 'P', 8 }, 678 { 'M' << 16 | 'A' << 8 | 'Y', 4 }, 679 { 0, -1 }, 680 { 'M' << 16 | 'A' << 8 | 'R', 2 }, 681 { 'F' << 16 | 'E' << 8 | 'B', 1 }, 682 { 0, -1 }, 683 { 'D' << 16 | 'E' << 8 | 'C', 11 }, 684 { 'O' << 16 | 'C' << 8 | 'T', 9 }, 685 { 'J' << 16 | 'U' << 8 | 'N', 5 }, 686 { 0, -1 }, 687 { 'A' << 16 | 'U' << 8 | 'G', 7 }, 688 { 'J' << 16 | 'A' << 8 | 'N', 0 }, 689 { 'J' << 16 | 'U' << 8 | 'L', 6 }, 690 { 0, -1 }, 691 { 'N' << 16 | 'O' << 8 | 'V', 10 } 692 }; 693 694 static inline int _mstr2num(const char *s) 695 { 696 const unsigned char *mstr = (const unsigned char *) s; 697 698 /* 699 * We compute ucmstr (an uppercase 3 character month string stored in a 700 * machine word) and hash (a perfect hash based on the last 2 characters 701 * of the 3 character uppercase month string) from the input string s. 702 * Note that each character from the input string is masked by 0xdf; in 703 * ASCII, this has the effect of converting alphabetic characters to 704 * uppercase while 1. not changing any nonalphabetic characters into 705 * alphabetic characters and 2. leaving any nul characters unchanged. 706 * 707 * The hash value is used as an index into the MSTR2NUM_HT[] hash table. 708 * If the ucmstr at that index matches our computed ucmstr, the mnum at 709 * that index is the 0-based month number corresponding to the input 710 * string. 711 * 712 * Note that we never read past the end of the input string and always 713 * return -1 if the input string doesn't begin with a valid 3 character 714 * month string. 715 */ 716 717 unsigned char ucmstr0 = mstr[0] & 0xdf; 718 unsigned ucmstr = ucmstr0 << 16; 719 if (ucmstr0 != '\0') { 720 unsigned char ucmstr1 = mstr[1] & 0xdf; 721 ucmstr |= ucmstr1 << 8; 722 if (ucmstr1 != '\0') { 723 unsigned char ucmstr2 = mstr[2] & 0xdf; 724 ucmstr |= ucmstr2; 725 726 unsigned hash = (ucmstr1 >> 2) ^ (ucmstr2 << 1); 727 728 int i = hash & MSTR2NUM_HT_MASK; 729 730 if (MSTR2NUM_HT[i].ucmstr == ucmstr) 731 return MSTR2NUM_HT[i].mnum; 732 } 733 } 734 735 return -1; 736 } 737 738 NSAPI_PUBLIC int util_mstr2num(const char *s) 739 { 740 return _mstr2num(s); 741 } 742 743 744 /* ------------------------- util_str_time_equal -------------------------- */ 745 746 /* 747 * Function to compare if two time strings are equal 748 * 749 * Acceptable date formats: 750 * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 751 * Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 752 * Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format 753 * 754 * Return 0 if equal, -1 if not equal. 755 */ 756 757 static inline const char * _parse_day_month(const char *p, int *day, int *month) 758 { 759 *day = 0; 760 761 if (*p == ',') { 762 // Parse day and month: ", 06 Nov", ", 06-Nov" 763 p++; 764 if (*p == ' ') 765 p++; 766 while (*p >= '0' && *p <= '9') 767 *day = *day * 10 + (*p++ - '0'); 768 if (*p == ' ' || *p == '-') 769 p++; 770 *month = _mstr2num(p); 771 if (*month != -1) 772 p += 3; 773 } else { 774 // Parse month and day: " Nov 6" 775 if (*p == ' ') 776 p++; 777 *month = _mstr2num(p); 778 if (*month != -1) 779 p += 3; 780 while (*p == ' ') 781 p++; 782 while (*p >= '0' && *p <= '9') 783 *day = *day * 10 + (*p++ - '0'); 784 } 785 786 return p; 787 } 788 789 static inline void _parse_year_time(const char *p, int *year, const char ** time) 790 { 791 int _year = 0; 792 793 if (*p == '-') { 794 // Parse year and time: "-94 08:49:37" 795 p++; 796 while (*p >= '0' && *p <= '9') 797 _year = _year * 10 + (*p++ - '0'); 798 if (_year < 70) { 799 _year += 2000; 800 } else { 801 _year += 1900; 802 } 803 if (*p == ' ') 804 p++; 805 *time = p; 806 } else { 807 // Parse year and time or time and year 808 if (*p == ' ') 809 p++; 810 if (p[0] && p[1] && p[2] == ':') { 811 // Parse time and year: "08:49:37 1994" 812 *time = p; 813 p += 3; 814 while (*p && *p != ' ') 815 p++; 816 if (*p == ' ') 817 p++; 818 while (*p >= '0' && *p <= '9') 819 _year = _year * 10 + (*p++ - '0'); 820 } else { 821 // Parse year and time: "1994 08:49:37" 822 while (*p >= '0' && *p <= '9') 823 _year = _year * 10 + (*p++ - '0'); 824 if (*p == ' ') 825 p++; 826 *time = p; 827 } 828 } 829 830 *year = _year; 831 } 832 833 NSAPI_PUBLIC int util_str_time_equal(const char *t1, const char *t2) 834 { 835 // Skip leading whitespace and day of week 836 while (isspace(*t1)) 837 t1++; 838 while (isalpha(*t1)) 839 t1++; 840 while (isspace(*t2)) 841 t2++; 842 while (isalpha(*t2)) 843 t2++; 844 845 // Day and month: ", 06 Nov", ", 06-Nov", or " Nov 6" 846 int day1; 847 int month1; 848 t1 = _parse_day_month(t1, &day1, &month1); 849 int day2; 850 int month2; 851 t2 = _parse_day_month(t2, &day2, &month2); 852 if (day1 != day2) 853 return -1; 854 if (month1 != month2) 855 return -1; 856 857 // Year and time: " 1994 08:49:37", "-94 08:49:37", or " 08:49:37 1994" 858 int year1; 859 const char *time1; 860 _parse_year_time(t1, &year1, &time1); 861 int year2; 862 const char *time2; 863 _parse_year_time(t2, &year2, &time2); 864 if (year1 != year2) 865 return -1; 866 while (*time1 && *time1 != ' ' && *time1 == *time2) { 867 time1++; 868 time2++; 869 } 870 if (*time2 && *time2 != ' ') 871 return -1; 872 873 return 0; 874 } 875 876 877 /* --------------------------- util_later_than ---------------------------- */ 878 879 static int _time_compare(const struct tm *lms, const char *ims) 880 { 881 while (isspace(*ims)) 882 ims++; 883 while (isalpha(*ims)) 884 ims++; 885 886 int day; 887 int month; 888 ims = _parse_day_month(ims, &day, &month); 889 if (month == -1) 890 return 1; 891 892 int year; 893 const char *time; 894 _parse_year_time(ims, &year, &time); 895 896 int rv; 897 898 rv = (lms->tm_year + 1900) - year; 899 if (rv) 900 return rv; 901 902 rv = lms->tm_mon - month; 903 if (rv) 904 return rv; 905 906 rv = lms->tm_mday - day; 907 if (rv) 908 return rv; 909 910 const char *p = time; 911 912 int hour = 0; 913 while (*p >= '0' && *p <= '9') 914 hour = hour * 10 + (*p++ - '0'); 915 if (*p == ':') 916 p++; 917 918 rv = lms->tm_hour - hour; 919 if (rv) 920 return rv; 921 922 int minutes = 0; 923 while (*p >= '0' && *p <= '9') 924 minutes = minutes * 10 + (*p++ - '0'); 925 if (*p == ':') 926 p++; 927 928 rv = lms->tm_min - minutes; 929 if (rv) 930 return rv; 931 932 int seconds = 0; 933 while (*p >= '0' && *p <= '9') 934 seconds = seconds * 10 + (*p++ - '0'); 935 if (*p == ':') 936 p++; 937 938 rv = lms->tm_sec - seconds; 939 if (rv) 940 return rv; 941 942 return 0; 943 } 944 945 NSAPI_PUBLIC int util_later_than(const struct tm *lms, const char *ims) 946 { 947 /* 948 * Returns 0 if lms later than ims 949 * 0 if ims is malformed 950 * 1 if ims later than lms 951 * 1 if equal 952 */ 953 954 return _time_compare(lms, ims) <= 0; 955 } 956 957 NSAPI_PUBLIC int util_time_equal(const struct tm *lms, const char *ims) 958 { 959 return _time_compare(lms, ims) == 0; 960 } 961 962 963 NSAPI_PUBLIC struct tm * 964 util_gmtime(const time_t *clock, struct tm *res) 965 { 966 return gmtime_r(clock, res); 967 } 968 969 int util_isdate(char *str) { 970 sstr_t datestr = sstr(str); 971 sstr_t example = S("Sun, 06 Nov 1994 08:49:37 GMT"); 972 973 if(datestr.length != example.length) { 974 return 0; 975 } 976 977 for(int i=0;i<datestr.length;i++) { 978 char e = example.ptr[i]; 979 if(isdigit(e)) { 980 if(!isdigit(datestr.ptr[i])) { 981 return 0; 982 } 983 } else if(e == ' ') { 984 if(datestr.ptr[i] != ' ') { 985 return 0; 986 } 987 } else if(e == ',') { 988 if(datestr.ptr[i] != ',') { 989 return 0; 990 } 991 } else if(e == ':') { 992 if(datestr.ptr[i] != ':') { 993 return 0; 994 } 995 } 996 } 997 998 if(!sstrsuffix(datestr, S("GMT"))) { 999 return 0; 1000 } 1001 1002 return 1; 1003 } 1004 1005 1006 /* ------------------------- util_mime_separator -------------------------- */ 1007 1008 1009 NSAPI_PUBLIC int util_mime_separator(char *sep) 1010 { 1011 int size = 35; // documented in nsapi.h 1012 int pos = 0; 1013 1014 sep[pos++] = CR; 1015 sep[pos++] = LF; 1016 sep[pos++] = '-'; 1017 sep[pos++] = '-'; 1018 1019 int r[6]; 1020 for(int i=0;i<6;i++) { 1021 r[i] = rand() % 10000; 1022 } 1023 pos += snprintf( 1024 sep+4, 1025 size-4, 1026 "X%04x%04x%04x%04x%04x%04xE", 1027 r[0], 1028 r[1], 1029 r[2], 1030 r[3], 1031 r[4], 1032 r[5]); 1033 1034 return pos; 1035 } 1036