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
43 #include "util.h"
44 #include "sha1.h"
45
46 /* Glob-style pattern matching. */
stringmatchlen(const char * pattern,int patternLen,const char * string,int stringLen,int nocase)47 int stringmatchlen(const char *pattern, int patternLen,
48 const char *string, int stringLen, int nocase)
49 {
50 while(patternLen) {
51 switch(pattern[0]) {
52 case '*':
53 while (pattern[1] == '*') {
54 pattern++;
55 patternLen--;
56 }
57 if (patternLen == 1)
58 return 1; /* match */
59 while(stringLen) {
60 if (stringmatchlen(pattern+1, patternLen-1,
61 string, stringLen, nocase))
62 return 1; /* match */
63 string++;
64 stringLen--;
65 }
66 return 0; /* no match */
67 break;
68 case '?':
69 if (stringLen == 0)
70 return 0; /* no match */
71 string++;
72 stringLen--;
73 break;
74 case '[':
75 {
76 int not, match;
77
78 pattern++;
79 patternLen--;
80 not = pattern[0] == '^';
81 if (not) {
82 pattern++;
83 patternLen--;
84 }
85 match = 0;
86 while(1) {
87 if (pattern[0] == '\\') {
88 pattern++;
89 patternLen--;
90 if (pattern[0] == string[0])
91 match = 1;
92 } else if (pattern[0] == ']') {
93 break;
94 } else if (patternLen == 0) {
95 pattern--;
96 patternLen++;
97 break;
98 } else if (pattern[1] == '-' && patternLen >= 3) {
99 int start = pattern[0];
100 int end = pattern[2];
101 int c = string[0];
102 if (start > end) {
103 int t = start;
104 start = end;
105 end = t;
106 }
107 if (nocase) {
108 start = tolower(start);
109 end = tolower(end);
110 c = tolower(c);
111 }
112 pattern += 2;
113 patternLen -= 2;
114 if (c >= start && c <= end)
115 match = 1;
116 } else {
117 if (!nocase) {
118 if (pattern[0] == string[0])
119 match = 1;
120 } else {
121 if (tolower((int)pattern[0]) == tolower((int)string[0]))
122 match = 1;
123 }
124 }
125 pattern++;
126 patternLen--;
127 }
128 if (not)
129 match = !match;
130 if (!match)
131 return 0; /* no match */
132 string++;
133 stringLen--;
134 break;
135 }
136 case '\\':
137 if (patternLen >= 2) {
138 pattern++;
139 patternLen--;
140 }
141 /* fall through */
142 default:
143 if (!nocase) {
144 if (pattern[0] != string[0])
145 return 0; /* no match */
146 } else {
147 if (tolower((int)pattern[0]) != tolower((int)string[0]))
148 return 0; /* no match */
149 }
150 string++;
151 stringLen--;
152 break;
153 }
154 pattern++;
155 patternLen--;
156 if (stringLen == 0) {
157 while(*pattern == '*') {
158 pattern++;
159 patternLen--;
160 }
161 break;
162 }
163 }
164 if (patternLen == 0 && stringLen == 0)
165 return 1;
166 return 0;
167 }
168
stringmatch(const char * pattern,const char * string,int nocase)169 int stringmatch(const char *pattern, const char *string, int nocase) {
170 return stringmatchlen(pattern,strlen(pattern),string,strlen(string),nocase);
171 }
172
173 /* Convert a string representing an amount of memory into the number of
174 * bytes, so for instance memtoll("1Gb") will return 1073741824 that is
175 * (1024*1024*1024).
176 *
177 * On parsing error, if *err is not NULL, it's set to 1, otherwise it's
178 * set to 0. On error the function return value is 0, regardless of the
179 * fact 'err' is NULL or not. */
memtoll(const char * p,int * err)180 long long memtoll(const char *p, int *err) {
181 const char *u;
182 char buf[128];
183 long mul; /* unit multiplier */
184 long long val;
185 unsigned int digits;
186
187 if (err) *err = 0;
188
189 /* Search the first non digit character. */
190 u = p;
191 if (*u == '-') u++;
192 while(*u && isdigit(*u)) u++;
193 if (*u == '\0' || !strcasecmp(u,"b")) {
194 mul = 1;
195 } else if (!strcasecmp(u,"k")) {
196 mul = 1000;
197 } else if (!strcasecmp(u,"kb")) {
198 mul = 1024;
199 } else if (!strcasecmp(u,"m")) {
200 mul = 1000*1000;
201 } else if (!strcasecmp(u,"mb")) {
202 mul = 1024*1024;
203 } else if (!strcasecmp(u,"g")) {
204 mul = 1000L*1000*1000;
205 } else if (!strcasecmp(u,"gb")) {
206 mul = 1024L*1024*1024;
207 } else {
208 if (err) *err = 1;
209 return 0;
210 }
211
212 /* Copy the digits into a buffer, we'll use strtoll() to convert
213 * the digit (without the unit) into a number. */
214 digits = u-p;
215 if (digits >= sizeof(buf)) {
216 if (err) *err = 1;
217 return 0;
218 }
219 memcpy(buf,p,digits);
220 buf[digits] = '\0';
221
222 char *endptr;
223 errno = 0;
224 val = strtoll(buf,&endptr,10);
225 if ((val == 0 && errno == EINVAL) || *endptr != '\0') {
226 if (err) *err = 1;
227 return 0;
228 }
229 return val*mul;
230 }
231
232 /* Return the number of digits of 'v' when converted to string in radix 10.
233 * See ll2string() for more information. */
digits10(uint64_t v)234 uint32_t digits10(uint64_t v) {
235 if (v < 10) return 1;
236 if (v < 100) return 2;
237 if (v < 1000) return 3;
238 if (v < 1000000000000UL) {
239 if (v < 100000000UL) {
240 if (v < 1000000) {
241 if (v < 10000) return 4;
242 return 5 + (v >= 100000);
243 }
244 return 7 + (v >= 10000000UL);
245 }
246 if (v < 10000000000UL) {
247 return 9 + (v >= 1000000000UL);
248 }
249 return 11 + (v >= 100000000000UL);
250 }
251 return 12 + digits10(v / 1000000000000UL);
252 }
253
254 /* Like digits10() but for signed values. */
sdigits10(int64_t v)255 uint32_t sdigits10(int64_t v) {
256 if (v < 0) {
257 /* Abs value of LLONG_MIN requires special handling. */
258 uint64_t uv = (v != LLONG_MIN) ?
259 (uint64_t)-v : ((uint64_t) LLONG_MAX)+1;
260 return digits10(uv)+1; /* +1 for the minus. */
261 } else {
262 return digits10(v);
263 }
264 }
265
266 /* Convert a long long into a string. Returns the number of
267 * characters needed to represent the number.
268 * If the buffer is not big enough to store the string, 0 is returned.
269 *
270 * Based on the following article (that apparently does not provide a
271 * novel approach but only publicizes an already used technique):
272 *
273 * https://www.facebook.com/notes/facebook-engineering/three-optimization-tips-for-c/10151361643253920
274 *
275 * Modified in order to handle signed integers since the original code was
276 * designed for unsigned integers. */
ll2string(char * dst,size_t dstlen,long long svalue)277 int ll2string(char* dst, size_t dstlen, long long svalue) {
278 static const char digits[201] =
279 "0001020304050607080910111213141516171819"
280 "2021222324252627282930313233343536373839"
281 "4041424344454647484950515253545556575859"
282 "6061626364656667686970717273747576777879"
283 "8081828384858687888990919293949596979899";
284 int negative;
285 unsigned long long value;
286
287 /* The main loop works with 64bit unsigned integers for simplicity, so
288 * we convert the number here and remember if it is negative. */
289 if (svalue < 0) {
290 if (svalue != LLONG_MIN) {
291 value = -svalue;
292 } else {
293 value = ((unsigned long long) LLONG_MAX)+1;
294 }
295 negative = 1;
296 } else {
297 value = svalue;
298 negative = 0;
299 }
300
301 /* Check length. */
302 uint32_t const length = digits10(value)+negative;
303 if (length >= dstlen) return 0;
304
305 /* Null term. */
306 uint32_t next = length;
307 dst[next] = '\0';
308 next--;
309 while (value >= 100) {
310 int const i = (value % 100) * 2;
311 value /= 100;
312 dst[next] = digits[i + 1];
313 dst[next - 1] = digits[i];
314 next -= 2;
315 }
316
317 /* Handle last 1-2 digits. */
318 if (value < 10) {
319 dst[next] = '0' + (uint32_t) value;
320 } else {
321 int i = (uint32_t) value * 2;
322 dst[next] = digits[i + 1];
323 dst[next - 1] = digits[i];
324 }
325
326 /* Add sign. */
327 if (negative) dst[0] = '-';
328 return length;
329 }
330
331 /* Convert a string into a long long. Returns 1 if the string could be parsed
332 * into a (non-overflowing) long long, 0 otherwise. The value will be set to
333 * the parsed value when appropriate. */
string2ll(const char * s,size_t slen,long long * value)334 int string2ll(const char *s, size_t slen, long long *value) {
335 const char *p = s;
336 size_t plen = 0;
337 int negative = 0;
338 unsigned long long v;
339
340 if (plen == slen)
341 return 0;
342
343 /* Special case: first and only digit is 0. */
344 if (slen == 1 && p[0] == '0') {
345 if (value != NULL) *value = 0;
346 return 1;
347 }
348
349 if (p[0] == '-') {
350 negative = 1;
351 p++; plen++;
352
353 /* Abort on only a negative sign. */
354 if (plen == slen)
355 return 0;
356 }
357
358 /* First digit should be 1-9, otherwise the string should just be 0. */
359 if (p[0] >= '1' && p[0] <= '9') {
360 v = p[0]-'0';
361 p++; plen++;
362 } else if (p[0] == '0' && slen == 1) {
363 *value = 0;
364 return 1;
365 } else {
366 return 0;
367 }
368
369 while (plen < slen && p[0] >= '0' && p[0] <= '9') {
370 if (v > (ULLONG_MAX / 10)) /* Overflow. */
371 return 0;
372 v *= 10;
373
374 if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */
375 return 0;
376 v += p[0]-'0';
377
378 p++; plen++;
379 }
380
381 /* Return if not all bytes were used. */
382 if (plen < slen)
383 return 0;
384
385 if (negative) {
386 if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */
387 return 0;
388 if (value != NULL) *value = -v;
389 } else {
390 if (v > LLONG_MAX) /* Overflow. */
391 return 0;
392 if (value != NULL) *value = v;
393 }
394 return 1;
395 }
396
397 /* Convert a string into a long. Returns 1 if the string could be parsed into a
398 * (non-overflowing) long, 0 otherwise. The value will be set to the parsed
399 * value when appropriate. */
string2l(const char * s,size_t slen,long * lval)400 int string2l(const char *s, size_t slen, long *lval) {
401 long long llval;
402
403 if (!string2ll(s,slen,&llval))
404 return 0;
405
406 if (llval < LONG_MIN || llval > LONG_MAX)
407 return 0;
408
409 *lval = (long)llval;
410 return 1;
411 }
412
413 /* Convert a double to a string representation. Returns the number of bytes
414 * required. The representation should always be parsable by strtod(3). */
d2string(char * buf,size_t len,double value)415 int d2string(char *buf, size_t len, double value) {
416 if (isnan(value)) {
417 len = snprintf(buf,len,"nan");
418 } else if (isinf(value)) {
419 if (value < 0)
420 len = snprintf(buf,len,"-inf");
421 else
422 len = snprintf(buf,len,"inf");
423 } else if (value == 0) {
424 /* See: http://en.wikipedia.org/wiki/Signed_zero, "Comparisons". */
425 if (1.0/value < 0)
426 len = snprintf(buf,len,"-0");
427 else
428 len = snprintf(buf,len,"0");
429 } else {
430 #if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL)
431 /* Check if the float is in a safe range to be casted into a
432 * long long. We are assuming that long long is 64 bit here.
433 * Also we are assuming that there are no implementations around where
434 * double has precision < 52 bit.
435 *
436 * Under this assumptions we test if a double is inside an interval
437 * where casting to long long is safe. Then using two castings we
438 * make sure the decimal part is zero. If all this is true we use
439 * integer printing function that is much faster. */
440 double min = -4503599627370495; /* (2^52)-1 */
441 double max = 4503599627370496; /* -(2^52) */
442 if (value > min && value < max && value == ((double)((long long)value)))
443 len = ll2string(buf,len,(long long)value);
444 else
445 #endif
446 len = snprintf(buf,len,"%.17g",value);
447 }
448
449 return len;
450 }
451
452 /* Generate the Redis "Run ID", a SHA1-sized random number that identifies a
453 * given execution of Redis, so that if you are talking with an instance
454 * having run_id == A, and you reconnect and it has run_id == B, you can be
455 * sure that it is either a different instance or it was restarted. */
getRandomHexChars(char * p,unsigned int len)456 void getRandomHexChars(char *p, unsigned int len) {
457 char *charset = "0123456789abcdef";
458 unsigned int j;
459
460 /* Global state. */
461 static int seed_initialized = 0;
462 static unsigned char seed[20]; /* The SHA1 seed, from /dev/urandom. */
463 static uint64_t counter = 0; /* The counter we hash with the seed. */
464
465 if (!seed_initialized) {
466 /* Initialize a seed and use SHA1 in counter mode, where we hash
467 * the same seed with a progressive counter. For the goals of this
468 * function we just need non-colliding strings, there are no
469 * cryptographic security needs. */
470 FILE *fp = fopen("/dev/urandom","r");
471 if (fp && fread(seed,sizeof(seed),1,fp) == 1)
472 seed_initialized = 1;
473 if (fp) fclose(fp);
474 }
475
476 if (seed_initialized) {
477 while(len) {
478 unsigned char digest[20];
479 SHA1_CTX ctx;
480 unsigned int copylen = len > 20 ? 20 : len;
481
482 SHA1Init(&ctx);
483 SHA1Update(&ctx, seed, sizeof(seed));
484 SHA1Update(&ctx, (unsigned char*)&counter,sizeof(counter));
485 SHA1Final(digest, &ctx);
486 counter++;
487
488 memcpy(p,digest,copylen);
489 /* Convert to hex digits. */
490 for (j = 0; j < copylen; j++) p[j] = charset[p[j] & 0x0F];
491 len -= copylen;
492 p += copylen;
493 }
494 } else {
495 /* If we can't read from /dev/urandom, do some reasonable effort
496 * in order to create some entropy, since this function is used to
497 * generate run_id and cluster instance IDs */
498 char *x = p;
499 unsigned int l = len;
500 struct timeval tv;
501 pid_t pid = getpid();
502
503 /* Use time and PID to fill the initial array. */
504 gettimeofday(&tv,NULL);
505 if (l >= sizeof(tv.tv_usec)) {
506 memcpy(x,&tv.tv_usec,sizeof(tv.tv_usec));
507 l -= sizeof(tv.tv_usec);
508 x += sizeof(tv.tv_usec);
509 }
510 if (l >= sizeof(tv.tv_sec)) {
511 memcpy(x,&tv.tv_sec,sizeof(tv.tv_sec));
512 l -= sizeof(tv.tv_sec);
513 x += sizeof(tv.tv_sec);
514 }
515 if (l >= sizeof(pid)) {
516 memcpy(x,&pid,sizeof(pid));
517 l -= sizeof(pid);
518 x += sizeof(pid);
519 }
520 /* Finally xor it with rand() output, that was already seeded with
521 * time() at startup, and convert to hex digits. */
522 for (j = 0; j < len; j++) {
523 p[j] ^= rand();
524 p[j] = charset[p[j] & 0x0F];
525 }
526 }
527 }
528
529 /* Given the filename, return the absolute path as an SDS string, or NULL
530 * if it fails for some reason. Note that "filename" may be an absolute path
531 * already, this will be detected and handled correctly.
532 *
533 * The function does not try to normalize everything, but only the obvious
534 * case of one or more "../" appearning at the start of "filename"
535 * relative path. */
getAbsolutePath(char * filename)536 sds getAbsolutePath(char *filename) {
537 char cwd[1024];
538 sds abspath;
539 sds relpath = sdsnew(filename);
540
541 relpath = sdstrim(relpath," \r\n\t");
542 if (relpath[0] == '/') return relpath; /* Path is already absolute. */
543
544 /* If path is relative, join cwd and relative path. */
545 if (getcwd(cwd,sizeof(cwd)) == NULL) {
546 sdsfree(relpath);
547 return NULL;
548 }
549 abspath = sdsnew(cwd);
550 if (sdslen(abspath) && abspath[sdslen(abspath)-1] != '/')
551 abspath = sdscat(abspath,"/");
552
553 /* At this point we have the current path always ending with "/", and
554 * the trimmed relative path. Try to normalize the obvious case of
555 * trailing ../ elements at the start of the path.
556 *
557 * For every "../" we find in the filename, we remove it and also remove
558 * the last element of the cwd, unless the current cwd is "/". */
559 while (sdslen(relpath) >= 3 &&
560 relpath[0] == '.' && relpath[1] == '.' && relpath[2] == '/')
561 {
562 sdsrange(relpath,3,-1);
563 if (sdslen(abspath) > 1) {
564 char *p = abspath + sdslen(abspath)-2;
565 int trimlen = 1;
566
567 while(*p != '/') {
568 p--;
569 trimlen++;
570 }
571 sdsrange(abspath,0,-(trimlen+1));
572 }
573 }
574
575 /* Finally glue the two parts together. */
576 abspath = sdscatsds(abspath,relpath);
577 sdsfree(relpath);
578 return abspath;
579 }
580
581 /* Return true if the specified path is just a file basename without any
582 * relative or absolute path. This function just checks that no / or \
583 * character exists inside the specified path, that's enough in the
584 * environments where Redis runs. */
pathIsBaseName(char * path)585 int pathIsBaseName(char *path) {
586 return strchr(path,'/') == NULL && strchr(path,'\\') == NULL;
587 }
588
589 #ifdef REDIS_TEST
590 #include <assert.h>
591
test_string2ll(void)592 static void test_string2ll(void) {
593 char buf[32];
594 long long v;
595
596 /* May not start with +. */
597 strcpy(buf,"+1");
598 assert(string2ll(buf,strlen(buf),&v) == 0);
599
600 /* Leading space. */
601 strcpy(buf," 1");
602 assert(string2ll(buf,strlen(buf),&v) == 0);
603
604 /* Trailing space. */
605 strcpy(buf,"1 ");
606 assert(string2ll(buf,strlen(buf),&v) == 0);
607
608 /* May not start with 0. */
609 strcpy(buf,"01");
610 assert(string2ll(buf,strlen(buf),&v) == 0);
611
612 strcpy(buf,"-1");
613 assert(string2ll(buf,strlen(buf),&v) == 1);
614 assert(v == -1);
615
616 strcpy(buf,"0");
617 assert(string2ll(buf,strlen(buf),&v) == 1);
618 assert(v == 0);
619
620 strcpy(buf,"1");
621 assert(string2ll(buf,strlen(buf),&v) == 1);
622 assert(v == 1);
623
624 strcpy(buf,"99");
625 assert(string2ll(buf,strlen(buf),&v) == 1);
626 assert(v == 99);
627
628 strcpy(buf,"-99");
629 assert(string2ll(buf,strlen(buf),&v) == 1);
630 assert(v == -99);
631
632 strcpy(buf,"-9223372036854775808");
633 assert(string2ll(buf,strlen(buf),&v) == 1);
634 assert(v == LLONG_MIN);
635
636 strcpy(buf,"-9223372036854775809"); /* overflow */
637 assert(string2ll(buf,strlen(buf),&v) == 0);
638
639 strcpy(buf,"9223372036854775807");
640 assert(string2ll(buf,strlen(buf),&v) == 1);
641 assert(v == LLONG_MAX);
642
643 strcpy(buf,"9223372036854775808"); /* overflow */
644 assert(string2ll(buf,strlen(buf),&v) == 0);
645 }
646
test_string2l(void)647 static void test_string2l(void) {
648 char buf[32];
649 long v;
650
651 /* May not start with +. */
652 strcpy(buf,"+1");
653 assert(string2l(buf,strlen(buf),&v) == 0);
654
655 /* May not start with 0. */
656 strcpy(buf,"01");
657 assert(string2l(buf,strlen(buf),&v) == 0);
658
659 strcpy(buf,"-1");
660 assert(string2l(buf,strlen(buf),&v) == 1);
661 assert(v == -1);
662
663 strcpy(buf,"0");
664 assert(string2l(buf,strlen(buf),&v) == 1);
665 assert(v == 0);
666
667 strcpy(buf,"1");
668 assert(string2l(buf,strlen(buf),&v) == 1);
669 assert(v == 1);
670
671 strcpy(buf,"99");
672 assert(string2l(buf,strlen(buf),&v) == 1);
673 assert(v == 99);
674
675 strcpy(buf,"-99");
676 assert(string2l(buf,strlen(buf),&v) == 1);
677 assert(v == -99);
678
679 #if LONG_MAX != LLONG_MAX
680 strcpy(buf,"-2147483648");
681 assert(string2l(buf,strlen(buf),&v) == 1);
682 assert(v == LONG_MIN);
683
684 strcpy(buf,"-2147483649"); /* overflow */
685 assert(string2l(buf,strlen(buf),&v) == 0);
686
687 strcpy(buf,"2147483647");
688 assert(string2l(buf,strlen(buf),&v) == 1);
689 assert(v == LONG_MAX);
690
691 strcpy(buf,"2147483648"); /* overflow */
692 assert(string2l(buf,strlen(buf),&v) == 0);
693 #endif
694 }
695
test_ll2string(void)696 static void test_ll2string(void) {
697 char buf[32];
698 long long v;
699 int sz;
700
701 v = 0;
702 sz = ll2string(buf, sizeof buf, v);
703 assert(sz == 1);
704 assert(!strcmp(buf, "0"));
705
706 v = -1;
707 sz = ll2string(buf, sizeof buf, v);
708 assert(sz == 2);
709 assert(!strcmp(buf, "-1"));
710
711 v = 99;
712 sz = ll2string(buf, sizeof buf, v);
713 assert(sz == 2);
714 assert(!strcmp(buf, "99"));
715
716 v = -99;
717 sz = ll2string(buf, sizeof buf, v);
718 assert(sz == 3);
719 assert(!strcmp(buf, "-99"));
720
721 v = -2147483648;
722 sz = ll2string(buf, sizeof buf, v);
723 assert(sz == 11);
724 assert(!strcmp(buf, "-2147483648"));
725
726 v = LLONG_MIN;
727 sz = ll2string(buf, sizeof buf, v);
728 assert(sz == 20);
729 assert(!strcmp(buf, "-9223372036854775808"));
730
731 v = LLONG_MAX;
732 sz = ll2string(buf, sizeof buf, v);
733 assert(sz == 19);
734 assert(!strcmp(buf, "9223372036854775807"));
735 }
736
737 #define UNUSED(x) (void)(x)
utilTest(int argc,char ** argv)738 int utilTest(int argc, char **argv) {
739 UNUSED(argc);
740 UNUSED(argv);
741
742 test_string2ll();
743 test_string2l();
744 test_ll2string();
745 return 0;
746 }
747 #endif
748