etc/services - sync with NetBSD-8
[minix.git] / crypto / external / bsd / heimdal / dist / lib / roken / snprintf.c
blob450ebba363f29b649dcb634257536035ace1199f
1 /* $NetBSD: snprintf.c,v 1.1.1.2 2014/04/24 12:45:52 pettai Exp $ */
3 /*
4 * Copyright (c) 1995-2003 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #include <config.h>
37 #include <stdio.h>
38 #include <stdarg.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <krb5/roken.h>
43 #include <assert.h>
45 enum format_flags {
46 minus_flag = 1,
47 plus_flag = 2,
48 space_flag = 4,
49 alternate_flag = 8,
50 zero_flag = 16
54 * Common state
57 struct snprintf_state {
58 unsigned char *str;
59 unsigned char *s;
60 unsigned char *theend;
61 size_t sz;
62 size_t max_sz;
63 void (*append_char)(struct snprintf_state *, unsigned char);
64 /* XXX - methods */
67 #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
68 static int
69 sn_reserve (struct snprintf_state *state, size_t n)
71 return state->s + n > state->theend;
74 static void
75 sn_append_char (struct snprintf_state *state, unsigned char c)
77 if (!sn_reserve (state, 1))
78 *state->s++ = c;
80 #endif
82 static int
83 as_reserve (struct snprintf_state *state, size_t n)
85 if (state->s + n > state->theend) {
86 int off = state->s - state->str;
87 unsigned char *tmp;
89 if (state->max_sz && state->sz >= state->max_sz)
90 return 1;
92 state->sz = max(state->sz * 2, state->sz + n);
93 if (state->max_sz)
94 state->sz = min(state->sz, state->max_sz);
95 tmp = realloc (state->str, state->sz);
96 if (tmp == NULL)
97 return 1;
98 state->str = tmp;
99 state->s = state->str + off;
100 state->theend = state->str + state->sz - 1;
102 return 0;
105 static void
106 as_append_char (struct snprintf_state *state, unsigned char c)
108 if(!as_reserve (state, 1))
109 *state->s++ = c;
112 /* longest integer types */
114 #ifdef HAVE_LONG_LONG
115 typedef unsigned long long u_longest;
116 typedef long long longest;
117 #else
118 typedef unsigned long u_longest;
119 typedef long longest;
120 #endif
124 static size_t
125 pad(struct snprintf_state *state, int width, char c)
127 size_t len = 0;
128 while(width-- > 0){
129 (*state->append_char)(state, c);
130 ++len;
132 return len;
135 /* return true if we should use alternatve hex form */
136 static int
137 use_alternative (int flags, u_longest num, unsigned base)
139 return (flags & alternate_flag) && base == 16 && num != 0;
142 static int
143 append_number(struct snprintf_state *state,
144 u_longest num, unsigned base, const char *rep,
145 int width, int prec, int flags, int minusp)
147 int len = 0;
148 u_longest n = num;
149 char nstr[64]; /* enough for <192 bit octal integers */
150 int nstart, nlen;
151 char signchar;
153 /* given precision, ignore zero flag */
154 if(prec != -1)
155 flags &= ~zero_flag;
156 else
157 prec = 1;
159 /* format number as string */
160 nstart = sizeof(nstr);
161 nlen = 0;
162 nstr[--nstart] = '\0';
163 do {
164 assert(nstart > 0);
165 nstr[--nstart] = rep[n % base];
166 ++nlen;
167 n /= base;
168 } while(n);
170 /* zero value with zero precision should produce no digits */
171 if(prec == 0 && num == 0) {
172 nlen--;
173 nstart++;
176 /* figure out what char to use for sign */
177 if(minusp)
178 signchar = '-';
179 else if((flags & plus_flag))
180 signchar = '+';
181 else if((flags & space_flag))
182 signchar = ' ';
183 else
184 signchar = '\0';
186 if((flags & alternate_flag) && base == 8) {
187 /* if necessary, increase the precision to
188 make first digit a zero */
190 /* XXX C99 claims (regarding # and %o) that "if the value and
191 precision are both 0, a single 0 is printed", but there is
192 no such wording for %x. This would mean that %#.o would
193 output "0", but %#.x "". This does not make sense, and is
194 also not what other printf implementations are doing. */
196 if(prec <= nlen && nstr[nstart] != '0' && nstr[nstart] != '\0')
197 prec = nlen + 1;
200 /* possible formats:
201 pad | sign | alt | zero | digits
202 sign | alt | zero | digits | pad minus_flag
203 sign | alt | zero | digits zero_flag */
205 /* if not right justifying or padding with zeros, we need to
206 compute the length of the rest of the string, and then pad with
207 spaces */
208 if(!(flags & (minus_flag | zero_flag))) {
209 if(prec > nlen)
210 width -= prec;
211 else
212 width -= nlen;
214 if(use_alternative(flags, num, base))
215 width -= 2;
217 if(signchar != '\0')
218 width--;
220 /* pad to width */
221 len += pad(state, width, ' ');
223 if(signchar != '\0') {
224 (*state->append_char)(state, signchar);
225 ++len;
227 if(use_alternative(flags, num, base)) {
228 (*state->append_char)(state, '0');
229 (*state->append_char)(state, rep[10] + 23); /* XXX */
230 len += 2;
232 if(flags & zero_flag) {
233 /* pad to width with zeros */
234 if(prec - nlen > width - len - nlen)
235 len += pad(state, prec - nlen, '0');
236 else
237 len += pad(state, width - len - nlen, '0');
238 } else
239 /* pad to prec with zeros */
240 len += pad(state, prec - nlen, '0');
242 while(nstr[nstart] != '\0') {
243 (*state->append_char)(state, nstr[nstart++]);
244 ++len;
247 if(flags & minus_flag)
248 len += pad(state, width - len, ' ');
250 return len;
254 * return length
257 static size_t
258 append_string (struct snprintf_state *state,
259 const unsigned char *arg,
260 int width,
261 int prec,
262 int flags)
264 size_t len = 0;
266 if(arg == NULL)
267 arg = (const unsigned char*)"(null)";
269 if(prec != -1)
270 width -= prec;
271 else
272 width -= strlen((const char *)arg);
273 if(!(flags & minus_flag))
274 len += pad(state, width, ' ');
276 if (prec != -1) {
277 while (*arg && prec--) {
278 (*state->append_char) (state, *arg++);
279 ++len;
281 } else {
282 while (*arg) {
283 (*state->append_char) (state, *arg++);
284 ++len;
287 if(flags & minus_flag)
288 len += pad(state, width, ' ');
289 return len;
292 static int
293 append_char(struct snprintf_state *state,
294 unsigned char arg,
295 int width,
296 int flags)
298 int len = 0;
300 while(!(flags & minus_flag) && --width > 0) {
301 (*state->append_char) (state, ' ') ;
302 ++len;
304 (*state->append_char) (state, arg);
305 ++len;
306 while((flags & minus_flag) && --width > 0) {
307 (*state->append_char) (state, ' ');
308 ++len;
310 return 0;
314 * This can't be made into a function...
317 #ifdef HAVE_LONG_LONG
319 #define PARSE_INT_FORMAT(res, arg, unsig) \
320 if (long_long_flag) \
321 res = (unsig long long)va_arg(arg, unsig long long); \
322 else if (long_flag) \
323 res = (unsig long)va_arg(arg, unsig long); \
324 else if (size_t_flag) \
325 res = (unsig long)va_arg(arg, size_t); \
326 else if (short_flag) \
327 res = (unsig short)va_arg(arg, unsig int); \
328 else \
329 res = (unsig int)va_arg(arg, unsig int)
331 #else
333 #define PARSE_INT_FORMAT(res, arg, unsig) \
334 if (long_flag) \
335 res = (unsig long)va_arg(arg, unsig long); \
336 else if (size_t_flag) \
337 res = (unsig long)va_arg(arg, size_t); \
338 else if (short_flag) \
339 res = (unsig short)va_arg(arg, unsig int); \
340 else \
341 res = (unsig int)va_arg(arg, unsig int)
343 #endif
346 * zyxprintf - return length, as snprintf
349 static size_t
350 xyzprintf (struct snprintf_state *state, const char *char_format, va_list ap)
352 const unsigned char *format = (const unsigned char *)char_format;
353 unsigned char c;
354 size_t len = 0;
356 while((c = *format++)) {
357 if (c == '%') {
358 int flags = 0;
359 int width = 0;
360 int prec = -1;
361 int size_t_flag = 0;
362 int long_long_flag = 0;
363 int long_flag = 0;
364 int short_flag = 0;
366 /* flags */
367 while((c = *format++)){
368 if(c == '-')
369 flags |= minus_flag;
370 else if(c == '+')
371 flags |= plus_flag;
372 else if(c == ' ')
373 flags |= space_flag;
374 else if(c == '#')
375 flags |= alternate_flag;
376 else if(c == '0')
377 flags |= zero_flag;
378 else if(c == '\'')
379 ; /* just ignore */
380 else
381 break;
384 if((flags & space_flag) && (flags & plus_flag))
385 flags ^= space_flag;
387 if((flags & minus_flag) && (flags & zero_flag))
388 flags ^= zero_flag;
390 /* width */
391 if (isdigit(c))
392 do {
393 width = width * 10 + c - '0';
394 c = *format++;
395 } while(isdigit(c));
396 else if(c == '*') {
397 width = va_arg(ap, int);
398 c = *format++;
401 /* precision */
402 if (c == '.') {
403 prec = 0;
404 c = *format++;
405 if (isdigit(c))
406 do {
407 prec = prec * 10 + c - '0';
408 c = *format++;
409 } while(isdigit(c));
410 else if (c == '*') {
411 prec = va_arg(ap, int);
412 c = *format++;
416 /* size */
418 if (c == 'h') {
419 short_flag = 1;
420 c = *format++;
421 } else if (c == 'z') {
422 size_t_flag = 1;
423 c = *format++;
424 } else if (c == 'l') {
425 long_flag = 1;
426 c = *format++;
427 if (c == 'l') {
428 long_long_flag = 1;
429 c = *format++;
433 if(c != 'd' && c != 'i')
434 flags &= ~(plus_flag | space_flag);
436 switch (c) {
437 case 'c' :
438 append_char(state, va_arg(ap, int), width, flags);
439 ++len;
440 break;
441 case 's' :
442 len += append_string(state,
443 va_arg(ap, unsigned char*),
444 width,
445 prec,
446 flags);
447 break;
448 case 'd' :
449 case 'i' : {
450 longest arg;
451 u_longest num;
452 int minusp = 0;
454 PARSE_INT_FORMAT(arg, ap, signed);
456 if (arg < 0) {
457 minusp = 1;
458 num = -arg;
459 } else
460 num = arg;
462 len += append_number (state, num, 10, "0123456789",
463 width, prec, flags, minusp);
464 break;
466 case 'u' : {
467 u_longest arg;
469 PARSE_INT_FORMAT(arg, ap, unsigned);
471 len += append_number (state, arg, 10, "0123456789",
472 width, prec, flags, 0);
473 break;
475 case 'o' : {
476 u_longest arg;
478 PARSE_INT_FORMAT(arg, ap, unsigned);
480 len += append_number (state, arg, 010, "01234567",
481 width, prec, flags, 0);
482 break;
484 case 'x' : {
485 u_longest arg;
487 PARSE_INT_FORMAT(arg, ap, unsigned);
489 len += append_number (state, arg, 0x10, "0123456789abcdef",
490 width, prec, flags, 0);
491 break;
493 case 'X' :{
494 u_longest arg;
496 PARSE_INT_FORMAT(arg, ap, unsigned);
498 len += append_number (state, arg, 0x10, "0123456789ABCDEF",
499 width, prec, flags, 0);
500 break;
502 case 'p' : {
503 u_longest arg = (u_longest)va_arg(ap, void*);
505 len += append_number (state, arg, 0x10, "0123456789ABCDEF",
506 width, prec, flags, 0);
507 break;
509 case 'n' : {
510 int *arg = va_arg(ap, int*);
511 *arg = state->s - state->str;
512 break;
514 case '\0' :
515 --format;
516 /* FALLTHROUGH */
517 case '%' :
518 (*state->append_char)(state, c);
519 ++len;
520 break;
521 default :
522 (*state->append_char)(state, '%');
523 (*state->append_char)(state, c);
524 len += 2;
525 break;
527 } else {
528 (*state->append_char) (state, c);
529 ++len;
532 return len;
535 #if !defined(HAVE_SNPRINTF) || defined(TEST_SNPRINTF)
536 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
537 rk_snprintf (char *str, size_t sz, const char *format, ...)
539 va_list args;
540 int ret;
542 va_start(args, format);
543 ret = vsnprintf (str, sz, format, args);
544 va_end(args);
546 #ifdef PARANOIA
548 int ret2;
549 char *tmp;
551 tmp = malloc (sz);
552 if (tmp == NULL)
553 abort ();
555 va_start(args, format);
556 ret2 = vsprintf (tmp, format, args);
557 va_end(args);
558 if (ret != ret2 || strcmp(str, tmp))
559 abort ();
560 free (tmp);
562 #endif
564 return ret;
566 #endif
568 #if !defined(HAVE_ASPRINTF) || defined(TEST_SNPRINTF)
569 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
570 rk_asprintf (char **ret, const char *format, ...)
572 va_list args;
573 int val;
575 va_start(args, format);
576 val = vasprintf (ret, format, args);
577 va_end(args);
579 #ifdef PARANOIA
581 int ret2;
582 char *tmp;
583 tmp = malloc (val + 1);
584 if (tmp == NULL)
585 abort ();
587 va_start(args, format);
588 ret2 = vsprintf (tmp, format, args);
589 va_end(args);
590 if (val != ret2 || strcmp(*ret, tmp))
591 abort ();
592 free (tmp);
594 #endif
596 return val;
598 #endif
600 #if !defined(HAVE_ASNPRINTF) || defined(TEST_SNPRINTF)
601 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
602 rk_asnprintf (char **ret, size_t max_sz, const char *format, ...)
604 va_list args;
605 int val;
607 va_start(args, format);
608 val = vasnprintf (ret, max_sz, format, args);
610 #ifdef PARANOIA
612 int ret2;
613 char *tmp;
614 tmp = malloc (val + 1);
615 if (tmp == NULL)
616 abort ();
618 ret2 = vsprintf (tmp, format, args);
619 if (val != ret2 || strcmp(*ret, tmp))
620 abort ();
621 free (tmp);
623 #endif
625 va_end(args);
626 return val;
628 #endif
630 #if !defined(HAVE_VASPRINTF) || defined(TEST_SNPRINTF)
631 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
632 rk_vasprintf (char **ret, const char *format, va_list args)
634 return vasnprintf (ret, 0, format, args);
636 #endif
639 #if !defined(HAVE_VASNPRINTF) || defined(TEST_SNPRINTF)
640 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
641 rk_vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
643 size_t st;
644 struct snprintf_state state;
646 state.max_sz = max_sz;
647 state.sz = 1;
648 state.str = malloc(state.sz);
649 if (state.str == NULL) {
650 *ret = NULL;
651 return -1;
653 state.s = state.str;
654 state.theend = state.s + state.sz - 1;
655 state.append_char = as_append_char;
657 st = xyzprintf (&state, format, args);
658 if (st > state.sz) {
659 free (state.str);
660 *ret = NULL;
661 return -1;
662 } else {
663 char *tmp;
665 *state.s = '\0';
666 tmp = realloc (state.str, st+1);
667 if (tmp == NULL) {
668 free (state.str);
669 *ret = NULL;
670 return -1;
672 *ret = tmp;
673 return st;
676 #endif
678 #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
679 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
680 rk_vsnprintf (char *str, size_t sz, const char *format, va_list args)
682 struct snprintf_state state;
683 int ret;
684 unsigned char *ustr = (unsigned char *)str;
686 state.max_sz = 0;
687 state.sz = sz;
688 state.str = ustr;
689 state.s = ustr;
690 state.theend = ustr + sz - (sz > 0);
691 state.append_char = sn_append_char;
693 ret = xyzprintf (&state, format, args);
694 if (state.s != NULL && sz != 0)
695 *state.s = '\0';
696 return ret;
698 #endif