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