1 /*
2 ** OSSP uuid - Universally Unique Identifier
3 ** Copyright (c) 2004-2008 Ralf S. Engelschall <rse@engelschall.com>
4 ** Copyright (c) 2004-2008 The OSSP Project <http://www.ossp.org/>
5 **
6 ** This file is part of OSSP uuid, a library for the generation
7 ** of UUIDs which can found at http://www.ossp.org/pkg/lib/uuid/
8 **
9 ** Permission to use, copy, modify, and distribute this software for
10 ** any purpose with or without fee is hereby granted, provided that
11 ** the above copyright notice and this permission notice appear in all
12 ** copies.
13 **
14 ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
15 ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
18 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
21 ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
24 ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 ** SUCH DAMAGE.
26 **
27 ** uuid_str.c: string formatting functions
28 */
29
30 /*
31 * Copyright Patrick Powell 1995
32 * This code is based on code written by Patrick Powell <papowell@astart.com>
33 * It may be used for any purpose as long as this notice remains intact
34 * on all source code distributions.
35 */
36
37 /*
38 * This code contains numerious changes and enhancements which were
39 * made by lots of contributors over the last years to Patrick Powell's
40 * original code:
41 *
42 * o Patrick Powell <papowell@astart.com> (1995)
43 * o Brandon Long <blong@fiction.net> (1996, for Mutt)
44 * o Thomas Roessler <roessler@guug.de> (1998, for Mutt)
45 * o Michael Elkins <me@cs.hmc.edu> (1998, for Mutt)
46 * o Andrew Tridgell <tridge@samba.org> (1998, for Samba)
47 * o Luke Mewburn <lukem@netbsd.org> (1999, for LukemFTP)
48 * o Ralf S. Engelschall <rse@engelschall.com> (1999, for OSSP)
49 */
50
51 /* own headers (part 1/2) */
52 #include "uuid_ac.h"
53
54 /* system headers */
55 #include <stdlib.h>
56 #include <stdarg.h>
57 #include <string.h>
58 #include <ctype.h>
59
60 /* own headers (part 2/2) */
61 #include "uuid_str.h"
62
63 #if HAVE_LONG_LONG
64 #define LLONG long long
65 #else
66 #define LLONG long
67 #endif
68
69 #if HAVE_LONG_DOUBLE
70 #define LDOUBLE long double
71 #else
72 #define LDOUBLE double
73 #endif
74
75 static void fmtstr (char *, size_t *, size_t, char *, int, int, int);
76 static void fmtint (char *, size_t *, size_t, LLONG, int, int, int, int);
77 static void fmtfp (char *, size_t *, size_t, LDOUBLE, int, int, int);
78 static void dopr_outch (char *, size_t *, size_t, int);
79
80 /* format read states */
81 #define DP_S_DEFAULT 0
82 #define DP_S_FLAGS 1
83 #define DP_S_MIN 2
84 #define DP_S_DOT 3
85 #define DP_S_MAX 4
86 #define DP_S_MOD 5
87 #define DP_S_CONV 6
88 #define DP_S_DONE 7
89
90 /* format flags - Bits */
91 #define DP_F_MINUS (1 << 0)
92 #define DP_F_PLUS (1 << 1)
93 #define DP_F_SPACE (1 << 2)
94 #define DP_F_NUM (1 << 3)
95 #define DP_F_ZERO (1 << 4)
96 #define DP_F_UP (1 << 5)
97 #define DP_F_UNSIGNED (1 << 6)
98
99 /* conversion flags */
100 #define DP_C_SHORT 1
101 #define DP_C_LONG 2
102 #define DP_C_LDOUBLE 3
103 #define DP_C_LLONG 4
104
105 /* some handy macros */
106 #define char_to_int(p) (p - '0')
107 #define STR_MAX(p,q) ((p >= q) ? p : q)
108 #define NUL '\0'
109
110 static void
dopr(char * buffer,size_t maxlen,size_t * retlen,const char * format,va_list args)111 dopr(
112 char *buffer,
113 size_t maxlen,
114 size_t *retlen,
115 const char *format,
116 va_list args)
117 {
118 char ch;
119 LLONG value;
120 LDOUBLE fvalue;
121 char *strvalue;
122 int min;
123 int max;
124 int state;
125 int flags;
126 int cflags;
127 size_t currlen;
128
129 state = DP_S_DEFAULT;
130 flags = currlen = cflags = min = 0;
131 max = -1;
132 ch = *format++;
133
134 if (buffer == NULL)
135 maxlen = 999999;
136
137 while (state != DP_S_DONE) {
138 if ((ch == NUL) || (currlen >= maxlen))
139 state = DP_S_DONE;
140
141 switch (state) {
142 case DP_S_DEFAULT:
143 if (ch == '%')
144 state = DP_S_FLAGS;
145 else
146 dopr_outch(buffer, &currlen, maxlen, ch);
147 ch = *format++;
148 break;
149 case DP_S_FLAGS:
150 switch (ch) {
151 case '-':
152 flags |= DP_F_MINUS;
153 ch = *format++;
154 break;
155 case '+':
156 flags |= DP_F_PLUS;
157 ch = *format++;
158 break;
159 case ' ':
160 flags |= DP_F_SPACE;
161 ch = *format++;
162 break;
163 case '#':
164 flags |= DP_F_NUM;
165 ch = *format++;
166 break;
167 case '0':
168 flags |= DP_F_ZERO;
169 ch = *format++;
170 break;
171 default:
172 state = DP_S_MIN;
173 break;
174 }
175 break;
176 case DP_S_MIN:
177 if (isdigit((unsigned char)ch)) {
178 min = 10 * min + char_to_int(ch);
179 ch = *format++;
180 } else if (ch == '*') {
181 min = va_arg(args, int);
182 ch = *format++;
183 state = DP_S_DOT;
184 } else
185 state = DP_S_DOT;
186 break;
187 case DP_S_DOT:
188 if (ch == '.') {
189 state = DP_S_MAX;
190 ch = *format++;
191 } else
192 state = DP_S_MOD;
193 break;
194 case DP_S_MAX:
195 if (isdigit((unsigned char)ch)) {
196 if (max < 0)
197 max = 0;
198 max = 10 * max + char_to_int(ch);
199 ch = *format++;
200 } else if (ch == '*') {
201 max = va_arg(args, int);
202 ch = *format++;
203 state = DP_S_MOD;
204 } else
205 state = DP_S_MOD;
206 break;
207 case DP_S_MOD:
208 switch (ch) {
209 case 'h':
210 cflags = DP_C_SHORT;
211 ch = *format++;
212 break;
213 case 'l':
214 if (*format == 'l') {
215 cflags = DP_C_LLONG;
216 format++;
217 } else
218 cflags = DP_C_LONG;
219 ch = *format++;
220 break;
221 case 'q':
222 cflags = DP_C_LLONG;
223 ch = *format++;
224 break;
225 case 'L':
226 cflags = DP_C_LDOUBLE;
227 ch = *format++;
228 break;
229 default:
230 break;
231 }
232 state = DP_S_CONV;
233 break;
234 case DP_S_CONV:
235 switch (ch) {
236 case 'd':
237 case 'i':
238 switch (cflags) {
239 case DP_C_SHORT:
240 value = (short int)va_arg(args, int);
241 break;
242 case DP_C_LONG:
243 value = va_arg(args, long int);
244 break;
245 case DP_C_LLONG:
246 value = va_arg(args, LLONG);
247 break;
248 default:
249 value = va_arg(args, int);
250 break;
251 }
252 fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
253 break;
254 case 'X':
255 flags |= DP_F_UP;
256 /* FALLTHROUGH */
257 case 'x':
258 case 'o':
259 case 'u':
260 flags |= DP_F_UNSIGNED;
261 switch (cflags) {
262 case DP_C_SHORT:
263 value = (unsigned short int)va_arg(args, unsigned int);
264 break;
265 case DP_C_LONG:
266 value = (LLONG)va_arg(args, unsigned long int);
267 break;
268 case DP_C_LLONG:
269 value = va_arg(args, unsigned LLONG);
270 break;
271 default:
272 value = (LLONG)va_arg(args, unsigned int);
273 break;
274 }
275 fmtint(buffer, &currlen, maxlen, value,
276 ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
277 min, max, flags);
278 break;
279 case 'f':
280 if (cflags == DP_C_LDOUBLE)
281 fvalue = va_arg(args, LDOUBLE);
282 else
283 fvalue = va_arg(args, double);
284 fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
285 break;
286 case 'E':
287 flags |= DP_F_UP;
288 /* FALLTHROUGH */
289 case 'e':
290 if (cflags == DP_C_LDOUBLE)
291 fvalue = va_arg(args, LDOUBLE);
292 else
293 fvalue = va_arg(args, double);
294 break;
295 case 'G':
296 flags |= DP_F_UP;
297 /* FALLTHROUGH */
298 case 'g':
299 if (cflags == DP_C_LDOUBLE)
300 fvalue = va_arg(args, LDOUBLE);
301 else
302 fvalue = va_arg(args, double);
303 break;
304 case 'c':
305 dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
306 break;
307 case 's':
308 strvalue = va_arg(args, char *);
309 if (max < 0)
310 max = maxlen;
311 fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
312 break;
313 case 'p':
314 value = (long)va_arg(args, void *);
315 fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);
316 break;
317 case 'n': /* XXX */
318 if (cflags == DP_C_SHORT) {
319 short int *num;
320 num = va_arg(args, short int *);
321 *num = currlen;
322 } else if (cflags == DP_C_LONG) { /* XXX */
323 long int *num;
324 num = va_arg(args, long int *);
325 *num = (long int) currlen;
326 } else if (cflags == DP_C_LLONG) { /* XXX */
327 LLONG *num;
328 num = va_arg(args, LLONG *);
329 *num = (LLONG) currlen;
330 } else {
331 int *num;
332 num = va_arg(args, int *);
333 *num = currlen;
334 }
335 break;
336 case '%':
337 dopr_outch(buffer, &currlen, maxlen, ch);
338 break;
339 case 'w':
340 /* not supported yet, treat as next char */
341 ch = *format++;
342 break;
343 default:
344 /* unknown, skip */
345 break;
346 }
347 ch = *format++;
348 state = DP_S_DEFAULT;
349 flags = cflags = min = 0;
350 max = -1;
351 break;
352 case DP_S_DONE:
353 break;
354 default:
355 break;
356 }
357 }
358 if (currlen >= maxlen - 1)
359 currlen = maxlen - 1;
360 if (buffer != NULL)
361 buffer[currlen] = NUL;
362 *retlen = currlen;
363 return;
364 }
365
366 static void
fmtstr(char * buffer,size_t * currlen,size_t maxlen,char * value,int flags,int min,int max)367 fmtstr(
368 char *buffer,
369 size_t *currlen,
370 size_t maxlen,
371 char *value,
372 int flags,
373 int min,
374 int max)
375 {
376 int padlen, strln;
377 int cnt = 0;
378
379 if (value == NULL)
380 value = "<NULL>";
381 for (strln = 0; value[strln] != '\0'; strln++)
382 ;
383 padlen = min - strln;
384 if (padlen < 0)
385 padlen = 0;
386 if (flags & DP_F_MINUS)
387 padlen = -padlen;
388
389 while ((padlen > 0) && (cnt < max)) {
390 dopr_outch(buffer, currlen, maxlen, ' ');
391 --padlen;
392 ++cnt;
393 }
394 while (*value && (cnt < max)) {
395 dopr_outch(buffer, currlen, maxlen, *value++);
396 ++cnt;
397 }
398 while ((padlen < 0) && (cnt < max)) {
399 dopr_outch(buffer, currlen, maxlen, ' ');
400 ++padlen;
401 ++cnt;
402 }
403 }
404
405 static void
fmtint(char * buffer,size_t * currlen,size_t maxlen,LLONG value,int base,int min,int max,int flags)406 fmtint(
407 char *buffer,
408 size_t *currlen,
409 size_t maxlen,
410 LLONG value,
411 int base,
412 int min,
413 int max,
414 int flags)
415 {
416 int signvalue = 0;
417 unsigned LLONG uvalue;
418 char convert[20];
419 int place = 0;
420 int spadlen = 0;
421 int zpadlen = 0;
422 int caps = 0;
423
424 if (max < 0)
425 max = 0;
426 uvalue = value;
427 if (!(flags & DP_F_UNSIGNED)) {
428 if (value < 0) {
429 signvalue = '-';
430 uvalue = -value;
431 } else if (flags & DP_F_PLUS)
432 signvalue = '+';
433 else if (flags & DP_F_SPACE)
434 signvalue = ' ';
435 }
436 if (flags & DP_F_UP)
437 caps = 1;
438 do {
439 convert[place++] =
440 (caps ? "0123456789ABCDEF" : "0123456789abcdef")
441 [uvalue % (unsigned) base];
442 uvalue = (uvalue / (unsigned) base);
443 } while (uvalue && (place < 20));
444 if (place == 20)
445 place--;
446 convert[place] = 0;
447
448 zpadlen = max - place;
449 spadlen = min - STR_MAX(max, place) - (signvalue ? 1 : 0);
450 if (zpadlen < 0)
451 zpadlen = 0;
452 if (spadlen < 0)
453 spadlen = 0;
454 if (flags & DP_F_ZERO) {
455 zpadlen = STR_MAX(zpadlen, spadlen);
456 spadlen = 0;
457 }
458 if (flags & DP_F_MINUS)
459 spadlen = -spadlen;
460
461 /* spaces */
462 while (spadlen > 0) {
463 dopr_outch(buffer, currlen, maxlen, ' ');
464 --spadlen;
465 }
466
467 /* sign */
468 if (signvalue)
469 dopr_outch(buffer, currlen, maxlen, signvalue);
470
471 /* zeros */
472 if (zpadlen > 0) {
473 while (zpadlen > 0) {
474 dopr_outch(buffer, currlen, maxlen, '0');
475 --zpadlen;
476 }
477 }
478 /* digits */
479 while (place > 0)
480 dopr_outch(buffer, currlen, maxlen, convert[--place]);
481
482 /* left justified spaces */
483 while (spadlen < 0) {
484 dopr_outch(buffer, currlen, maxlen, ' ');
485 ++spadlen;
486 }
487 return;
488 }
489
490 static LDOUBLE
math_abs(LDOUBLE value)491 math_abs(LDOUBLE value)
492 {
493 LDOUBLE result = value;
494 if (value < 0)
495 result = -value;
496 return result;
497 }
498
499 static LDOUBLE
math_pow10(int exponent)500 math_pow10(int exponent)
501 {
502 LDOUBLE result = 1;
503 while (exponent > 0) {
504 result *= 10;
505 exponent--;
506 }
507 return result;
508 }
509
510 static long
math_round(LDOUBLE value)511 math_round(LDOUBLE value)
512 {
513 long intpart;
514 intpart = (long) value;
515 value = value - intpart;
516 if (value >= 0.5)
517 intpart++;
518 return intpart;
519 }
520
521 static void
fmtfp(char * buffer,size_t * currlen,size_t maxlen,LDOUBLE fvalue,int min,int max,int flags)522 fmtfp(
523 char *buffer,
524 size_t *currlen,
525 size_t maxlen,
526 LDOUBLE fvalue,
527 int min,
528 int max,
529 int flags)
530 {
531 int signvalue = 0;
532 LDOUBLE ufvalue;
533 char iconvert[20];
534 char fconvert[20];
535 int iplace = 0;
536 int fplace = 0;
537 int padlen = 0;
538 int zpadlen = 0;
539 int caps = 0;
540 long intpart;
541 long fracpart;
542
543 if (max < 0)
544 max = 6;
545 ufvalue = math_abs(fvalue);
546 if (fvalue < 0)
547 signvalue = '-';
548 else if (flags & DP_F_PLUS)
549 signvalue = '+';
550 else if (flags & DP_F_SPACE)
551 signvalue = ' ';
552
553 intpart = (long)ufvalue;
554
555 /* sorry, we only support 9 digits past the decimal because of our
556 conversion method */
557 if (max > 9)
558 max = 9;
559
560 /* we "cheat" by converting the fractional part to integer by
561 multiplying by a factor of 10 */
562 fracpart = math_round((math_pow10(max)) * (ufvalue - intpart));
563
564 if (fracpart >= math_pow10(max)) {
565 intpart++;
566 fracpart -= (long)math_pow10(max);
567 }
568
569 /* convert integer part */
570 do {
571 iconvert[iplace++] =
572 (caps ? "0123456789ABCDEF"
573 : "0123456789abcdef")[intpart % 10];
574 intpart = (intpart / 10);
575 } while (intpart && (iplace < 20));
576 if (iplace == 20)
577 iplace--;
578 iconvert[iplace] = 0;
579
580 /* convert fractional part */
581 do {
582 fconvert[fplace++] =
583 (caps ? "0123456789ABCDEF"
584 : "0123456789abcdef")[fracpart % 10];
585 fracpart = (fracpart / 10);
586 } while (fracpart && (fplace < 20));
587 if (fplace == 20)
588 fplace--;
589 fconvert[fplace] = 0;
590
591 /* -1 for decimal point, another -1 if we are printing a sign */
592 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
593 zpadlen = max - fplace;
594 if (zpadlen < 0)
595 zpadlen = 0;
596 if (padlen < 0)
597 padlen = 0;
598 if (flags & DP_F_MINUS)
599 padlen = -padlen;
600
601 if ((flags & DP_F_ZERO) && (padlen > 0)) {
602 if (signvalue) {
603 dopr_outch(buffer, currlen, maxlen, signvalue);
604 --padlen;
605 signvalue = 0;
606 }
607 while (padlen > 0) {
608 dopr_outch(buffer, currlen, maxlen, '0');
609 --padlen;
610 }
611 }
612 while (padlen > 0) {
613 dopr_outch(buffer, currlen, maxlen, ' ');
614 --padlen;
615 }
616 if (signvalue)
617 dopr_outch(buffer, currlen, maxlen, signvalue);
618
619 while (iplace > 0)
620 dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
621
622 /*
623 * Decimal point. This should probably use locale to find the correct
624 * char to print out.
625 */
626 if (max > 0) {
627 dopr_outch(buffer, currlen, maxlen, '.');
628
629 while (fplace > 0)
630 dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
631 }
632 while (zpadlen > 0) {
633 dopr_outch(buffer, currlen, maxlen, '0');
634 --zpadlen;
635 }
636
637 while (padlen < 0) {
638 dopr_outch(buffer, currlen, maxlen, ' ');
639 ++padlen;
640 }
641 return;
642 }
643
644 static void
dopr_outch(char * buffer,size_t * currlen,size_t maxlen,int c)645 dopr_outch(
646 char *buffer,
647 size_t *currlen,
648 size_t maxlen,
649 int c)
650 {
651 if (*currlen < maxlen) {
652 if (buffer != NULL)
653 buffer[(*currlen)] = (char)c;
654 (*currlen)++;
655 }
656 return;
657 }
658
659 int
str_vsnprintf(char * str,size_t count,const char * fmt,va_list args)660 str_vsnprintf(
661 char *str,
662 size_t count,
663 const char *fmt,
664 va_list args)
665 {
666 size_t retlen;
667
668 if (str != NULL)
669 str[0] = NUL;
670 dopr(str, count, &retlen, fmt, args);
671 return retlen;
672 }
673
674 int
str_snprintf(char * str,size_t count,const char * fmt,...)675 str_snprintf(
676 char *str,
677 size_t count,
678 const char *fmt,
679 ...)
680 {
681 va_list ap;
682 int rv;
683
684 va_start(ap, fmt);
685 rv = str_vsnprintf(str, count, fmt, ap);
686 va_end(ap);
687 return rv;
688 }
689
690 char *
str_vasprintf(const char * fmt,va_list ap)691 str_vasprintf(
692 const char *fmt,
693 va_list ap)
694 {
695 char *rv;
696 int n;
697 va_list ap_tmp;
698
699 va_copy(ap_tmp, ap);
700 n = str_vsnprintf(NULL, 0, fmt, ap_tmp);
701 if ((rv = (char *)malloc(n+1)) == NULL)
702 return NULL;
703 str_vsnprintf(rv, n+1, fmt, ap);
704 return rv;
705 }
706
707 char *
str_asprintf(const char * fmt,...)708 str_asprintf(
709 const char *fmt,
710 ...)
711 {
712 va_list ap;
713 char *rv;
714
715 va_start(ap, fmt);
716 rv = str_vasprintf(fmt, ap);
717 va_end(ap);
718 return rv;
719 }
720
721 int
str_vrsprintf(char ** str,const char * fmt,va_list ap)722 str_vrsprintf(
723 char **str,
724 const char *fmt,
725 va_list ap)
726 {
727 int rv;
728 size_t n;
729 va_list ap_tmp;
730
731 if (str == NULL)
732 return -1;
733 if (*str == NULL) {
734 *str = str_vasprintf(fmt, ap);
735 rv = strlen(*str);
736 }
737 else {
738 va_copy(ap_tmp, ap);
739 n = strlen(*str);
740 rv = str_vsnprintf(NULL, 0, fmt, ap_tmp);
741 if ((*str = (char *)realloc(*str, n+rv+1)) == NULL)
742 return -1;
743 str_vsnprintf((*str)+n, rv+1, fmt, ap);
744 }
745 return rv;
746 }
747
748 int
str_rsprintf(char ** str,const char * fmt,...)749 str_rsprintf(
750 char **str,
751 const char *fmt,
752 ...)
753 {
754 va_list ap;
755 int rv;
756
757 va_start(ap, fmt);
758 rv = str_vrsprintf(str, fmt, ap);
759 va_end(ap);
760 return rv;
761 }
762
763