1 /* 2 * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * * Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * * Neither the name of Redis nor the names of its contributors may be used 14 * to endorse or promote products derived from this software without 15 * specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "fmacros.h" 31 #include <stdlib.h> 32 #include <stdio.h> 33 #include <string.h> 34 #include <ctype.h> 35 #include <limits.h> 36 #include <math.h> 37 #include <unistd.h> 38 #include <sys/time.h> 39 #include <float.h> 40 #include <stdint.h> 41 #include <errno.h> 42 #include <time.h> 43 44 #include "util.h" 45 #include "sha1.h" 46 47 /* Glob-style pattern matching. */ 48 int stringmatchlen(const char *pattern, int patternLen, 49 const char *string, int stringLen, int nocase) 50 { 51 while(patternLen && stringLen) { 52 switch(pattern[0]) { 53 case '*': 54 while (pattern[1] == '*') { 55 pattern++; 56 patternLen--; 57 } 58 if (patternLen == 1) 59 return 1; /* match */ 60 while(stringLen) { 61 if (stringmatchlen(pattern+1, patternLen-1, 62 string, stringLen, nocase)) 63 return 1; /* match */ 64 string++; 65 stringLen--; 66 } 67 return 0; /* no match */ 68 break; 69 case '?': 70 if (stringLen == 0) 71 return 0; /* no match */ 72 string++; 73 stringLen--; 74 break; 75 case '[': 76 { 77 int not, match; 78 79 pattern++; 80 patternLen--; 81 not = pattern[0] == '^'; 82 if (not) { 83 pattern++; 84 patternLen--; 85 } 86 match = 0; 87 while(1) { 88 if (pattern[0] == '\\' && patternLen >= 2) { 89 pattern++; 90 patternLen--; 91 if (pattern[0] == string[0]) 92 match = 1; 93 } else if (pattern[0] == ']') { 94 break; 95 } else if (patternLen == 0) { 96 pattern--; 97 patternLen++; 98 break; 99 } else if (pattern[1] == '-' && patternLen >= 3) { 100 int start = pattern[0]; 101 int end = pattern[2]; 102 int c = string[0]; 103 if (start > end) { 104 int t = start; 105 start = end; 106 end = t; 107 } 108 if (nocase) { 109 start = tolower(start); 110 end = tolower(end); 111 c = tolower(c); 112 } 113 pattern += 2; 114 patternLen -= 2; 115 if (c >= start && c <= end) 116 match = 1; 117 } else { 118 if (!nocase) { 119 if (pattern[0] == string[0]) 120 match = 1; 121 } else { 122 if (tolower((int)pattern[0]) == tolower((int)string[0])) 123 match = 1; 124 } 125 } 126 pattern++; 127 patternLen--; 128 } 129 if (not) 130 match = !match; 131 if (!match) 132 return 0; /* no match */ 133 string++; 134 stringLen--; 135 break; 136 } 137 case '\\': 138 if (patternLen >= 2) { 139 pattern++; 140 patternLen--; 141 } 142 /* fall through */ 143 default: 144 if (!nocase) { 145 if (pattern[0] != string[0]) 146 return 0; /* no match */ 147 } else { 148 if (tolower((int)pattern[0]) != tolower((int)string[0])) 149 return 0; /* no match */ 150 } 151 string++; 152 stringLen--; 153 break; 154 } 155 pattern++; 156 patternLen--; 157 if (stringLen == 0) { 158 while(*pattern == '*') { 159 pattern++; 160 patternLen--; 161 } 162 break; 163 } 164 } 165 if (patternLen == 0 && stringLen == 0) 166 return 1; 167 return 0; 168 } 169 170 int stringmatch(const char *pattern, const char *string, int nocase) { 171 return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase); 172 } 173 174 /* Fuzz stringmatchlen() trying to crash it with bad input. */ 175 int stringmatchlen_fuzz_test(void) { 176 char str[32]; 177 char pat[32]; 178 int cycles = 10000000; 179 int total_matches = 0; 180 while(cycles--) { 181 int strlen = rand() % sizeof(str); 182 int patlen = rand() % sizeof(pat); 183 for (int j = 0; j < strlen; j++) str[j] = rand() % 128; 184 for (int j = 0; j < patlen; j++) pat[j] = rand() % 128; 185 total_matches += stringmatchlen(pat, patlen, str, strlen, 0); 186 } 187 return total_matches; 188 } 189 190 /* Convert a string representing an amount of memory into the number of 191 * bytes, so for instance memtoll("1Gb") will return 1073741824 that is 192 * (1024*1024*1024). 193 * 194 * On parsing error, if *err is not NULL, it's set to 1, otherwise it's 195 * set to 0. On error the function return value is 0, regardless of the 196 * fact 'err' is NULL or not. */ 197 long long memtoll(const char *p, int *err) { 198 const char *u; 199 char buf[128]; 200 long mul; /* unit multiplier */ 201 long long val; 202 unsigned int digits; 203 204 if (err) *err = 0; 205 206 /* Search the first non digit character. */ 207 u = p; 208 if (*u == '-') u++; 209 while(*u && isdigit(*u)) u++; 210 if (*u == '\0' || !strcasecmp(u,"b")) { 211 mul = 1; 212 } else if (!strcasecmp(u,"k")) { 213 mul = 1000; 214 } else if (!strcasecmp(u,"kb")) { 215 mul = 1024; 216 } else if (!strcasecmp(u,"m")) { 217 mul = 1000*1000; 218 } else if (!strcasecmp(u,"mb")) { 219 mul = 1024*1024; 220 } else if (!strcasecmp(u,"g")) { 221 mul = 1000L*1000*1000; 222 } else if (!strcasecmp(u,"gb")) { 223 mul = 1024L*1024*1024; 224 } else { 225 if (err) *err = 1; 226 return 0; 227 } 228 229 /* Copy the digits into a buffer, we'll use strtoll() to convert 230 * the digit (without the unit) into a number. */ 231 digits = u-p; 232 if (digits >= sizeof(buf)) { 233 if (err) *err = 1; 234 return 0; 235 } 236 memcpy(buf,p,digits); 237 buf[digits] = '\0'; 238 239 char *endptr; 240 errno = 0; 241 val = strtoll(buf,&endptr,10); 242 if ((val == 0 && errno == EINVAL) || *endptr != '\0') { 243 if (err) *err = 1; 244 return 0; 245 } 246 return val*mul; 247 } 248 249 /* Return the number of digits of 'v' when converted to string in radix 10. 250 * See ll2string() for more information. */ 251 uint32_t digits10(uint64_t v) { 252 if (v < 10) return 1; 253 if (v < 100) return 2; 254 if (v < 1000) return 3; 255 if (v < 1000000000000UL) { 256 if (v < 100000000UL) { 257 if (v < 1000000) { 258 if (v < 10000) return 4; 259 return 5 + (v >= 100000); 260 } 261 return 7 + (v >= 10000000UL); 262 } 263 if (v < 10000000000UL) { 264 return 9 + (v >= 1000000000UL); 265 } 266 return 11 + (v >= 100000000000UL); 267 } 268 return 12 + digits10(v / 1000000000000UL); 269 } 270 271 /* Like digits10() but for signed values. */ 272 uint32_t sdigits10(int64_t v) { 273 if (v < 0) { 274 /* Abs value of LLONG_MIN requires special handling. */ 275 uint64_t uv = (v != LLONG_MIN) ? 276 (uint64_t)-v : ((uint64_t) LLONG_MAX)+1; 277 return digits10(uv)+1; /* +1 for the minus. */ 278 } else { 279 return digits10(v); 280 } 281 } 282 283 /* Convert a long long into a string. Returns the number of 284 * characters needed to represent the number. 285 * If the buffer is not big enough to store the string, 0 is returned. 286 * 287 * Based on the following article (that apparently does not provide a 288 * novel approach but only publicizes an already used technique): 289 * 290 * https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920 291 * 292 * Modified in order to handle signed integers since the original code was 293 * designed for unsigned integers. */ 294 int ll2string(char *dst, size_t dstlen, long long svalue) { 295 static const char digits[201] = 296 "0001020304050607080910111213141516171819" 297 "2021222324252627282930313233343536373839" 298 "4041424344454647484950515253545556575859" 299 "6061626364656667686970717273747576777879" 300 "8081828384858687888990919293949596979899"; 301 int negative; 302 unsigned long long value; 303 304 /* The main loop works with 64bit unsigned integers for simplicity, so 305 * we convert the number here and remember if it is negative. */ 306 if (svalue < 0) { 307 if (svalue != LLONG_MIN) { 308 value = -svalue; 309 } else { 310 value = ((unsigned long long) LLONG_MAX)+1; 311 } 312 negative = 1; 313 } else { 314 value = svalue; 315 negative = 0; 316 } 317 318 /* Check length. */ 319 uint32_t const length = digits10(value)+negative; 320 if (length >= dstlen) return 0; 321 322 /* Null term. */ 323 uint32_t next = length; 324 dst[next] = '\0'; 325 next--; 326 while (value >= 100) { 327 int const i = (value % 100) * 2; 328 value /= 100; 329 dst[next] = digits[i + 1]; 330 dst[next - 1] = digits[i]; 331 next -= 2; 332 } 333 334 /* Handle last 1-2 digits. */ 335 if (value < 10) { 336 dst[next] = '0' + (uint32_t) value; 337 } else { 338 int i = (uint32_t) value * 2; 339 dst[next] = digits[i + 1]; 340 dst[next - 1] = digits[i]; 341 } 342 343 /* Add sign. */ 344 if (negative) dst[0] = '-'; 345 return length; 346 } 347 348 /* Convert a string into a long long. Returns 1 if the string could be parsed 349 * into a (non-overflowing) long long, 0 otherwise. The value will be set to 350 * the parsed value when appropriate. 351 * 352 * Note that this function demands that the string strictly represents 353 * a long long: no spaces or other characters before or after the string 354 * representing the number are accepted, nor zeroes at the start if not 355 * for the string "0" representing the zero number. 356 * 357 * Because of its strictness, it is safe to use this function to check if 358 * you can convert a string into a long long, and obtain back the string 359 * from the number without any loss in the string representation. */ 360 int string2ll(const char *s, size_t slen, long long *value) { 361 const char *p = s; 362 size_t plen = 0; 363 int negative = 0; 364 unsigned long long v; 365 366 /* A zero length string is not a valid number. */ 367 if (plen == slen) 368 return 0; 369 370 /* Special case: first and only digit is 0. */ 371 if (slen == 1 && p[0] == '0') { 372 if (value != NULL) *value = 0; 373 return 1; 374 } 375 376 /* Handle negative numbers: just set a flag and continue like if it 377 * was a positive number. Later convert into negative. */ 378 if (p[0] == '-') { 379 negative = 1; 380 p++; plen++; 381 382 /* Abort on only a negative sign. */ 383 if (plen == slen) 384 return 0; 385 } 386 387 /* First digit should be 1-9, otherwise the string should just be 0. */ 388 if (p[0] >= '1' && p[0] <= '9') { 389 v = p[0]-'0'; 390 p++; plen++; 391 } else { 392 return 0; 393 } 394 395 /* Parse all the other digits, checking for overflow at every step. */ 396 while (plen < slen && p[0] >= '0' && p[0] <= '9') { 397 if (v > (ULLONG_MAX / 10)) /* Overflow. */ 398 return 0; 399 v *= 10; 400 401 if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */ 402 return 0; 403 v += p[0]-'0'; 404 405 p++; plen++; 406 } 407 408 /* Return if not all bytes were used. */ 409 if (plen < slen) 410 return 0; 411 412 /* Convert to negative if needed, and do the final overflow check when 413 * converting from unsigned long long to long long. */ 414 if (negative) { 415 if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */ 416 return 0; 417 if (value != NULL) *value = -v; 418 } else { 419 if (v > LLONG_MAX) /* Overflow. */ 420 return 0; 421 if (value != NULL) *value = v; 422 } 423 return 1; 424 } 425 426 /* Convert a string into a long. Returns 1 if the string could be parsed into a 427 * (non-overflowing) long, 0 otherwise. The value will be set to the parsed 428 * value when appropriate. */ 429 int string2l(const char *s, size_t slen, long *lval) { 430 long long llval; 431 432 if (!string2ll(s,slen,&llval)) 433 return 0; 434 435 if (llval < LONG_MIN || llval > LONG_MAX) 436 return 0; 437 438 *lval = (long)llval; 439 return 1; 440 } 441 442 /* Convert a string into a double. Returns 1 if the string could be parsed 443 * into a (non-overflowing) double, 0 otherwise. The value will be set to 444 * the parsed value when appropriate. 445 * 446 * Note that this function demands that the string strictly represents 447 * a double: no spaces or other characters before or after the string 448 * representing the number are accepted. */ 449 int string2ld(const char *s, size_t slen, long double *dp) { 450 char buf[MAX_LONG_DOUBLE_CHARS]; 451 long double value; 452 char *eptr; 453 454 if (slen >= sizeof(buf)) return 0; 455 memcpy(buf,s,slen); 456 buf[slen] = '\0'; 457 458 errno = 0; 459 value = strtold(buf, &eptr); 460 if (isspace(buf[0]) || eptr[0] != '\0' || 461 (errno == ERANGE && 462 (value == HUGE_VAL || value == -HUGE_VAL || value == 0)) || 463 errno == EINVAL || 464 isnan(value)) 465 return 0; 466 467 if (dp) *dp = value; 468 return 1; 469 } 470 471 /* Convert a double to a string representation. Returns the number of bytes 472 * required. The representation should always be parsable by strtod(3). 473 * This function does not support human-friendly formatting like ld2string 474 * does. It is intended mainly to be used inside t_zset.c when writing scores 475 * into a ziplist representing a sorted set. */ 476 int d2string(char *buf, size_t len, double value) { 477 if (isnan(value)) { 478 len = snprintf(buf,len,"nan"); 479 } else if (isinf(value)) { 480 if (value < 0) 481 len = snprintf(buf,len,"-inf"); 482 else 483 len = snprintf(buf,len,"inf"); 484 } else if (value == 0) { 485 /* See: http://en.wikipedia.org/wiki/Signed_zero, "Comparisons". */ 486 if (1.0/value < 0) 487 len = snprintf(buf,len,"-0"); 488 else 489 len = snprintf(buf,len,"0"); 490 } else { 491 #if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL) 492 /* Check if the float is in a safe range to be casted into a 493 * long long. We are assuming that long long is 64 bit here. 494 * Also we are assuming that there are no implementations around where 495 * double has precision < 52 bit. 496 * 497 * Under this assumptions we test if a double is inside an interval 498 * where casting to long long is safe. Then using two castings we 499 * make sure the decimal part is zero. If all this is true we use 500 * integer printing function that is much faster. */ 501 double min = -4503599627370495; /* (2^52)-1 */ 502 double max = 4503599627370496; /* -(2^52) */ 503 if (value > min && value < max && value == ((double)((long long)value))) 504 len = ll2string(buf,len,(long long)value); 505 else 506 #endif 507 len = snprintf(buf,len,"%.17g",value); 508 } 509 510 return len; 511 } 512 513 /* Convert a long double into a string. If humanfriendly is non-zero 514 * it does not use exponential format and trims trailing zeroes at the end, 515 * however this results in loss of precision. Otherwise exp format is used 516 * and the output of snprintf() is not modified. 517 * 518 * The function returns the length of the string or zero if there was not 519 * enough buffer room to store it. */ 520 int ld2string(char *buf, size_t len, long double value, int humanfriendly) { 521 size_t l; 522 523 if (isinf(value)) { 524 /* Libc in odd systems (Hi Solaris!) will format infinite in a 525 * different way, so better to handle it in an explicit way. */ 526 if (len < 5) return 0; /* No room. 5 is "-inf\0" */ 527 if (value > 0) { 528 memcpy(buf,"inf",3); 529 l = 3; 530 } else { 531 memcpy(buf,"-inf",4); 532 l = 4; 533 } 534 } else if (humanfriendly) { 535 /* We use 17 digits precision since with 128 bit floats that precision 536 * after rounding is able to represent most small decimal numbers in a 537 * way that is "non surprising" for the user (that is, most small 538 * decimal numbers will be represented in a way that when converted 539 * back into a string are exactly the same as what the user typed.) */ 540 l = snprintf(buf,len,"%.17Lf", value); 541 if (l+1 > len) return 0; /* No room. */ 542 /* Now remove trailing zeroes after the '.' */ 543 if (strchr(buf,'.') != NULL) { 544 char *p = buf+l-1; 545 while(*p == '0') { 546 p--; 547 l--; 548 } 549 if (*p == '.') l--; 550 } 551 } else { 552 l = snprintf(buf,len,"%.17Lg", value); 553 if (l+1 > len) return 0; /* No room. */ 554 } 555 buf[l] = '\0'; 556 return l; 557 } 558 559 /* Get random bytes, attempts to get an initial seed from /dev/urandom and 560 * the uses a one way hash function in counter mode to generate a random 561 * stream. However if /dev/urandom is not available, a weaker seed is used. 562 * 563 * This function is not thread safe, since the state is global. */ 564 void getRandomBytes(unsigned char *p, size_t len) { 565 /* Global state. */ 566 static int seed_initialized = 0; 567 static unsigned char seed[20]; /* The SHA1 seed, from /dev/urandom. */ 568 static uint64_t counter = 0; /* The counter we hash with the seed. */ 569 570 if (!seed_initialized) { 571 /* Initialize a seed and use SHA1 in counter mode, where we hash 572 * the same seed with a progressive counter. For the goals of this 573 * function we just need non-colliding strings, there are no 574 * cryptographic security needs. */ 575 FILE *fp = fopen("/dev/urandom","r"); 576 if (fp == NULL || fread(seed,sizeof(seed),1,fp) != 1) { 577 /* Revert to a weaker seed, and in this case reseed again 578 * at every call.*/ 579 for (unsigned int j = 0; j < sizeof(seed); j++) { 580 struct timeval tv; 581 gettimeofday(&tv,NULL); 582 pid_t pid = getpid(); 583 seed[j] = tv.tv_sec ^ tv.tv_usec ^ pid ^ (long)fp; 584 } 585 } else { 586 seed_initialized = 1; 587 } 588 if (fp) fclose(fp); 589 } 590 591 while(len) { 592 unsigned char digest[20]; 593 SHA1_CTX ctx; 594 unsigned int copylen = len > 20 ? 20 : len; 595 596 SHA1Init(&ctx); 597 SHA1Update(&ctx, seed, sizeof(seed)); 598 SHA1Update(&ctx, (unsigned char*)&counter,sizeof(counter)); 599 SHA1Final(digest, &ctx); 600 counter++; 601 602 memcpy(p,digest,copylen); 603 len -= copylen; 604 p += copylen; 605 } 606 } 607 608 /* Generate the Redis "Run ID", a SHA1-sized random number that identifies a 609 * given execution of Redis, so that if you are talking with an instance 610 * having run_id == A, and you reconnect and it has run_id == B, you can be 611 * sure that it is either a different instance or it was restarted. */ 612 void getRandomHexChars(char *p, size_t len) { 613 char *charset = "0123456789abcdef"; 614 size_t j; 615 616 getRandomBytes((unsigned char*)p,len); 617 for (j = 0; j < len; j++) p[j] = charset[p[j] & 0x0F]; 618 } 619 620 /* Given the filename, return the absolute path as an SDS string, or NULL 621 * if it fails for some reason. Note that "filename" may be an absolute path 622 * already, this will be detected and handled correctly. 623 * 624 * The function does not try to normalize everything, but only the obvious 625 * case of one or more "../" appearing at the start of "filename" 626 * relative path. */ 627 sds getAbsolutePath(char *filename) { 628 char cwd[1024]; 629 sds abspath; 630 sds relpath = sdsnew(filename); 631 632 relpath = sdstrim(relpath," \r\n\t"); 633 if (relpath[0] == '/') return relpath; /* Path is already absolute. */ 634 635 /* If path is relative, join cwd and relative path. */ 636 if (getcwd(cwd,sizeof(cwd)) == NULL) { 637 sdsfree(relpath); 638 return NULL; 639 } 640 abspath = sdsnew(cwd); 641 if (sdslen(abspath) && abspath[sdslen(abspath)-1] != '/') 642 abspath = sdscat(abspath,"/"); 643 644 /* At this point we have the current path always ending with "/", and 645 * the trimmed relative path. Try to normalize the obvious case of 646 * trailing ../ elements at the start of the path. 647 * 648 * For every "../" we find in the filename, we remove it and also remove 649 * the last element of the cwd, unless the current cwd is "/". */ 650 while (sdslen(relpath) >= 3 && 651 relpath[0] == '.' && relpath[1] == '.' && relpath[2] == '/') 652 { 653 sdsrange(relpath,3,-1); 654 if (sdslen(abspath) > 1) { 655 char *p = abspath + sdslen(abspath)-2; 656 int trimlen = 1; 657 658 while(*p != '/') { 659 p--; 660 trimlen++; 661 } 662 sdsrange(abspath,0,-(trimlen+1)); 663 } 664 } 665 666 /* Finally glue the two parts together. */ 667 abspath = sdscatsds(abspath,relpath); 668 sdsfree(relpath); 669 return abspath; 670 } 671 672 /* 673 * Gets the proper timezone in a more portable fashion 674 * i.e timezone variables are linux specific. 675 */ 676 677 unsigned long getTimeZone(void) { 678 #ifdef __linux__ 679 return timezone; 680 #else 681 struct timeval tv; 682 struct timezone tz; 683 684 gettimeofday(&tv, &tz); 685 686 return tz.tz_minuteswest * 60UL; 687 #endif 688 } 689 690 /* Return true if the specified path is just a file basename without any 691 * relative or absolute path. This function just checks that no / or \ 692 * character exists inside the specified path, that's enough in the 693 * environments where Redis runs. */ 694 int pathIsBaseName(char *path) { 695 return strchr(path,'/') == NULL && strchr(path,'\\') == NULL; 696 } 697 698 #ifdef REDIS_TEST 699 #include <assert.h> 700 701 static void test_string2ll(void) { 702 char buf[32]; 703 long long v; 704 705 /* May not start with +. */ 706 strcpy(buf,"+1"); 707 assert(string2ll(buf,strlen(buf),&v) == 0); 708 709 /* Leading space. */ 710 strcpy(buf," 1"); 711 assert(string2ll(buf,strlen(buf),&v) == 0); 712 713 /* Trailing space. */ 714 strcpy(buf,"1 "); 715 assert(string2ll(buf,strlen(buf),&v) == 0); 716 717 /* May not start with 0. */ 718 strcpy(buf,"01"); 719 assert(string2ll(buf,strlen(buf),&v) == 0); 720 721 strcpy(buf,"-1"); 722 assert(string2ll(buf,strlen(buf),&v) == 1); 723 assert(v == -1); 724 725 strcpy(buf,"0"); 726 assert(string2ll(buf,strlen(buf),&v) == 1); 727 assert(v == 0); 728 729 strcpy(buf,"1"); 730 assert(string2ll(buf,strlen(buf),&v) == 1); 731 assert(v == 1); 732 733 strcpy(buf,"99"); 734 assert(string2ll(buf,strlen(buf),&v) == 1); 735 assert(v == 99); 736 737 strcpy(buf,"-99"); 738 assert(string2ll(buf,strlen(buf),&v) == 1); 739 assert(v == -99); 740 741 strcpy(buf,"-9223372036854775808"); 742 assert(string2ll(buf,strlen(buf),&v) == 1); 743 assert(v == LLONG_MIN); 744 745 strcpy(buf,"-9223372036854775809"); /* overflow */ 746 assert(string2ll(buf,strlen(buf),&v) == 0); 747 748 strcpy(buf,"9223372036854775807"); 749 assert(string2ll(buf,strlen(buf),&v) == 1); 750 assert(v == LLONG_MAX); 751 752 strcpy(buf,"9223372036854775808"); /* overflow */ 753 assert(string2ll(buf,strlen(buf),&v) == 0); 754 } 755 756 static void test_string2l(void) { 757 char buf[32]; 758 long v; 759 760 /* May not start with +. */ 761 strcpy(buf,"+1"); 762 assert(string2l(buf,strlen(buf),&v) == 0); 763 764 /* May not start with 0. */ 765 strcpy(buf,"01"); 766 assert(string2l(buf,strlen(buf),&v) == 0); 767 768 strcpy(buf,"-1"); 769 assert(string2l(buf,strlen(buf),&v) == 1); 770 assert(v == -1); 771 772 strcpy(buf,"0"); 773 assert(string2l(buf,strlen(buf),&v) == 1); 774 assert(v == 0); 775 776 strcpy(buf,"1"); 777 assert(string2l(buf,strlen(buf),&v) == 1); 778 assert(v == 1); 779 780 strcpy(buf,"99"); 781 assert(string2l(buf,strlen(buf),&v) == 1); 782 assert(v == 99); 783 784 strcpy(buf,"-99"); 785 assert(string2l(buf,strlen(buf),&v) == 1); 786 assert(v == -99); 787 788 #if LONG_MAX != LLONG_MAX 789 strcpy(buf,"-2147483648"); 790 assert(string2l(buf,strlen(buf),&v) == 1); 791 assert(v == LONG_MIN); 792 793 strcpy(buf,"-2147483649"); /* overflow */ 794 assert(string2l(buf,strlen(buf),&v) == 0); 795 796 strcpy(buf,"2147483647"); 797 assert(string2l(buf,strlen(buf),&v) == 1); 798 assert(v == LONG_MAX); 799 800 strcpy(buf,"2147483648"); /* overflow */ 801 assert(string2l(buf,strlen(buf),&v) == 0); 802 #endif 803 } 804 805 static void test_ll2string(void) { 806 char buf[32]; 807 long long v; 808 int sz; 809 810 v = 0; 811 sz = ll2string(buf, sizeof buf, v); 812 assert(sz == 1); 813 assert(!strcmp(buf, "0")); 814 815 v = -1; 816 sz = ll2string(buf, sizeof buf, v); 817 assert(sz == 2); 818 assert(!strcmp(buf, "-1")); 819 820 v = 99; 821 sz = ll2string(buf, sizeof buf, v); 822 assert(sz == 2); 823 assert(!strcmp(buf, "99")); 824 825 v = -99; 826 sz = ll2string(buf, sizeof buf, v); 827 assert(sz == 3); 828 assert(!strcmp(buf, "-99")); 829 830 v = -2147483648; 831 sz = ll2string(buf, sizeof buf, v); 832 assert(sz == 11); 833 assert(!strcmp(buf, "-2147483648")); 834 835 v = LLONG_MIN; 836 sz = ll2string(buf, sizeof buf, v); 837 assert(sz == 20); 838 assert(!strcmp(buf, "-9223372036854775808")); 839 840 v = LLONG_MAX; 841 sz = ll2string(buf, sizeof buf, v); 842 assert(sz == 19); 843 assert(!strcmp(buf, "9223372036854775807")); 844 } 845 846 #define UNUSED(x) (void)(x) 847 int utilTest(int argc, char **argv) { 848 UNUSED(argc); 849 UNUSED(argv); 850 851 test_string2ll(); 852 test_string2l(); 853 test_ll2string(); 854 return 0; 855 } 856 #endif 857