xref: /redis-3.2.3/src/util.c (revision 0e5e8ca9)
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