]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/cygmon/v2_0/misc/bsp/common/vprintf.c
Initial revision
[karo-tx-redboot.git] / packages / cygmon / v2_0 / misc / bsp / common / vprintf.c
1 //==========================================================================
2 //
3 //      vprintf.c
4 //
5 //      Stripped down (no floating point) for debugging printf in ROMable BSP.
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):    
44 // Contributors: gthomas
45 // Date:         1999-10-20
46 // Purpose:      
47 // Description:  
48 //               
49 //
50 //####DESCRIPTIONEND####
51 //
52 //=========================================================================
53
54 /*
55  * Copyright (c) 1990, 1999 The Regents of the University of California.
56  * All rights reserved.
57  *
58  * This code is derived from software contributed to Berkeley by
59  * Chris Torek.
60  *
61  * Redistribution and use in source and binary forms, with or without
62  * modification, are permitted provided that the following conditions
63  * are met:
64  * 1. Redistributions of source code must retain the above copyright
65  *    notice, this list of conditions and the following disclaimer.
66  * 2. Redistributions in binary form must reproduce the above copyright
67  *    notice, this list of conditions and the following disclaimer in the
68  *    documentation and/or other materials provided with the distribution.
69  * 3. All advertising materials mentioning features or use of this software
70  *    must display the following acknowledgement:
71  *      This product includes software developed by the University of
72  *      California, Berkeley and its contributors.
73  * 4. Neither the name of the University nor the names of its contributors
74  *    may be used to endorse or promote products derived from this software
75  *    without specific prior written permission.
76  *
77  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
78  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
79  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
80  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
81  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
82  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
83  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
84  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
85  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
86  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
87  * SUCH DAMAGE.
88  */
89
90 /*
91  * Stripped down (no floating point) for debugging printf in ROMable BSP.
92  */
93 #include <string.h>
94 #include <stdarg.h>
95
96 #define BUF             40
97
98 #ifndef NULL
99 #define NULL ((void *)0)
100 #endif
101
102 /*
103  * Macros for converting digits to letters and vice versa
104  */
105 #define to_digit(c)     ((c) - '0')
106 #define is_digit(c)     ((unsigned)to_digit(c) <= 9)
107 #define to_char(n)      ((n) + '0')
108
109 /*
110  * Flags used during conversion.
111  */
112 #define ALT             0x001           /* alternate form */
113 #define HEXPREFIX       0x002           /* add 0x or 0X prefix */
114 #define LADJUST         0x004           /* left adjustment */
115 #define LONGDBL         0x008           /* long double; unimplemented */
116 #define LONGINT         0x010           /* long integer */
117 #define QUADINT         0x020           /* quad integer */
118 #define SHORTINT        0x040           /* short integer */
119 #define ZEROPAD         0x080           /* zero (as opposed to blank) pad */
120 #define FPT             0x100           /* Floating point number */
121
122
123 void
124 __vprintf(void (*putc_func)(char c), const char *fmt0, va_list ap)
125 {
126     char *fmt;          /* format string */
127     int ch;             /* character from fmt */
128     int n, m;           /* handy integers (short term usage) */
129     char *cp;           /* handy char pointer (short term usage) */
130     int flags;          /* flags as above */
131     int width;                  /* width from format (%8d), or 0 */
132     int prec;                   /* precision from format (%.3d), or -1 */
133     char sign;                  /* sign prefix (' ', '+', '-', or \0) */
134     unsigned long _uquad;
135     enum {OCT, DEC, HEX} base;  /* base for [diouxX] conversion */
136     int dprec;                  /* a copy of prec if [diouxX], 0 otherwise */
137     int realsz;                 /* field size expanded by dprec */
138     int size;                   /* size of converted field or string */
139     char *xdigs = NULL;         /* digits for [xX] conversion */
140     char buf[BUF];              /* space for %c, %[diouxX], %[eEfgG] */
141     char ox[2];                 /* space for 0x hex-prefix */
142
143 #define PRINT(ptr, len) {         \
144         for(n=0;n<(len);n++) {    \
145           if((ptr)[n] == '\n')    \
146             (*putc_func)('\r');   \
147           (*putc_func)((ptr)[n]); \
148         } \
149 }
150
151 #define PAD(howmany, with) {        \
152         if ((n = (howmany)) > 0) {  \
153             while (n--)             \
154                 (*putc_func)(with); \
155         } \
156 }
157
158     /*
159      * To extend shorts properly, we need both signed and unsigned
160      * argument extraction methods.
161      */
162 #define SARG() \
163         (flags&LONGINT ? va_arg(ap, long) : \
164             flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
165             (long)va_arg(ap, int))
166
167 #define UARG() \
168         (flags&LONGINT ? va_arg(ap, unsigned long) : \
169             flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
170             (unsigned long)va_arg(ap, unsigned int))
171
172     fmt = (char *)fmt0;
173
174     /*
175      * Scan the format for conversions (`%' character).
176      */
177     for (;;) {
178         cp = fmt;
179         while (*fmt && *fmt != '%')
180             fmt++;
181         if ((m = fmt - cp) != 0) {
182             PRINT(cp, m);
183         }
184
185         if (*fmt)
186             fmt++;              /* skip over '%' */
187         else
188             goto done;
189
190         flags = 0;
191         dprec = 0;
192         width = 0;
193         prec = -1;
194         sign = '\0';
195
196     rflag:
197         ch = *fmt++;
198     reswitch:
199         switch (ch) {
200           case ' ':
201             /*
202              * ``If the space and + flags both appear, the space
203              * flag will be ignored.''
204              *  -- ANSI X3J11
205              */
206             if (!sign)
207                 sign = ' ';
208             goto rflag;
209           case '#':
210             flags |= ALT;
211             goto rflag;
212           case '*':
213             /*
214              * ``A negative field width argument is taken as a
215              * - flag followed by a positive field width.''
216              *  -- ANSI X3J11
217              * They don't exclude field widths read from args.
218              */
219             if ((width = va_arg(ap, int)) >= 0)
220                 goto rflag;
221             width = -width;
222             /* FALLTHROUGH */
223           case '-':
224             flags |= LADJUST;
225             goto rflag;
226           case '+':
227             sign = '+';
228             goto rflag;
229           case '.':
230             if ((ch = *fmt++) == '*') {
231                 n = va_arg(ap, int);
232                 prec = n < 0 ? -1 : n;
233                 goto rflag;
234             }
235             n = 0;
236             while (is_digit(ch)) {
237                 n = 10 * n + to_digit(ch);
238                 ch = *fmt++;
239             }
240             prec = n < 0 ? -1 : n;
241             goto reswitch;
242           case '0':
243             /*
244              * ``Note that 0 is taken as a flag, not as the
245              * beginning of a field width.''
246              *  -- ANSI X3J11
247              */
248             flags |= ZEROPAD;
249             goto rflag;
250           case '1': case '2': case '3': case '4':
251           case '5': case '6': case '7': case '8': case '9':
252             n = 0;
253             do {
254                 n = 10 * n + to_digit(ch);
255                 ch = *fmt++;
256             } while (is_digit(ch));
257             width = n;
258             goto reswitch;
259           case 'h':
260             flags |= SHORTINT;
261             goto rflag;
262           case 'l':
263             if (*fmt == 'l') {
264                 fmt++;
265                 flags |= QUADINT;
266             } else {
267                 flags |= LONGINT;
268             }
269             goto rflag;
270           case 'c':
271             *(cp = buf) = va_arg(ap, int);
272             size = 1;
273             sign = '\0';
274             break;
275           case 'd':
276           case 'i':
277             _uquad = SARG();
278             if ((long) _uquad < 0)
279                 {
280
281                     _uquad = -_uquad;
282                     sign = '-';
283                 }
284             base = DEC;
285             goto number;
286           case 'o':
287             _uquad = UARG();
288             base = OCT;
289             goto nosign;
290           case 's':
291             if ((cp = va_arg(ap, char *)) == NULL)
292                 cp = "(null)";
293             if (prec >= 0) {
294                 /*
295                  * can't use strlen; can only look for the
296                  * NUL in the first `prec' characters, and
297                  * strlen() will go further.
298                  */
299                 char *p = memchr(cp, 0, prec);
300
301                 if (p != NULL) {
302                     size = p - cp;
303                     if (size > prec)
304                         size = prec;
305                 } else
306                     size = prec;
307             } else
308                 size = strlen(cp);
309             sign = '\0';
310             break;
311           case 'u':
312             _uquad = UARG();
313             base = DEC;
314             goto nosign;
315           case 'X':
316             xdigs = "0123456789ABCDEF";
317             goto hex;
318           case 'x':
319             xdigs = "0123456789abcdef";
320         hex:                    _uquad = UARG();
321             base = HEX;
322             /* leading 0x/X only if non-zero */
323             if (flags & ALT && _uquad != 0)
324                 flags |= HEXPREFIX;
325
326             /* unsigned conversions */
327         nosign:                 sign = '\0';
328             /*
329              * ``... diouXx conversions ... if a precision is
330              * specified, the 0 flag will be ignored.''
331              *  -- ANSI X3J11
332              */
333         number:                 if ((dprec = prec) >= 0)
334             flags &= ~ZEROPAD;
335
336             /*
337              * ``The result of converting a zero value with an
338              * explicit precision of zero is no characters.''
339              *  -- ANSI X3J11
340              */
341             cp = buf + BUF;
342             if (_uquad != 0 || prec != 0) {
343                 /*
344                  * Unsigned mod is hard, and unsigned mod
345                  * by a constant is easier than that by
346                  * a variable; hence this switch.
347                   */
348                 switch (base) {
349                   case OCT:
350                     do {
351                         *--cp = to_char(_uquad & 7);
352                         _uquad >>= 3;
353                     } while (_uquad);
354                     /* handle octal leading 0 */
355                     if (flags & ALT && *cp != '0')
356                         *--cp = '0';
357                     break;
358
359                   case DEC:
360                     /* many numbers are 1 digit */
361                     while (_uquad >= 10) {
362                         *--cp = to_char(_uquad % 10);
363                         _uquad /= 10;
364                     }
365                     *--cp = to_char(_uquad);
366                     break;
367
368                   case HEX:
369                     do {
370                         *--cp = xdigs[_uquad & 15];
371                         _uquad >>= 4;
372                     } while (_uquad);
373                     break;
374
375                   default:
376                     cp = "bug in vfprintf: bad base";
377                     size = strlen(cp);
378                     goto skipsize;
379                 }
380             }
381             size = buf + BUF - cp;
382         skipsize:
383             break;
384           default:      /* "%?" prints ?, unless ? is NUL */
385             if (ch == '\0')
386                 goto done;
387             /* pretend it was %c with argument ch */
388             cp = buf;
389             *cp = ch;
390             size = 1;
391             sign = '\0';
392             break;
393         }
394
395         /*
396          * All reasonable formats wind up here.  At this point, `cp'
397          * points to a string which (if not flags&LADJUST) should be
398          * padded out to `width' places.  If flags&ZEROPAD, it should
399          * first be prefixed by any sign or other prefix; otherwise,
400          * it should be blank padded before the prefix is emitted.
401          * After any left-hand padding and prefixing, emit zeroes
402          * required by a decimal [diouxX] precision, then print the
403          * string proper, then emit zeroes required by any leftover
404          * floating precision; finally, if LADJUST, pad with blanks.
405          *
406          * Compute actual size, so we know how much to pad.
407          * size excludes decimal prec; realsz includes it.
408          */
409         realsz = dprec > size ? dprec : size;
410         if (sign)
411             realsz++;
412         else if (flags & HEXPREFIX)
413             realsz+= 2;
414
415         /* right-adjusting blank padding */
416         if ((flags & (LADJUST|ZEROPAD)) == 0)
417             PAD(width - realsz, ' ');
418
419         /* prefix */
420         if (sign) {
421             PRINT(&sign, 1);
422         } else if (flags & HEXPREFIX) {
423             ox[0] = '0';
424             ox[1] = ch;
425             PRINT(ox, 2);
426         }
427
428         /* right-adjusting zero padding */
429         if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
430             PAD(width - realsz, '0');
431
432         /* leading zeroes from decimal precision */
433         PAD(dprec - size, '0');
434
435         /* the string or number proper */
436         PRINT(cp, size);
437
438         /* left-adjusting padding (always blank) */
439         if (flags & LADJUST)
440             PAD(width - realsz, ' ');
441     }
442  done:
443 }
444
445