No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / editline / snprintf.c
blob09336addf52a1dd1074e396a234a322e69259ad3
1 /*
2 * Copyright (c) 1995-2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 __RCSID("$Heimdal: snprintf.c 21005 2007-06-08 01:54:35Z lha $"
37 "$NetBSD$");
38 #endif
39 #if defined(TEST_SNPRINTF)
40 #include "snprintf-test.h"
41 #endif /* TEST_SNPRINTF */
42 #include <stdio.h>
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <ctype.h>
47 #include "roken.h"
48 #include <assert.h>
50 enum format_flags {
51 minus_flag = 1,
52 plus_flag = 2,
53 space_flag = 4,
54 alternate_flag = 8,
55 zero_flag = 16
59 * Common state
62 struct snprintf_state {
63 unsigned char *str;
64 unsigned char *s;
65 unsigned char *theend;
66 size_t sz;
67 size_t max_sz;
68 void (*append_char)(struct snprintf_state *, unsigned char);
69 /* XXX - methods */
72 #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
73 static int
74 sn_reserve (struct snprintf_state *state, size_t n)
76 return state->s + n > state->theend;
79 static void
80 sn_append_char (struct snprintf_state *state, unsigned char c)
82 if (!sn_reserve (state, 1))
83 *state->s++ = c;
85 #endif
87 static int
88 as_reserve (struct snprintf_state *state, size_t n)
90 if (state->s + n > state->theend) {
91 int off = state->s - state->str;
92 unsigned char *tmp;
94 if (state->max_sz && state->sz >= state->max_sz)
95 return 1;
97 state->sz = max(state->sz * 2, state->sz + n);
98 if (state->max_sz)
99 state->sz = min(state->sz, state->max_sz);
100 tmp = realloc (state->str, state->sz);
101 if (tmp == NULL)
102 return 1;
103 state->str = tmp;
104 state->s = state->str + off;
105 state->theend = state->str + state->sz - 1;
107 return 0;
110 static void
111 as_append_char (struct snprintf_state *state, unsigned char c)
113 if(!as_reserve (state, 1))
114 *state->s++ = c;
117 /* longest integer types */
119 #ifdef HAVE_LONG_LONG
120 typedef unsigned long long u_longest;
121 typedef long long longest;
122 #else
123 typedef unsigned long u_longest;
124 typedef long longest;
125 #endif
129 static int
130 pad(struct snprintf_state *state, int width, char c)
132 int len = 0;
133 while(width-- > 0){
134 (*state->append_char)(state, c);
135 ++len;
137 return len;
140 /* return true if we should use alternatve hex form */
141 static int
142 use_alternative (int flags, u_longest num, unsigned base)
144 return (flags & alternate_flag) && base == 16 && num != 0;
147 static int
148 append_number(struct snprintf_state *state,
149 u_longest num, unsigned base, const char *rep,
150 int width, int prec, int flags, int minusp)
152 int len = 0;
153 u_longest n = num;
154 char nstr[64]; /* enough for <192 bit octal integers */
155 int nstart, nlen;
156 char signchar;
158 /* given precision, ignore zero flag */
159 if(prec != -1)
160 flags &= ~zero_flag;
161 else
162 prec = 1;
164 /* format number as string */
165 nstart = sizeof(nstr);
166 nlen = 0;
167 nstr[--nstart] = '\0';
168 do {
169 assert(nstart > 0);
170 nstr[--nstart] = rep[n % base];
171 ++nlen;
172 n /= base;
173 } while(n);
175 /* zero value with zero precision should produce no digits */
176 if(prec == 0 && num == 0) {
177 nlen--;
178 nstart++;
181 /* figure out what char to use for sign */
182 if(minusp)
183 signchar = '-';
184 else if((flags & plus_flag))
185 signchar = '+';
186 else if((flags & space_flag))
187 signchar = ' ';
188 else
189 signchar = '\0';
191 if((flags & alternate_flag) && base == 8) {
192 /* if necessary, increase the precision to
193 make first digit a zero */
195 /* XXX C99 claims (regarding # and %o) that "if the value and
196 precision are both 0, a single 0 is printed", but there is
197 no such wording for %x. This would mean that %#.o would
198 output "0", but %#.x "". This does not make sense, and is
199 also not what other printf implementations are doing. */
201 if(prec <= nlen && nstr[nstart] != '0' && nstr[nstart] != '\0')
202 prec = nlen + 1;
205 /* possible formats:
206 pad | sign | alt | zero | digits
207 sign | alt | zero | digits | pad minus_flag
208 sign | alt | zero | digits zero_flag */
210 /* if not right justifying or padding with zeros, we need to
211 compute the length of the rest of the string, and then pad with
212 spaces */
213 if(!(flags & (minus_flag | zero_flag))) {
214 if(prec > nlen)
215 width -= prec;
216 else
217 width -= nlen;
219 if(use_alternative(flags, num, base))
220 width -= 2;
222 if(signchar != '\0')
223 width--;
225 /* pad to width */
226 len += pad(state, width, ' ');
228 if(signchar != '\0') {
229 (*state->append_char)(state, signchar);
230 ++len;
232 if(use_alternative(flags, num, base)) {
233 (*state->append_char)(state, '0');
234 (*state->append_char)(state, rep[10] + 23); /* XXX */
235 len += 2;
237 if(flags & zero_flag) {
238 /* pad to width with zeros */
239 if(prec - nlen > width - len - nlen)
240 len += pad(state, prec - nlen, '0');
241 else
242 len += pad(state, width - len - nlen, '0');
243 } else
244 /* pad to prec with zeros */
245 len += pad(state, prec - nlen, '0');
247 while(nstr[nstart] != '\0') {
248 (*state->append_char)(state, nstr[nstart++]);
249 ++len;
252 if(flags & minus_flag)
253 len += pad(state, width - len, ' ');
255 return len;
259 * return length
262 static int
263 append_string (struct snprintf_state *state,
264 const unsigned char *arg,
265 int width,
266 int prec,
267 int flags)
269 int len = 0;
271 if(arg == NULL)
272 arg = (const unsigned char*)"(null)";
274 if(prec != -1)
275 width -= prec;
276 else
277 width -= strlen((const char *)arg);
278 if(!(flags & minus_flag))
279 len += pad(state, width, ' ');
281 if (prec != -1) {
282 while (*arg && prec--) {
283 (*state->append_char) (state, *arg++);
284 ++len;
286 } else {
287 while (*arg) {
288 (*state->append_char) (state, *arg++);
289 ++len;
292 if(flags & minus_flag)
293 len += pad(state, width, ' ');
294 return len;
297 static int
298 append_char(struct snprintf_state *state,
299 unsigned char arg,
300 int width,
301 int flags)
303 int len = 0;
305 while(!(flags & minus_flag) && --width > 0) {
306 (*state->append_char) (state, ' ') ;
307 ++len;
309 (*state->append_char) (state, arg);
310 ++len;
311 while((flags & minus_flag) && --width > 0) {
312 (*state->append_char) (state, ' ');
313 ++len;
315 return 0;
319 * This can't be made into a function...
322 #ifdef HAVE_LONG_LONG
324 #define PARSE_INT_FORMAT(res, arg, unsig) \
325 if (long_long_flag) \
326 res = (unsig long long)va_arg(arg, unsig long long); \
327 else if (long_flag) \
328 res = (unsig long)va_arg(arg, unsig long); \
329 else if (size_t_flag) \
330 res = (unsig long)va_arg(arg, size_t); \
331 else if (short_flag) \
332 res = (unsig short)va_arg(arg, unsig int); \
333 else \
334 res = (unsig int)va_arg(arg, unsig int)
336 #else
338 #define PARSE_INT_FORMAT(res, arg, unsig) \
339 if (long_flag) \
340 res = (unsig long)va_arg(arg, unsig long); \
341 else if (size_t_flag) \
342 res = (unsig long)va_arg(arg, size_t); \
343 else if (short_flag) \
344 res = (unsig short)va_arg(arg, unsig int); \
345 else \
346 res = (unsig int)va_arg(arg, unsig int)
348 #endif
351 * zyxprintf - return length, as snprintf
354 static int
355 xyzprintf (struct snprintf_state *state, const char *char_format, va_list ap)
357 const unsigned char *format = (const unsigned char *)char_format;
358 unsigned char c;
359 int len = 0;
361 while((c = *format++)) {
362 if (c == '%') {
363 int flags = 0;
364 int width = 0;
365 int prec = -1;
366 int size_t_flag = 0;
367 int long_long_flag = 0;
368 int long_flag = 0;
369 int short_flag = 0;
371 /* flags */
372 while((c = *format++)){
373 if(c == '-')
374 flags |= minus_flag;
375 else if(c == '+')
376 flags |= plus_flag;
377 else if(c == ' ')
378 flags |= space_flag;
379 else if(c == '#')
380 flags |= alternate_flag;
381 else if(c == '0')
382 flags |= zero_flag;
383 else if(c == '\'')
384 ; /* just ignore */
385 else
386 break;
389 if((flags & space_flag) && (flags & plus_flag))
390 flags ^= space_flag;
392 if((flags & minus_flag) && (flags & zero_flag))
393 flags ^= zero_flag;
395 /* width */
396 if (isdigit(c))
397 do {
398 width = width * 10 + c - '0';
399 c = *format++;
400 } while(isdigit(c));
401 else if(c == '*') {
402 width = va_arg(ap, int);
403 c = *format++;
406 /* precision */
407 if (c == '.') {
408 prec = 0;
409 c = *format++;
410 if (isdigit(c))
411 do {
412 prec = prec * 10 + c - '0';
413 c = *format++;
414 } while(isdigit(c));
415 else if (c == '*') {
416 prec = va_arg(ap, int);
417 c = *format++;
421 /* size */
423 if (c == 'h') {
424 short_flag = 1;
425 c = *format++;
426 } else if (c == 'z') {
427 size_t_flag = 1;
428 c = *format++;
429 } else if (c == 'l') {
430 long_flag = 1;
431 c = *format++;
432 if (c == 'l') {
433 long_long_flag = 1;
434 c = *format++;
438 if(c != 'd' && c != 'i')
439 flags &= ~(plus_flag | space_flag);
441 switch (c) {
442 case 'c' :
443 append_char(state, va_arg(ap, int), width, flags);
444 ++len;
445 break;
446 case 's' :
447 len += append_string(state,
448 va_arg(ap, unsigned char*),
449 width,
450 prec,
451 flags);
452 break;
453 case 'd' :
454 case 'i' : {
455 longest arg;
456 u_longest num;
457 int minusp = 0;
459 PARSE_INT_FORMAT(arg, ap, signed);
461 if (arg < 0) {
462 minusp = 1;
463 num = -arg;
464 } else
465 num = arg;
467 len += append_number (state, num, 10, "0123456789",
468 width, prec, flags, minusp);
469 break;
471 case 'u' : {
472 u_longest arg;
474 PARSE_INT_FORMAT(arg, ap, unsigned);
476 len += append_number (state, arg, 10, "0123456789",
477 width, prec, flags, 0);
478 break;
480 case 'o' : {
481 u_longest arg;
483 PARSE_INT_FORMAT(arg, ap, unsigned);
485 len += append_number (state, arg, 010, "01234567",
486 width, prec, flags, 0);
487 break;
489 case 'x' : {
490 u_longest arg;
492 PARSE_INT_FORMAT(arg, ap, unsigned);
494 len += append_number (state, arg, 0x10, "0123456789abcdef",
495 width, prec, flags, 0);
496 break;
498 case 'X' :{
499 u_longest arg;
501 PARSE_INT_FORMAT(arg, ap, unsigned);
503 len += append_number (state, arg, 0x10, "0123456789ABCDEF",
504 width, prec, flags, 0);
505 break;
507 case 'p' : {
508 unsigned long arg = (unsigned long)va_arg(ap, void*);
510 len += append_number (state, arg, 0x10, "0123456789ABCDEF",
511 width, prec, flags, 0);
512 break;
514 case 'n' : {
515 int *arg = va_arg(ap, int*);
516 *arg = state->s - state->str;
517 break;
519 case '\0' :
520 --format;
521 /* FALLTHROUGH */
522 case '%' :
523 (*state->append_char)(state, c);
524 ++len;
525 break;
526 default :
527 (*state->append_char)(state, '%');
528 (*state->append_char)(state, c);
529 len += 2;
530 break;
532 } else {
533 (*state->append_char) (state, c);
534 ++len;
537 return len;
540 #if !defined(HAVE_SNPRINTF) || defined(TEST_SNPRINTF)
541 int ROKEN_LIB_FUNCTION
542 snprintf (char *str, size_t sz, const char *format, ...)
544 va_list args;
545 int ret;
547 va_start(args, format);
548 ret = vsnprintf (str, sz, format, args);
549 va_end(args);
551 #ifdef PARANOIA
553 int ret2;
554 char *tmp;
556 tmp = malloc (sz);
557 if (tmp == NULL)
558 abort ();
560 va_start(args, format);
561 ret2 = vsprintf (tmp, format, args);
562 va_end(args);
563 if (ret != ret2 || strcmp(str, tmp))
564 abort ();
565 free (tmp);
567 #endif
569 return ret;
571 #endif
573 #if !defined(HAVE_ASPRINTF) || defined(TEST_SNPRINTF)
574 int ROKEN_LIB_FUNCTION
575 asprintf (char **ret, const char *format, ...)
577 va_list args;
578 int val;
580 va_start(args, format);
581 val = vasprintf (ret, format, args);
582 va_end(args);
584 #ifdef PARANOIA
586 int ret2;
587 char *tmp;
588 tmp = malloc (val + 1);
589 if (tmp == NULL)
590 abort ();
592 va_start(args, format);
593 ret2 = vsprintf (tmp, format, args);
594 va_end(args);
595 if (val != ret2 || strcmp(*ret, tmp))
596 abort ();
597 free (tmp);
599 #endif
601 return val;
603 #endif
605 #if !defined(HAVE_ASNPRINTF) || defined(TEST_SNPRINTF)
606 int ROKEN_LIB_FUNCTION
607 asnprintf (char **ret, size_t max_sz, const char *format, ...)
609 va_list args;
610 int val;
612 va_start(args, format);
613 val = vasnprintf (ret, max_sz, format, args);
615 #ifdef PARANOIA
617 int ret2;
618 char *tmp;
619 tmp = malloc (val + 1);
620 if (tmp == NULL)
621 abort ();
623 ret2 = vsprintf (tmp, format, args);
624 if (val != ret2 || strcmp(*ret, tmp))
625 abort ();
626 free (tmp);
628 #endif
630 va_end(args);
631 return val;
633 #endif
635 #if !defined(HAVE_VASPRINTF) || defined(TEST_SNPRINTF)
636 int ROKEN_LIB_FUNCTION
637 vasprintf (char **ret, const char *format, va_list args)
639 return vasnprintf (ret, 0, format, args);
641 #endif
644 #if !defined(HAVE_VASNPRINTF) || defined(TEST_SNPRINTF)
645 int ROKEN_LIB_FUNCTION
646 vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
648 int st;
649 struct snprintf_state state;
651 state.max_sz = max_sz;
652 state.sz = 1;
653 state.str = malloc(state.sz);
654 if (state.str == NULL) {
655 *ret = NULL;
656 return -1;
658 state.s = state.str;
659 state.theend = state.s + state.sz - 1;
660 state.append_char = as_append_char;
662 st = xyzprintf (&state, format, args);
663 if (st > state.sz) {
664 free (state.str);
665 *ret = NULL;
666 return -1;
667 } else {
668 char *tmp;
670 *state.s = '\0';
671 tmp = realloc (state.str, st+1);
672 if (tmp == NULL) {
673 free (state.str);
674 *ret = NULL;
675 return -1;
677 *ret = tmp;
678 return st;
681 #endif
683 #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
684 int ROKEN_LIB_FUNCTION
685 vsnprintf (char *str, size_t sz, const char *format, va_list args)
687 struct snprintf_state state;
688 int ret;
689 unsigned char *ustr = (unsigned char *)str;
691 state.max_sz = 0;
692 state.sz = sz;
693 state.str = ustr;
694 state.s = ustr;
695 state.theend = ustr + sz - (sz > 0);
696 state.append_char = sn_append_char;
698 ret = xyzprintf (&state, format, args);
699 if (state.s != NULL && sz != 0)
700 *state.s = '\0';
701 return ret;
703 #endif