Vari fix per documentazione e commenti
[bertos.git] / mware / formatwr.c
1 /*!
2  * \file
3  * <!--
4  * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
5  * This file is part of DevLib - See devlib/README for information.
6  * -->
7  *
8  * \version $Id$
9  *
10  * \brief Basic "printf", "sprintf" and "fprintf" formatter.
11  *
12  * This module is 100% reentrant and can be adapted to user-defined routines
13  * that needs formatters with special properties like different output
14  * channels or new format specifiers.
15  *
16  * To reduce size in applications not using real numbers or long integers
17  * the formatter may be compiled to exclude certain parts.  This is
18  * controlled by giving a -D option a compilation time:
19  *
20  * \code
21  *  -D CONFIG_PRINTF=PRINTF_FULL         Full ANSI printf formatter
22  *  -D CONFIG_PRINTF=PRINTF_NOFLOAT      Exclude support for floats
23  *  -D CONFIG_PRINTF=PRINTF_REDUCED      Simplified formatter (see below)
24  *  -D CONFIG_PRINTF=PRINTF_NOMODIFIERS  Exclude 'l' and 'h' modifiers in reduced version
25  *  -D CONFIG_PRINTF=PRINTF_DISABLED     No formatter at all
26  * \endcode
27  *
28  * Code size on AVR4 with GCC 3.4.1 (-O2):
29  *   PRINTF_FULL        2912byte (0xB60)
30  *   PRINTF_NOFLOAT     1684byte (0x694)
31  *   PRINTF_REDUCED      924byte (0x39C)
32  *   PRINTF_NOMODIFIERS  416byte (0x1A0)
33  *
34  * Code/data size in words on DSP56K with CodeWarrior 6.0:
35  *   PRINTF_FULL         1493/45
36  *   PRINTF_NOFLOAT      795/45
37  *   PRINTF_REDUCED      482/0
38  *   PRINTF_NOMODIFIERS  301/0
39  *
40  * The reduced version of formatter is suitable when program size is critical
41  * rather than formatting power.  This routine uses less than 20 bytes of
42  * stack space which makes it practical even in systems with less than 256
43  * bytes of user RAM.
44  *
45  * The only formatting specifiers supported by the reduced formatter are:
46  * \code
47  *    %% %c %s %d %o %x %X and %hd %ho %hx %hX %ld %lo %lx %lX
48  * \endcode
49  *
50  * It means that real variables are not supported as well as field
51  * width and precision arguments.
52  */
53
54 /*
55  * $Log$
56  * Revision 1.6  2004/07/30 14:34:10  rasky
57  * Vari fix per documentazione e commenti
58  * Aggiunte PP_CATn e STATIC_ASSERT
59  *
60  * Revision 1.5  2004/07/29 22:57:09  bernie
61  * Switch to new-style config handling.
62  *
63  * Revision 1.4  2004/07/21 00:20:20  bernie
64  * Allow completely disabling printf()-like formatter.
65  *
66  * Revision 1.3  2004/07/18 22:00:15  bernie
67  * Reorganize configuration parameters to match DevLib's convention.
68  *
69  * Revision 1.2  2004/06/03 11:27:09  bernie
70  * Add dual-license information.
71  *
72  * Revision 1.1  2004/05/23 15:43:16  bernie
73  * Import mware modules.
74  *
75  */
76
77 #include "formatwr.h"
78 #include <compiler.h> /* progmem macros */
79 #include <config.h> /* CONFIG_ macros */
80
81 #if CONFIG_PRINTF
82
83 #if CONFIG_PRINTF > PRINTF_NOFLOAT
84 #include <float.h>
85 #endif /* CONFIG_PRINTF > PRINTF_NOFLOAT */
86
87 #ifndef FRMWRI_BUFSIZE
88 /*bernie: save some memory, who cares about floats with lots of decimals? */
89 /*#define FRMWRI_BUFSIZE 134*/
90 #define FRMWRI_BUFSIZE 32
91 #endif
92
93 #ifndef MEM_ATTRIBUTE
94 #define MEM_ATTRIBUTE
95 #endif
96
97 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS
98         #define IS_SHORT (h_modifier || (sizeof(int) == 2 && !l_modifier))
99 #else
100         #define IS_SHORT (sizeof(int) == 2)
101 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */
102
103
104 #if CONFIG_PRINTF > PRINTF_NOFLOAT
105
106 static char *float_conversion(MEM_ATTRIBUTE long double value,
107                 MEM_ATTRIBUTE short nr_of_digits,
108                 MEM_ATTRIBUTE char *buf,
109                 MEM_ATTRIBUTE char format_flag,
110                 MEM_ATTRIBUTE char g_flag,
111                 MEM_ATTRIBUTE char alternate_flag)
112 {
113         MEM_ATTRIBUTE char *cp;
114         MEM_ATTRIBUTE char *buf_pointer;
115         MEM_ATTRIBUTE short n, i, dec_point_pos, integral_10_log;
116
117         buf_pointer = buf;
118         integral_10_log = 0;
119
120         if (value >= 1)
121         {
122                 while (value >= 1e11) /* To speed up things a bit */
123                 {
124                         value /= 1e10;
125                         integral_10_log += 10;
126                 }
127                 while (value >= 10)
128                 {
129                         value /= 10;
130                         integral_10_log++;
131                 }
132         }
133         else if (value) /* Not just 0.0 */
134         {
135                 while (value <= 1e-10) /* To speed up things a bit */
136                 {
137                         value *= 1e10;
138                         integral_10_log -= 10;
139                 }
140                 while (value < 1)
141                 {
142                         value *= 10;
143                         integral_10_log--;
144                 }
145         }
146         if (g_flag)
147         {
148                 if (integral_10_log < nr_of_digits && integral_10_log >= -4)
149                 {
150                         format_flag = 0;
151                         nr_of_digits -= integral_10_log;
152                 }
153                 nr_of_digits--;
154                 if (alternate_flag)
155                         /* %#G - No removal of trailing zeros */
156                         g_flag = 0;
157                 else
158                         /* %G - Removal of trailing zeros */
159                         alternate_flag = 1;
160         }
161
162         /* %e or %E */
163         if (format_flag)
164         {
165                 dec_point_pos = 0;
166         }
167         else
168         {
169                 /* Less than one... */
170                 if (integral_10_log < 0)
171                 {
172                         *buf_pointer++ = '0';
173                         if ((n = nr_of_digits) || alternate_flag)
174                                 *buf_pointer++ = '.';
175                         i = 0;
176                         while (--i > integral_10_log && nr_of_digits)
177                         {
178                                 *buf_pointer++ = '0';
179                                 nr_of_digits--;
180                         }
181                         if (integral_10_log < (-n - 1))
182                                 /* Nothing more to do */
183                                 goto CLEAN_UP;
184                         dec_point_pos = 1;
185                 }
186                 else
187                 {
188                         dec_point_pos = - integral_10_log;
189                 }
190         }
191
192         i = dec_point_pos;
193         while (i <= nr_of_digits )
194         {
195                 value -= (long double)(n = (short)value); /* n=Digit value=Remainder */
196                 value *= 10; /* Prepare for next shot */
197                 *buf_pointer++ = n + '0';
198                 if ( ! i++ && (nr_of_digits || alternate_flag))
199                         *buf_pointer++ = '.';
200         }
201
202         /* Rounding possible */
203         if (value >= 5)
204         {
205                 n = 1; /* Carry */
206                 cp = buf_pointer - 1;
207                 do
208                 {
209                         if (*cp != '.')
210                         {
211                                 if ( (*cp += n) == ('9' + 1) )
212                                 {
213                                         *cp = '0';
214                                         n = 1;
215                                 }
216                                 else
217                                         n = 0;
218                         }
219                 } while (cp-- > buf);
220                 if (n)
221                 {
222                         /* %e or %E */
223                         if (format_flag)
224                         {
225                                 cp = buf_pointer;
226                                 while (cp > buf)
227                                 {
228                                         if (*(cp - 1) == '.')
229                                         {
230                                                 *cp = *(cp - 2);
231                                                 cp--;
232                                         }
233                                         else
234                                                 *cp = *(cp - 1);
235                                         cp--;
236                                 }
237                                 integral_10_log++;
238                         }
239                         else
240                         {
241                                 cp = ++buf_pointer;
242                                 while (cp > buf)
243                                 {
244                                         *cp = *(cp - 1);
245                                         cp--;
246                                 }
247                         }
248                         *buf = '1';
249                 }
250         }
251
252 CLEAN_UP:
253         /* %G - Remove trailing zeros */
254         if (g_flag)
255         {
256                 while (*(buf_pointer - 1) == '0')
257                         buf_pointer--;
258                 if (*(buf_pointer - 1) == '.')
259                         buf_pointer--;
260         }
261
262         /* %e or %E */
263         if (format_flag)
264         {
265                 *buf_pointer++ = format_flag;
266                 if (integral_10_log < 0)
267                 {
268                         *buf_pointer++ = '-';
269                         integral_10_log = -integral_10_log;
270                 }
271                 else
272                         *buf_pointer++ = '+';
273                 n = 0;
274                 buf_pointer +=10;
275                 do
276                 {
277                         n++;
278                         *buf_pointer++ = (integral_10_log % 10) + '0';
279                         integral_10_log /= 10;
280                 } while ( integral_10_log || n < 2 );
281                 for ( i = n ; n > 0 ; n-- )
282                         *(buf_pointer - 11 - i + n) = *(buf_pointer - n);
283                 buf_pointer -= 10;
284         }
285         return (buf_pointer);
286 }
287
288 #endif /* CONFIG_PRINTF > PRINTF_NOFLOAT */
289
290 /*!
291  * This routine forms the core and entry of the formatter.
292  *
293  * The conversion performed conforms to the ANSI specification for "printf".
294  */
295 int
296 PGM_FUNC(_formatted_write)(const char * PGM_ATTR format,
297                 void put_one_char(char, void *),
298                 void *secret_pointer,
299                 va_list ap)
300 {
301 #if CONFIG_PRINTF > PRINTF_REDUCED
302         MEM_ATTRIBUTE static char bad_conversion[] = "???";
303         MEM_ATTRIBUTE static char null_pointer[] = "<NULL>";
304
305         MEM_ATTRIBUTE char format_flag;
306         MEM_ATTRIBUTE int precision;
307         MEM_ATTRIBUTE int n;
308         MEM_ATTRIBUTE int field_width, nr_of_chars;
309         MEM_ATTRIBUTE char plus_space_flag, left_adjust, l_L_modifier;
310         MEM_ATTRIBUTE char h_modifier, alternate_flag;
311         MEM_ATTRIBUTE char nonzero_value;
312         MEM_ATTRIBUTE unsigned long ulong, div_factor;
313
314 #if CONFIG_PRINTF >  PRINTF_NOFLOAT
315         MEM_ATTRIBUTE long double fvalue;
316 #endif
317
318         MEM_ATTRIBUTE char *buf_pointer;
319         MEM_ATTRIBUTE char *ptr;
320         MEM_ATTRIBUTE const char *hex;
321         MEM_ATTRIBUTE char zeropad;
322         MEM_ATTRIBUTE char buf[FRMWRI_BUFSIZE];
323
324         nr_of_chars = 0;
325         for (;;)    /* Until full format string read */
326         {
327                 while ((format_flag = PGM_READ_CHAR(format++)) != '%')    /* Until '%' or '\0' */
328                 {
329                         if (!format_flag)
330                                 return (nr_of_chars);
331                         put_one_char(format_flag, secret_pointer);
332                         nr_of_chars++;
333                 }
334                 if (PGM_READ_CHAR(format) == '%')    /* %% prints as % */
335                 {
336                         format++;
337                         put_one_char('%', secret_pointer);
338                         nr_of_chars++;
339                         continue;
340                 }
341
342                 plus_space_flag = left_adjust = alternate_flag = zeropad = 0;
343                 ptr = buf_pointer = &buf[0];
344                 hex = "0123456789ABCDEF";
345
346                 /* check for leading '-', '+', ' ','#' or '0' flags  */
347                 for (;;)
348                 {
349                         switch (PGM_READ_CHAR(format))
350                         {
351                                 case ' ':
352                                         if (plus_space_flag)
353                                                 goto NEXT_FLAG;
354                                 case '+':
355                                         plus_space_flag = PGM_READ_CHAR(format);
356                                         goto NEXT_FLAG;
357                                 case '-':
358                                         left_adjust++;
359                                         goto NEXT_FLAG;
360                                 case '#':
361                                         alternate_flag++;
362                                         goto NEXT_FLAG;
363                                 case '0':
364                                         zeropad++;
365                                         goto NEXT_FLAG;
366                         }
367                         break;
368 NEXT_FLAG:
369                         format++;
370                 }
371
372                 /* Optional field width (may be '*') */
373                 if (PGM_READ_CHAR(format) == '*')
374                 {
375                         field_width = va_arg(ap, int);
376                         if (field_width < 0)
377                         {
378                                 field_width = -field_width;
379                                 left_adjust++;
380                         }
381                         format++;
382                 }
383                 else
384                 {
385                         field_width = 0;
386                         while (PGM_READ_CHAR(format) >= '0' && PGM_READ_CHAR(format) <= '9')
387                                 field_width = field_width * 10 + (PGM_READ_CHAR(format++) - '0');
388                 }
389
390                 if (left_adjust)
391                         zeropad = 0;
392
393                 /* Optional precision (or '*') */
394                 if (PGM_READ_CHAR(format) == '.')
395                 {
396                         if (PGM_READ_CHAR(++format) == '*')
397                         {
398                                 precision = va_arg(ap, int);
399                                 format++;
400                         }
401                         else
402                         {
403                                 precision = 0;
404                                 while (PGM_READ_CHAR(format) >= '0' && PGM_READ_CHAR(format) <= '9')
405                                         precision = precision * 10 + (PGM_READ_CHAR(format++) - '0');
406                         }
407                 }
408                 else
409                         precision = -1;
410
411                 /* At this point, "left_adjust" is nonzero if there was
412                  * a sign, "zeropad" is 1 if there was a leading zero
413                  * and 0 otherwise, "field_width" and "precision"
414                  * contain numbers corresponding to the digit strings
415                  * before and after the decimal point, respectively,
416                  * and "plus_space_flag" is either 0 (no flag) or
417                  * contains a plus or space character. If there was no
418                  * decimal point, "precision" will be -1.
419                  */
420
421                 l_L_modifier = h_modifier = 0;
422
423                 /* Optional 'l','L' r 'h' modifier? */
424                 switch (PGM_READ_CHAR(format))
425                 {
426                         case 'l':
427                         case 'L':
428                                 l_L_modifier++;
429                                 format++;
430                                 break;
431                         case 'h':
432                                 h_modifier++;
433                                 format++;
434                                 break;
435                 }
436
437                 /*
438                  * At exit from the following switch, we will emit
439                  * the characters starting at "buf_pointer" and
440                  * ending at "ptr"-1
441                  */
442                 switch (format_flag = PGM_READ_CHAR(format++))
443                 {
444 #if 0 /* bernie */
445                         case 'n':
446                                 if (sizeof(short) != sizeof(int))
447                                 {
448                                         if (sizeof(int) != sizeof(long))
449                                         {
450                                                 if (h_modifier)
451                                                         *va_arg(ap, short *) = nr_of_chars;
452                                                 else if (l_L_modifier)
453                                                         *va_arg(ap, long *) = nr_of_chars;
454                                                 else
455                                                         *va_arg(ap, int *) = nr_of_chars;
456                                         }
457                                         else
458                                         {
459                                                 if (h_modifier)
460                                                         *va_arg(ap, short *) = nr_of_chars;
461                                                 else
462                                                         *va_arg(ap, int *) = nr_of_chars;
463                                         }
464                                 }
465                                 else
466                                 {
467                                         if (l_L_modifier)
468                                                 *va_arg(ap, long *) = nr_of_chars;
469                                         else
470                                                 *va_arg(ap, int *) = nr_of_chars;
471                                 }
472                                 continue;
473 #endif
474                         case 'c':
475                                 buf[0] = va_arg(ap, int);
476                                 ptr++;
477                                 break;
478
479                         case 's':
480                                 if ( !(buf_pointer = va_arg(ap, char *)) )
481                                         buf_pointer = null_pointer;
482                                 if (precision < 0)
483                                         precision = 10000;
484                                 for (n=0; *buf_pointer++ && n < precision; n++)
485                                         ;
486                                 ptr = --buf_pointer;
487                                 buf_pointer -= n;
488                                 break;
489
490                         case 'o':
491                                 if (alternate_flag && !precision)
492                                         precision++;
493                         case 'x':
494                                 hex = "0123456789abcdef";
495                         case 'u':
496                         case 'p':
497                         case 'X':
498                                 if (format_flag == 'p')
499 #if defined(__AVR__) || defined(__I196__) /* 16bit pointers */
500                                         ulong = (unsigned long)(unsigned short)va_arg(ap, char *);
501 #else /* 32bit pointers */
502                                 ulong = (unsigned long)va_arg(ap, char *);
503 #endif /* 32bit pointers */
504                                 else if (sizeof(short) == sizeof(int))
505                                         ulong = l_L_modifier ?
506                                                 va_arg(ap, unsigned long) : (unsigned long)va_arg(ap, unsigned int);
507                                 else
508                                         ulong = h_modifier ?
509                                                 (unsigned long)(unsigned short) va_arg(ap, int)
510                                                 : (unsigned long)va_arg(ap, int);
511                                 div_factor = (format_flag == 'o') ?
512                                         8 : (format_flag == 'u') ? 10 : 16;
513                                 plus_space_flag = 0;
514                                 goto INTEGRAL_CONVERSION;
515
516                         case 'd':
517                         case 'i':
518                                 if (sizeof(short) == sizeof(long))
519                                 {
520                                         if ( (long)(ulong = va_arg(ap, unsigned long)) < 0)
521                                         {
522                                                 plus_space_flag = '-';
523                                                 ulong = (unsigned long)(-((signed long)ulong));
524                                         }
525                                 }
526                                 else if (sizeof(short) == sizeof(int))
527                                 {
528                                         if ( (long)(ulong = l_L_modifier ?
529                                                                 va_arg(ap,unsigned long) : (unsigned long)va_arg(ap,int)) < 0)
530                                         {
531                                                 plus_space_flag = '-';
532                                                 ulong = (unsigned long)(-((signed long)ulong));
533                                         }
534                                 }
535                                 else
536                                 {
537                                         if ( (signed long)(ulong = (unsigned long) (h_modifier ?
538                                                                         (short) va_arg(ap, int) : va_arg(ap,int))) < 0)
539                                         {
540                                                 plus_space_flag = '-';
541                                                 ulong = (unsigned long)(-((signed long)ulong));
542                                         }
543                                 }
544                                 div_factor = 10;
545
546                                 /* Now convert to digits */
547 INTEGRAL_CONVERSION:
548                                 ptr = buf_pointer = &buf[FRMWRI_BUFSIZE - 1];
549                                 nonzero_value = (ulong != 0);
550
551                                 /* No char if zero and zero precision */
552                                 if (precision != 0 || nonzero_value)
553                                         do
554                                                 *--buf_pointer = hex[ulong % div_factor];
555                                         while (ulong /= div_factor);
556
557                                 /* "precision" takes precedence */
558                                 if (precision < 0)
559                                         if (zeropad)
560                                                 precision = field_width - (plus_space_flag != 0);
561                                 while (precision > (int)(ptr - buf_pointer))
562                                         *--buf_pointer = '0';
563
564                                 if (alternate_flag && nonzero_value)
565                                 {
566                                         if (format_flag == 'x' || format_flag == 'X')
567                                         {
568                                                 *--buf_pointer = format_flag;
569                                                 *--buf_pointer = '0';
570                                         }
571                                         else if ((format_flag == 'o') && (*buf_pointer != '0'))
572                                         {
573                                                 *--buf_pointer = '0';
574                                         }
575                                 }
576                                 break;
577
578 #if CONFIG_PRINTF > PRINTF_NOFLOAT
579                         case 'g':
580                         case 'G':
581                                 n = 1;
582                                 format_flag -= 2;
583                                 if (! precision)
584                                 {
585                                         precision = 1;
586                                 }
587                                 goto FLOATING_CONVERSION;
588                         case 'f':
589                                 format_flag = 0;
590                         case 'e':
591                         case 'E':
592                                 n = 0;
593 FLOATING_CONVERSION:
594                                 if (precision < 0)
595                                 {
596                                         precision = 6;
597                                 }
598                                 if (sizeof(double) != sizeof(long double))
599                                 {
600                                         if ( (fvalue = l_L_modifier ?
601                                                                 va_arg(ap,long double) : va_arg(ap,double)) < 0)
602                                         {
603                                                 plus_space_flag = '-';
604                                                 fvalue = -fvalue;
605                                         }
606                                 }
607                                 else if ( (fvalue = va_arg(ap,long double)) < 0)
608                                 {
609                                         plus_space_flag = '-';
610                                         fvalue = -fvalue;
611                                 }
612                                 ptr = float_conversion (fvalue,
613                                                 (short)precision,
614                                                 buf_pointer += field_width,
615                                                 format_flag,
616                                                 (char)n,
617                                                 alternate_flag);
618                                 if (zeropad)
619                                 {
620                                         precision = field_width - (plus_space_flag != 0);
621                                         while (precision > ptr - buf_pointer)
622                                                 *--buf_pointer = '0';
623                                 }
624                                 break;
625
626 #else /* CONFIG_PRINTF <= PRINTF_NOFLOAT */
627                         case 'g':
628                         case 'G':
629                         case 'f':
630                         case 'e':
631                         case 'E':
632                                 ptr = buf_pointer = bad_conversion;
633                                 while (*ptr)
634                                         ptr++;
635                                 break;
636 #endif /* CONFIG_PRINTF <= PRINTF_NOFLOAT */
637
638                         case '\0': /* Really bad place to find NUL in */
639                                 format--;
640
641                         default:
642                                 /* Undefined conversion! */
643                                 ptr = buf_pointer = bad_conversion;
644                                 ptr += 3;
645                                 break;
646
647                 }
648
649                 /*
650                  * This part emittes the formatted string to "put_one_char".
651                  */
652
653                 /* If field_width == 0 then nothing should be written. */
654                 precision = ptr - buf_pointer;
655
656                 if ( precision > field_width)
657                 {
658                         n = 0;
659                 }
660                 else
661                 {
662                         n = field_width - precision - (plus_space_flag != 0);
663                 }
664
665                 /* emit any leading pad characters */
666                 if (!left_adjust)
667                         while (--n >= 0)
668                         {
669                                 put_one_char(' ', secret_pointer);
670                                 nr_of_chars++;
671                         }
672
673                 /* emit flag characters (if any) */
674                 if (plus_space_flag)
675                 {
676                         put_one_char(plus_space_flag, secret_pointer);
677                         nr_of_chars++;
678                 }
679
680                 /* emit the string itself */
681                 while (--precision >= 0)
682                 {
683                         put_one_char(*buf_pointer++, secret_pointer);
684                         nr_of_chars++;
685                 }
686
687                 /* emit trailing space characters */
688                 if (left_adjust)
689                         while (--n >= 0)
690                         {
691                                 put_one_char(' ', secret_pointer);
692                                 nr_of_chars++;
693                         }
694         }
695
696 #else /* PRINTF_REDUCED starts here */
697
698 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS
699         char l_modifier, h_modifier;
700         unsigned long u_val, div_val;
701 #else
702         unsigned int u_val, div_val;
703 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */
704
705         char format_flag;
706         unsigned int nr_of_chars, base;
707         char outChar;
708         char *ptr;
709
710         nr_of_chars = 0;
711         for (;;)    /* Until full format string read */
712         {
713                 while ((format_flag = PGM_READ_CHAR(format++)) != '%')    /* Until '%' or '\0' */
714                 {
715                         if (!format_flag)
716                                 return (nr_of_chars);
717                         put_one_char(format_flag, secret_pointer);
718                         nr_of_chars++;
719                 }
720
721 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS
722                 /*=================================*/
723                 /* Optional 'l' or 'h' modifiers ? */
724                 /*=================================*/
725                 l_modifier = h_modifier = 0;
726                 switch (PGM_READ_CHAR(format))
727                 {
728                         case 'l':
729                                 l_modifier = 1;
730                                 format++;
731                                 break;
732
733                         case 'h':
734                                 h_modifier = 1;
735                                 format++;
736                                 break;
737                 }
738 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */
739
740                 switch (format_flag = PGM_READ_CHAR(format++))
741                 {
742                         case 'c':
743                                 format_flag = va_arg(ap, int);
744                         default:
745                                 put_one_char(format_flag, secret_pointer);
746                                 nr_of_chars++;
747                                 continue;
748
749                         case 's':
750                                 ptr = va_arg(ap, char *);
751                                 while ((format_flag = *ptr++))
752                                 {
753                                         put_one_char(format_flag, secret_pointer);
754                                         nr_of_chars++;
755                                 }
756                                 continue;
757
758                         case 'o':
759                                 base = 8;
760                                 if (IS_SHORT)
761                                         div_val = 0x8000;
762                                 else
763                                         div_val = 0x40000000;
764                                 goto CONVERSION_LOOP;
765
766                         case 'd':
767                                 base = 10;
768                                 if (IS_SHORT)
769                                         div_val = 10000;
770                                 else
771                                         div_val = 1000000000;
772                                 goto CONVERSION_LOOP;
773
774                         case 'X':
775                         case 'x':
776                                 base = 16;
777                                 if (IS_SHORT)
778                                         div_val = 0x1000;
779                                 else
780                                         div_val = 0x10000000;
781
782 CONVERSION_LOOP:
783 #if CONFIG_PRINTF > PRINTF_NOMODIFIERS
784                                 if (h_modifier)
785                                         u_val = (format_flag == 'd') ?
786                                                 (short)va_arg(ap, int) : (unsigned short)va_arg(ap, int);
787                                 else if (l_modifier)
788                                         u_val = va_arg(ap, long);
789                                 else
790                                         u_val = (format_flag == 'd') ?
791                                                 va_arg(ap,int) : va_arg(ap,unsigned int);
792 #else /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */
793                                 u_val = va_arg(ap,int);
794 #endif /* CONFIG_PRINTF > PRINTF_NOMODIFIERS */
795                                 if (format_flag == 'd')
796                                 {
797                                         if (((int)u_val) < 0)
798                                         {
799                                                 u_val = - u_val;
800                                                 put_one_char('-', secret_pointer);
801                                                 nr_of_chars++;
802                                         }
803                                 }
804                                 while (div_val > 1 && div_val > u_val)
805                                 {
806                                         div_val /= base;
807                                 }
808                                 do
809                                 {
810                                         outChar = (u_val / div_val) + '0';
811                                         if (outChar > '9')
812                                         {
813                                                 if (format_flag == 'x')
814                                                         outChar += 'a'-'9'-1;
815                                                 else
816                                                         outChar += 'A'-'9'-1;
817                                         }
818                                         put_one_char(outChar, secret_pointer);
819                                         nr_of_chars++;
820                                         u_val %= div_val;
821                                         div_val /= base;
822                                 }
823                                 while (div_val);
824
825                 } /* end switch(format_flag...) */
826         }
827 #endif /* CONFIG_PRINTF > PRINTF_REDUCED */
828 }
829
830 #endif /* CONFIG_PRINTF */