Use DES_set_key_unchecked().
[heimdal.git] / lib / roken / snprintf.c
blobeb70c33df3c9b683a20af91bee43d19afa4516ab
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("$Id$");
37 #endif
38 #if defined(TEST_SNPRINTF)
39 #include "snprintf-test.h"
40 #endif /* TEST_SNPRINTF */
41 #include <stdio.h>
42 #include <stdarg.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <ctype.h>
46 #include "roken.h"
47 #include <assert.h>
49 enum format_flags {
50 minus_flag = 1,
51 plus_flag = 2,
52 space_flag = 4,
53 alternate_flag = 8,
54 zero_flag = 16
58 * Common state
61 struct snprintf_state {
62 unsigned char *str;
63 unsigned char *s;
64 unsigned char *theend;
65 size_t sz;
66 size_t max_sz;
67 void (*append_char)(struct snprintf_state *, unsigned char);
68 /* XXX - methods */
71 #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
72 static int
73 sn_reserve (struct snprintf_state *state, size_t n)
75 return state->s + n > state->theend;
78 static void
79 sn_append_char (struct snprintf_state *state, unsigned char c)
81 if (!sn_reserve (state, 1))
82 *state->s++ = c;
84 #endif
86 static int
87 as_reserve (struct snprintf_state *state, size_t n)
89 if (state->s + n > state->theend) {
90 int off = state->s - state->str;
91 unsigned char *tmp;
93 if (state->max_sz && state->sz >= state->max_sz)
94 return 1;
96 state->sz = max(state->sz * 2, state->sz + n);
97 if (state->max_sz)
98 state->sz = min(state->sz, state->max_sz);
99 tmp = realloc (state->str, state->sz);
100 if (tmp == NULL)
101 return 1;
102 state->str = tmp;
103 state->s = state->str + off;
104 state->theend = state->str + state->sz - 1;
106 return 0;
109 static void
110 as_append_char (struct snprintf_state *state, unsigned char c)
112 if(!as_reserve (state, 1))
113 *state->s++ = c;
116 /* longest integer types */
118 #ifdef HAVE_LONG_LONG
119 typedef unsigned long long u_longest;
120 typedef long long longest;
121 #else
122 typedef unsigned long u_longest;
123 typedef long longest;
124 #endif
128 static int
129 pad(struct snprintf_state *state, int width, char c)
131 int len = 0;
132 while(width-- > 0){
133 (*state->append_char)(state, c);
134 ++len;
136 return len;
139 /* return true if we should use alternatve hex form */
140 static int
141 use_alternative (int flags, u_longest num, unsigned base)
143 return (flags & alternate_flag) && base == 16 && num != 0;
146 static int
147 append_number(struct snprintf_state *state,
148 u_longest num, unsigned base, const char *rep,
149 int width, int prec, int flags, int minusp)
151 int len = 0;
152 u_longest n = num;
153 char nstr[64]; /* enough for <192 bit octal integers */
154 int nstart, nlen;
155 char signchar;
157 /* given precision, ignore zero flag */
158 if(prec != -1)
159 flags &= ~zero_flag;
160 else
161 prec = 1;
163 /* format number as string */
164 nstart = sizeof(nstr);
165 nlen = 0;
166 nstr[--nstart] = '\0';
167 do {
168 assert(nstart > 0);
169 nstr[--nstart] = rep[n % base];
170 ++nlen;
171 n /= base;
172 } while(n);
174 /* zero value with zero precision should produce no digits */
175 if(prec == 0 && num == 0) {
176 nlen--;
177 nstart++;
180 /* figure out what char to use for sign */
181 if(minusp)
182 signchar = '-';
183 else if((flags & plus_flag))
184 signchar = '+';
185 else if((flags & space_flag))
186 signchar = ' ';
187 else
188 signchar = '\0';
190 if((flags & alternate_flag) && base == 8) {
191 /* if necessary, increase the precision to
192 make first digit a zero */
194 /* XXX C99 claims (regarding # and %o) that "if the value and
195 precision are both 0, a single 0 is printed", but there is
196 no such wording for %x. This would mean that %#.o would
197 output "0", but %#.x "". This does not make sense, and is
198 also not what other printf implementations are doing. */
200 if(prec <= nlen && nstr[nstart] != '0' && nstr[nstart] != '\0')
201 prec = nlen + 1;
204 /* possible formats:
205 pad | sign | alt | zero | digits
206 sign | alt | zero | digits | pad minus_flag
207 sign | alt | zero | digits zero_flag */
209 /* if not right justifying or padding with zeros, we need to
210 compute the length of the rest of the string, and then pad with
211 spaces */
212 if(!(flags & (minus_flag | zero_flag))) {
213 if(prec > nlen)
214 width -= prec;
215 else
216 width -= nlen;
218 if(use_alternative(flags, num, base))
219 width -= 2;
221 if(signchar != '\0')
222 width--;
224 /* pad to width */
225 len += pad(state, width, ' ');
227 if(signchar != '\0') {
228 (*state->append_char)(state, signchar);
229 ++len;
231 if(use_alternative(flags, num, base)) {
232 (*state->append_char)(state, '0');
233 (*state->append_char)(state, rep[10] + 23); /* XXX */
234 len += 2;
236 if(flags & zero_flag) {
237 /* pad to width with zeros */
238 if(prec - nlen > width - len - nlen)
239 len += pad(state, prec - nlen, '0');
240 else
241 len += pad(state, width - len - nlen, '0');
242 } else
243 /* pad to prec with zeros */
244 len += pad(state, prec - nlen, '0');
246 while(nstr[nstart] != '\0') {
247 (*state->append_char)(state, nstr[nstart++]);
248 ++len;
251 if(flags & minus_flag)
252 len += pad(state, width - len, ' ');
254 return len;
258 * return length
261 static int
262 append_string (struct snprintf_state *state,
263 const unsigned char *arg,
264 int width,
265 int prec,
266 int flags)
268 int len = 0;
270 if(arg == NULL)
271 arg = (const unsigned char*)"(null)";
273 if(prec != -1)
274 width -= prec;
275 else
276 width -= strlen((const char *)arg);
277 if(!(flags & minus_flag))
278 len += pad(state, width, ' ');
280 if (prec != -1) {
281 while (*arg && prec--) {
282 (*state->append_char) (state, *arg++);
283 ++len;
285 } else {
286 while (*arg) {
287 (*state->append_char) (state, *arg++);
288 ++len;
291 if(flags & minus_flag)
292 len += pad(state, width, ' ');
293 return len;
296 static int
297 append_char(struct snprintf_state *state,
298 unsigned char arg,
299 int width,
300 int flags)
302 int len = 0;
304 while(!(flags & minus_flag) && --width > 0) {
305 (*state->append_char) (state, ' ') ;
306 ++len;
308 (*state->append_char) (state, arg);
309 ++len;
310 while((flags & minus_flag) && --width > 0) {
311 (*state->append_char) (state, ' ');
312 ++len;
314 return 0;
318 * This can't be made into a function...
321 #ifdef HAVE_LONG_LONG
323 #define PARSE_INT_FORMAT(res, arg, unsig) \
324 if (long_long_flag) \
325 res = (unsig long long)va_arg(arg, unsig long long); \
326 else if (long_flag) \
327 res = (unsig long)va_arg(arg, unsig long); \
328 else if (size_t_flag) \
329 res = (unsig long)va_arg(arg, size_t); \
330 else if (short_flag) \
331 res = (unsig short)va_arg(arg, unsig int); \
332 else \
333 res = (unsig int)va_arg(arg, unsig int)
335 #else
337 #define PARSE_INT_FORMAT(res, arg, unsig) \
338 if (long_flag) \
339 res = (unsig long)va_arg(arg, unsig long); \
340 else if (size_t_flag) \
341 res = (unsig long)va_arg(arg, size_t); \
342 else if (short_flag) \
343 res = (unsig short)va_arg(arg, unsig int); \
344 else \
345 res = (unsig int)va_arg(arg, unsig int)
347 #endif
350 * zyxprintf - return length, as snprintf
353 static int
354 xyzprintf (struct snprintf_state *state, const char *char_format, va_list ap)
356 const unsigned char *format = (const unsigned char *)char_format;
357 unsigned char c;
358 int len = 0;
360 while((c = *format++)) {
361 if (c == '%') {
362 int flags = 0;
363 int width = 0;
364 int prec = -1;
365 int size_t_flag = 0;
366 int long_long_flag = 0;
367 int long_flag = 0;
368 int short_flag = 0;
370 /* flags */
371 while((c = *format++)){
372 if(c == '-')
373 flags |= minus_flag;
374 else if(c == '+')
375 flags |= plus_flag;
376 else if(c == ' ')
377 flags |= space_flag;
378 else if(c == '#')
379 flags |= alternate_flag;
380 else if(c == '0')
381 flags |= zero_flag;
382 else if(c == '\'')
383 ; /* just ignore */
384 else
385 break;
388 if((flags & space_flag) && (flags & plus_flag))
389 flags ^= space_flag;
391 if((flags & minus_flag) && (flags & zero_flag))
392 flags ^= zero_flag;
394 /* width */
395 if (isdigit(c))
396 do {
397 width = width * 10 + c - '0';
398 c = *format++;
399 } while(isdigit(c));
400 else if(c == '*') {
401 width = va_arg(ap, int);
402 c = *format++;
405 /* precision */
406 if (c == '.') {
407 prec = 0;
408 c = *format++;
409 if (isdigit(c))
410 do {
411 prec = prec * 10 + c - '0';
412 c = *format++;
413 } while(isdigit(c));
414 else if (c == '*') {
415 prec = va_arg(ap, int);
416 c = *format++;
420 /* size */
422 if (c == 'h') {
423 short_flag = 1;
424 c = *format++;
425 } else if (c == 'z') {
426 size_t_flag = 1;
427 c = *format++;
428 } else if (c == 'l') {
429 long_flag = 1;
430 c = *format++;
431 if (c == 'l') {
432 long_long_flag = 1;
433 c = *format++;
437 if(c != 'd' && c != 'i')
438 flags &= ~(plus_flag | space_flag);
440 switch (c) {
441 case 'c' :
442 append_char(state, va_arg(ap, int), width, flags);
443 ++len;
444 break;
445 case 's' :
446 len += append_string(state,
447 va_arg(ap, unsigned char*),
448 width,
449 prec,
450 flags);
451 break;
452 case 'd' :
453 case 'i' : {
454 longest arg;
455 u_longest num;
456 int minusp = 0;
458 PARSE_INT_FORMAT(arg, ap, signed);
460 if (arg < 0) {
461 minusp = 1;
462 num = -arg;
463 } else
464 num = arg;
466 len += append_number (state, num, 10, "0123456789",
467 width, prec, flags, minusp);
468 break;
470 case 'u' : {
471 u_longest arg;
473 PARSE_INT_FORMAT(arg, ap, unsigned);
475 len += append_number (state, arg, 10, "0123456789",
476 width, prec, flags, 0);
477 break;
479 case 'o' : {
480 u_longest arg;
482 PARSE_INT_FORMAT(arg, ap, unsigned);
484 len += append_number (state, arg, 010, "01234567",
485 width, prec, flags, 0);
486 break;
488 case 'x' : {
489 u_longest arg;
491 PARSE_INT_FORMAT(arg, ap, unsigned);
493 len += append_number (state, arg, 0x10, "0123456789abcdef",
494 width, prec, flags, 0);
495 break;
497 case 'X' :{
498 u_longest arg;
500 PARSE_INT_FORMAT(arg, ap, unsigned);
502 len += append_number (state, arg, 0x10, "0123456789ABCDEF",
503 width, prec, flags, 0);
504 break;
506 case 'p' : {
507 unsigned long arg = (unsigned long)va_arg(ap, void*);
509 len += append_number (state, arg, 0x10, "0123456789ABCDEF",
510 width, prec, flags, 0);
511 break;
513 case 'n' : {
514 int *arg = va_arg(ap, int*);
515 *arg = state->s - state->str;
516 break;
518 case '\0' :
519 --format;
520 /* FALLTHROUGH */
521 case '%' :
522 (*state->append_char)(state, c);
523 ++len;
524 break;
525 default :
526 (*state->append_char)(state, '%');
527 (*state->append_char)(state, c);
528 len += 2;
529 break;
531 } else {
532 (*state->append_char) (state, c);
533 ++len;
536 return len;
539 #if !defined(HAVE_SNPRINTF) || defined(TEST_SNPRINTF)
540 int ROKEN_LIB_FUNCTION
541 snprintf (char *str, size_t sz, const char *format, ...)
543 va_list args;
544 int ret;
546 va_start(args, format);
547 ret = vsnprintf (str, sz, format, args);
548 va_end(args);
550 #ifdef PARANOIA
552 int ret2;
553 char *tmp;
555 tmp = malloc (sz);
556 if (tmp == NULL)
557 abort ();
559 va_start(args, format);
560 ret2 = vsprintf (tmp, format, args);
561 va_end(args);
562 if (ret != ret2 || strcmp(str, tmp))
563 abort ();
564 free (tmp);
566 #endif
568 return ret;
570 #endif
572 #if !defined(HAVE_ASPRINTF) || defined(TEST_SNPRINTF)
573 int ROKEN_LIB_FUNCTION
574 asprintf (char **ret, const char *format, ...)
576 va_list args;
577 int val;
579 va_start(args, format);
580 val = vasprintf (ret, format, args);
581 va_end(args);
583 #ifdef PARANOIA
585 int ret2;
586 char *tmp;
587 tmp = malloc (val + 1);
588 if (tmp == NULL)
589 abort ();
591 va_start(args, format);
592 ret2 = vsprintf (tmp, format, args);
593 va_end(args);
594 if (val != ret2 || strcmp(*ret, tmp))
595 abort ();
596 free (tmp);
598 #endif
600 return val;
602 #endif
604 #if !defined(HAVE_ASNPRINTF) || defined(TEST_SNPRINTF)
605 int ROKEN_LIB_FUNCTION
606 asnprintf (char **ret, size_t max_sz, const char *format, ...)
608 va_list args;
609 int val;
611 va_start(args, format);
612 val = vasnprintf (ret, max_sz, format, args);
614 #ifdef PARANOIA
616 int ret2;
617 char *tmp;
618 tmp = malloc (val + 1);
619 if (tmp == NULL)
620 abort ();
622 ret2 = vsprintf (tmp, format, args);
623 if (val != ret2 || strcmp(*ret, tmp))
624 abort ();
625 free (tmp);
627 #endif
629 va_end(args);
630 return val;
632 #endif
634 #if !defined(HAVE_VASPRINTF) || defined(TEST_SNPRINTF)
635 int ROKEN_LIB_FUNCTION
636 vasprintf (char **ret, const char *format, va_list args)
638 return vasnprintf (ret, 0, format, args);
640 #endif
643 #if !defined(HAVE_VASNPRINTF) || defined(TEST_SNPRINTF)
644 int ROKEN_LIB_FUNCTION
645 vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
647 int st;
648 struct snprintf_state state;
650 state.max_sz = max_sz;
651 state.sz = 1;
652 state.str = malloc(state.sz);
653 if (state.str == NULL) {
654 *ret = NULL;
655 return -1;
657 state.s = state.str;
658 state.theend = state.s + state.sz - 1;
659 state.append_char = as_append_char;
661 st = xyzprintf (&state, format, args);
662 if (st > state.sz) {
663 free (state.str);
664 *ret = NULL;
665 return -1;
666 } else {
667 char *tmp;
669 *state.s = '\0';
670 tmp = realloc (state.str, st+1);
671 if (tmp == NULL) {
672 free (state.str);
673 *ret = NULL;
674 return -1;
676 *ret = tmp;
677 return st;
680 #endif
682 #if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF)
683 int ROKEN_LIB_FUNCTION
684 vsnprintf (char *str, size_t sz, const char *format, va_list args)
686 struct snprintf_state state;
687 int ret;
688 unsigned char *ustr = (unsigned char *)str;
690 state.max_sz = 0;
691 state.sz = sz;
692 state.str = ustr;
693 state.s = ustr;
694 state.theend = ustr + sz - (sz > 0);
695 state.append_char = sn_append_char;
697 ret = xyzprintf (&state, format, args);
698 if (state.s != NULL && sz != 0)
699 *state.s = '\0';
700 return ret;
702 #endif