test-suite-solaris-fixes-plus-some-kaserver-glue-20020216
[openafs.git] / src / tests / snprintf.c
1 /*
2  * Copyright (c) 1995-2000 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.
12  * 
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.
16  * 
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.
20  * 
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.
32  */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 RCSID("$Id$");
37 #endif
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <ctype.h>
43
44 #ifndef min
45 #define min(a, b)               ((a) > (b) ? (b) : (a))
46 #endif
47 #ifndef max
48 #define max(a, b)               ((a) < (b) ? (b) : (a))
49 #endif
50
51 enum format_flags {
52     minus_flag     =  1,
53     plus_flag      =  2,
54     space_flag     =  4,
55     alternate_flag =  8,
56     zero_flag      = 16
57 };
58
59 /*
60  * Common state
61  */
62
63 struct state {
64   unsigned char *str;
65   unsigned char *s;
66   unsigned char *theend;
67   size_t sz;
68   size_t max_sz;
69   int (*append_char)(struct state *, unsigned char);
70   int (*reserve)(struct state *, size_t);
71   /* XXX - methods */
72 };
73
74 #ifndef HAVE_VSNPRINTF
75 static int
76 sn_reserve (struct state *state, size_t n)
77 {
78   return state->s + n > state->theend;
79 }
80
81 static int
82 sn_append_char (struct state *state, unsigned char c)
83 {
84   if (sn_reserve (state, 1)) {
85     return 1;
86   } else {
87     *state->s++ = c;
88     return 0;
89   }
90 }
91 #endif
92
93 static int
94 as_reserve (struct state *state, size_t n)
95 {
96   if (state->s + n > state->theend) {
97     int off = state->s - state->str;
98     unsigned char *tmp;
99
100     if (state->max_sz && state->sz >= state->max_sz)
101       return 1;
102
103     state->sz = max(state->sz * 2, state->sz + n);
104     if (state->max_sz)
105       state->sz = min(state->sz, state->max_sz);
106     tmp = realloc (state->str, state->sz);
107     if (tmp == NULL)
108       return 1;
109     state->str = tmp;
110     state->s = state->str + off;
111     state->theend = state->str + state->sz - 1;
112   }
113   return 0;
114 }
115
116 static int
117 as_append_char (struct state *state, unsigned char c)
118 {
119   if(as_reserve (state, 1))
120     return 1;
121   else {
122     *state->s++ = c;
123     return 0;
124   }
125 }
126
127 static int
128 append_number(struct state *state,
129               unsigned long num, unsigned base, char *rep,
130               int width, int prec, int flags, int minusp)
131 {
132   int len = 0;
133   int i;
134
135   /* given precision, ignore zero flag */
136   if(prec != -1)
137     flags &= ~zero_flag;
138   else
139     prec = 1;
140   /* zero value with zero precision -> "" */
141   if(prec == 0 && num == 0)
142     return 0;
143   do{
144     if((*state->append_char)(state, rep[num % base]))
145       return 1;
146     len++;
147     num /= base;
148   }while(num);
149   prec -= len;
150   /* pad with prec zeros */
151   while(prec-- > 0){
152     if((*state->append_char)(state, '0'))
153       return 1;
154     len++;
155   }
156   /* add length of alternate prefix (added later) to len */
157   if(flags & alternate_flag && (base == 16 || base == 8))
158     len += base / 8;
159   /* pad with zeros */
160   if(flags & zero_flag){
161     width -= len;
162     if(minusp || (flags & space_flag) || (flags & plus_flag))
163       width--;
164     while(width-- > 0){
165       if((*state->append_char)(state, '0'))
166         return 1;
167       len++;
168     }
169   }
170   /* add alternate prefix */
171   if(flags & alternate_flag && (base == 16 || base == 8)){
172     if(base == 16)
173       if((*state->append_char)(state, rep[10] + 23)) /* XXX */
174         return 1;
175     if((*state->append_char)(state, '0'))
176       return 1;
177   }
178   /* add sign */
179   if(minusp){
180     if((*state->append_char)(state, '-'))
181       return 1;
182     len++;
183   } else if(flags & plus_flag) {
184     if((*state->append_char)(state, '+'))
185       return 1;
186     len++;
187   } else if(flags & space_flag) {
188     if((*state->append_char)(state, ' '))
189       return 1;
190     len++;
191   }
192   if(flags & minus_flag)
193     /* swap before padding with spaces */
194     for(i = 0; i < len / 2; i++){
195       char c = state->s[-i-1];
196       state->s[-i-1] = state->s[-len+i];
197       state->s[-len+i] = c;
198     }
199   width -= len;
200   while(width-- > 0){
201     if((*state->append_char)(state,  ' '))
202       return 1;
203     len++;
204   }
205   if(!(flags & minus_flag))
206     /* swap after padding with spaces */
207     for(i = 0; i < len / 2; i++){
208       char c = state->s[-i-1];
209       state->s[-i-1] = state->s[-len+i];
210       state->s[-len+i] = c;
211     }
212     
213   return 0;
214 }
215
216 static int
217 append_string (struct state *state,
218                unsigned char *arg,
219                int width,
220                int prec,
221                int flags)
222 {
223     if(arg == NULL)
224         arg = (unsigned char*)"(null)";
225
226     if(prec != -1)
227         width -= prec;
228     else
229         width -= strlen((char *)arg);
230     if(!(flags & minus_flag))
231         while(width-- > 0)
232             if((*state->append_char) (state, ' '))
233                 return 1;
234     if (prec != -1) {
235         while (*arg && prec--)
236             if ((*state->append_char) (state, *arg++))
237                 return 1;
238     } else {
239         while (*arg)
240             if ((*state->append_char) (state, *arg++))
241                 return 1;
242     }
243     if(flags & minus_flag)
244         while(width-- > 0)
245             if((*state->append_char) (state, ' '))
246                 return 1;
247     return 0;
248 }
249
250 static int
251 append_char(struct state *state,
252             unsigned char arg,
253             int width,
254             int flags)
255 {
256   while(!(flags & minus_flag) && --width > 0)
257     if((*state->append_char) (state, ' '))
258       return 1;
259     
260   if((*state->append_char) (state, arg))
261     return 1;
262   while((flags & minus_flag) && --width > 0)
263     if((*state->append_char) (state, ' '))
264       return 1;
265     
266   return 0;
267 }
268
269 /*
270  * This can't be made into a function...
271  */
272
273 #define PARSE_INT_FORMAT(res, arg, unsig) \
274 if (long_flag) \
275      res = (unsig long)va_arg(arg, unsig long); \
276 else if (short_flag) \
277      res = (unsig short)va_arg(arg, unsig int); \
278 else \
279      res = (unsig int)va_arg(arg, unsig int)
280
281 /*
282  * zyxprintf - return 0 or -1
283  */
284
285 static int
286 xyzprintf (struct state *state, const char *char_format, va_list ap)
287 {
288   const unsigned char *format = (const unsigned char *)char_format;
289   unsigned char c;
290
291   while((c = *format++)) {
292     if (c == '%') {
293       int flags      = 0;
294       int width      = 0;
295       int prec       = -1;
296       int long_flag  = 0;
297       int short_flag = 0;
298
299       /* flags */
300       while((c = *format++)){
301         if(c == '-')
302           flags |= minus_flag;
303         else if(c == '+')
304           flags |= plus_flag;
305         else if(c == ' ')
306           flags |= space_flag;
307         else if(c == '#')
308           flags |= alternate_flag;
309         else if(c == '0')
310           flags |= zero_flag;
311         else
312           break;
313       }
314       
315       if((flags & space_flag) && (flags & plus_flag))
316         flags ^= space_flag;
317
318       if((flags & minus_flag) && (flags & zero_flag))
319         flags ^= zero_flag;
320
321       /* width */
322       if (isdigit(c))
323         do {
324           width = width * 10 + c - '0';
325           c = *format++;
326         } while(isdigit(c));
327       else if(c == '*') {
328         width = va_arg(ap, int);
329         c = *format++;
330       }
331
332       /* precision */
333       if (c == '.') {
334         prec = 0;
335         c = *format++;
336         if (isdigit(c))
337           do {
338             prec = prec * 10 + c - '0';
339             c = *format++;
340           } while(isdigit(c));
341         else if (c == '*') {
342           prec = va_arg(ap, int);
343           c = *format++;
344         }
345       }
346
347       /* size */
348
349       if (c == 'h') {
350         short_flag = 1;
351         c = *format++;
352       } else if (c == 'l') {
353         long_flag = 1;
354         c = *format++;
355       }
356
357       switch (c) {
358       case 'c' :
359         if(append_char(state, va_arg(ap, int), width, flags))
360           return -1;
361         break;
362       case 's' :
363         if (append_string(state,
364                           va_arg(ap, unsigned char*),
365                           width,
366                           prec, 
367                           flags))
368           return -1;
369         break;
370       case 'd' :
371       case 'i' : {
372         long arg;
373         unsigned long num;
374         int minusp = 0;
375
376         PARSE_INT_FORMAT(arg, ap, signed);
377
378         if (arg < 0) {
379           minusp = 1;
380           num = -arg;
381         } else
382           num = arg;
383
384         if (append_number (state, num, 10, "0123456789",
385                            width, prec, flags, minusp))
386           return -1;
387         break;
388       }
389       case 'u' : {
390         unsigned long arg;
391
392         PARSE_INT_FORMAT(arg, ap, unsigned);
393
394         if (append_number (state, arg, 10, "0123456789",
395                            width, prec, flags, 0))
396           return -1;
397         break;
398       }
399       case 'o' : {
400         unsigned long arg;
401
402         PARSE_INT_FORMAT(arg, ap, unsigned);
403
404         if (append_number (state, arg, 010, "01234567",
405                            width, prec, flags, 0))
406           return -1;
407         break;
408       }
409       case 'x' : {
410         unsigned long arg;
411
412         PARSE_INT_FORMAT(arg, ap, unsigned);
413
414         if (append_number (state, arg, 0x10, "0123456789abcdef",
415                            width, prec, flags, 0))
416           return -1;
417         break;
418       }
419       case 'X' :{
420         unsigned long arg;
421
422         PARSE_INT_FORMAT(arg, ap, unsigned);
423
424         if (append_number (state, arg, 0x10, "0123456789ABCDEF",
425                            width, prec, flags, 0))
426           return -1;
427         break;
428       }
429       case 'p' : {
430         unsigned long arg = (unsigned long)va_arg(ap, void*);
431
432         if (append_number (state, arg, 0x10, "0123456789ABCDEF",
433                            width, prec, flags, 0))
434           return -1;
435         break;
436       }
437       case 'n' : {
438         int *arg = va_arg(ap, int*);
439         *arg = state->s - state->str;
440         break;
441       }
442       case '\0' :
443           --format;
444           /* FALLTHROUGH */
445       case '%' :
446         if ((*state->append_char)(state, c))
447           return -1;
448         break;
449       default :
450         if (   (*state->append_char)(state, '%')
451             || (*state->append_char)(state, c))
452           return -1;
453         break;
454       }
455     } else
456       if ((*state->append_char) (state, c))
457         return -1;
458   }
459   return 0;
460 }
461
462 #ifndef HAVE_SNPRINTF
463 int
464 snprintf (char *str, size_t sz, const char *format, ...)
465 {
466   va_list args;
467   int ret;
468
469   va_start(args, format);
470   ret = vsnprintf (str, sz, format, args);
471
472 #ifdef PARANOIA
473   {
474     int ret2;
475     char *tmp;
476
477     tmp = malloc (sz);
478     if (tmp == NULL)
479       abort ();
480
481     ret2 = vsprintf (tmp, format, args);
482     if (ret != ret2 || strcmp(str, tmp))
483       abort ();
484     free (tmp);
485   }
486 #endif
487
488   va_end(args);
489   return ret;
490 }
491 #endif
492
493 #ifndef HAVE_ASPRINTF
494 int
495 asprintf (char **ret, const char *format, ...)
496 {
497   va_list args;
498   int val;
499
500   va_start(args, format);
501   val = vasprintf (ret, format, args);
502
503 #ifdef PARANOIA
504   {
505     int ret2;
506     char *tmp;
507     tmp = malloc (val + 1);
508     if (tmp == NULL)
509       abort ();
510
511     ret2 = vsprintf (tmp, format, args);
512     if (val != ret2 || strcmp(*ret, tmp))
513       abort ();
514     free (tmp);
515   }
516 #endif
517
518   va_end(args);
519   return val;
520 }
521 #endif
522
523 #ifndef HAVE_ASNPRINTF
524 int
525 asnprintf (char **ret, size_t max_sz, const char *format, ...)
526 {
527   va_list args;
528   int val;
529
530   va_start(args, format);
531   val = vasnprintf (ret, max_sz, format, args);
532
533 #ifdef PARANOIA
534   {
535     int ret2;
536     char *tmp;
537     tmp = malloc (val + 1);
538     if (tmp == NULL)
539       abort ();
540
541     ret2 = vsprintf (tmp, format, args);
542     if (val != ret2 || strcmp(*ret, tmp))
543       abort ();
544     free (tmp);
545   }
546 #endif
547
548   va_end(args);
549   return val;
550 }
551 #endif
552
553 #ifndef HAVE_VASPRINTF
554 int
555 vasprintf (char **ret, const char *format, va_list args)
556 {
557   return vasnprintf (ret, 0, format, args);
558 }
559 #endif
560
561
562 #ifndef HAVE_VASNPRINTF
563 int
564 vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
565 {
566   int st;
567   size_t len;
568   struct state state;
569
570   state.max_sz = max_sz;
571   state.sz     = 1;
572   state.str    = malloc(state.sz);
573   if (state.str == NULL) {
574     *ret = NULL;
575     return -1;
576   }
577   state.s = state.str;
578   state.theend = state.s + state.sz - 1;
579   state.append_char = as_append_char;
580   state.reserve     = as_reserve;
581
582   st = xyzprintf (&state, format, args);
583   if (st) {
584     free (state.str);
585     *ret = NULL;
586     return -1;
587   } else {
588     char *tmp;
589
590     *state.s = '\0';
591     len = state.s - state.str;
592     tmp = realloc (state.str, len+1);
593     if (tmp == NULL) {
594       free (state.str);
595       *ret = NULL;
596       return -1;
597     }
598     *ret = tmp;
599     return len;
600   }
601 }
602 #endif
603
604 #ifndef HAVE_VSNPRINTF
605 int
606 vsnprintf (char *str, size_t sz, const char *format, va_list args)
607 {
608   struct state state;
609   int ret;
610   unsigned char *ustr = (unsigned char *)str;
611
612   state.max_sz = 0;
613   state.sz     = sz;
614   state.str    = ustr;
615   state.s      = ustr;
616   state.theend = ustr + sz - 1;
617   state.append_char = sn_append_char;
618   state.reserve     = sn_reserve;
619
620   ret = xyzprintf (&state, format, args);
621   *state.s = '\0';
622   if (ret)
623     return sz;
624   else
625     return state.s - state.str;
626 }
627 #endif
628