/[rtmk]/rtmk/libkern/printf.c
ViewVC logotype

Diff of /rtmk/libkern/printf.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1.1.1 by jrydberg, Fri Dec 7 02:06:28 2001 UTC revision 1.2 by jrydberg, Sat Jan 5 00:08:30 2002 UTC
# Line 1  Line 1 
1    /* Common code for printf.
2       Copyright 1999-2002 Johan Rydberg, jrydberg@rtmk.org.
3    
4  /*  This program is free software; you can redistribute it and/or modify
5   * Mach Operating System  it under the terms of the GNU General Public License as published by
6   * Copyright (c) 1993 Carnegie Mellon University  the Free Software Foundation; either version 2 of the License, or
7   * All Rights Reserved.  (at your option) any later version.
8   *  
9   * Permission to use, copy, modify and distribute this software and its  This program is distributed in the hope that it will be useful,
10   * documentation is hereby granted, provided that both the copyright  but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * notice and this permission notice appear in all copies of the  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * software, derivative works or modified versions, and any portions  GNU General Public License for more details.
13   * thereof, and that both notices appear in supporting documentation.  
14   *  You should have received a copy of the GNU General Public License
15   * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"  along with this program; if not, write to the Free Software
16   * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.  
  *  
  * Carnegie Mellon requests users of this software to return to  
  *  
  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU  
  *  School of Computer Science  
  *  Carnegie Mellon University  
  *  Pittsburgh PA 15213-3890  
  *  
  * any improvements or extensions that they make and grant Carnegie Mellon  
  * the rights to redistribute these changes.  
  */  
 /*  
  *  Common code for printf et al.  
  *  
  *  The calling routine typically takes a variable number of arguments,  
  *  and passes the address of the first one.  This implementation  
  *  assumes a straightforward, stack implementation, aligned to the  
  *  machine's wordsize.  Increasing addresses are assumed to point to  
  *  successive arguments (left-to-right), as is the case for a machine  
  *  with a downward-growing stack with arguments pushed right-to-left.  
  *  
  *  To write, for example, fprintf() using this routine, the code  
  *  
  *  fprintf(fd, format, args)  
  *  FILE *fd;  
  *  char *format;  
  *  {  
  *  _doprnt(format, &args, fd);  
  *  }  
  *  
  *  would suffice.  (This example does not handle the fprintf's "return  
  *  value" correctly, but who looks at the return value of fprintf  
  *  anyway?)  
  *  
  *  This version implements the following printf features:  
  *  
  *  %d  decimal conversion  
  *  %u  unsigned conversion  
  *  %x  hexadecimal conversion  
  *  %X  hexadecimal conversion with capital letters  
  *  %o  octal conversion  
  *  %c  character  
  *  %s  string  
  *  %m.n  field width, precision  
  *  %-m.n left adjustment  
  *  %0m.n zero-padding  
  *  %*.*  width and precision taken from arguments  
  *  
  *  This version does not implement %f, %e, or %g.  It accepts, but  
  *  ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not  
  *  work correctly on machines for which sizeof(long) != sizeof(int).  
  *  It does not even parse %D, %O, or %U; you should be using %ld, %o and  
  *  %lu if you mean long conversion.  
  *  
  *  As mentioned, this version does not return any reasonable value.  
  *  
  *  Permission is granted to use, modify, or propagate this code as  
  *  long as this notice is incorporated.  
  *  
  *  Steve Summit 3/25/87  
  */  
   
 /*  
  * Added formats for decoding device registers:  
  *  
  * printf("reg = %b", regval, "<base><arg>*")  
  *  
  * where <base> is the output base expressed as a control character:  
  * i.e. '\10' gives octal, '\20' gives hex.  Each <arg> is a sequence of  
  * characters, the first of which gives the bit number to be inspected  
  * (origin 1), and the rest (up to a control character (<= 32)) give the  
  * name of the register.  Thus  
  *  printf("reg = %b\n", 3, "\10\2BITTWO\1BITONE")  
  * would produce  
  *  reg = 3<BITTWO,BITONE>  
  *  
  * If the second character in <arg> is also a control character, it  
  * indicates the last bit of a bit field.  In this case, printf will extract  
  * bits <1> to <2> and print it.  Characters following the second control  
  * character are printed before the bit field.  
  *  printf("reg = %b\n", 0xb, "\10\4\3FIELD1=\2BITTWO\1BITONE")  
  * would produce  
  *  reg = b<FIELD1=2,BITONE>  
  */  
 /*  
  * Added for general use:  
  *  # prefix for alternate format:  
  *    0x (0X) for hex  
  *    leading 0 for octal  
  *  + print '+' if positive  
  *  blank print ' ' if positive  
  *  
  *  z signed hexadecimal  
  *  r signed, 'radix'  
  *  n unsigned, 'radix'  
  *  
  *  D,U,O,Z same as corresponding lower-case versions  
  *    (compatibility)  
  */  
17    
 #include <stdbool.h>  
18  #include <stdarg.h>  #include <stdarg.h>
19  #include "libkern.h"  #include "libkern.h"
20    
 #define isdigit(d) ((d) >= '0' && (d) <= '9')  
 #define Ctod(c) ((c) - '0')  
   
 #define MAXBUF (sizeof(long int) * 8)   /* enough for binary */  
   
 static void  
 printnum (register unsigned long u,  
           register int base, void (*putc) (char, void *), void *putc_arg)  
 {  
   char buf[MAXBUF];             /* build number here */  
   register char *p = &buf[MAXBUF - 1];  
   static char digs[] = "0123456789abcdef";  
   
   do  
     {  
       *p-- = digs[u % base];  
       u /= base;  
     }  
   while (u != 0);  
   
   while (++p != &buf[MAXBUF])  
     (*putc) (*p, putc_arg);  
   
 }  
   
 static bool _doprnt_truncates = false;  
   
 static void  
 _doprnt (register char *fmt, va_list *argp,  
          /* character output routine */  
          void (*putc) (char, void *), int radix,        /* default radix - for '%r' */  
          void *putc_arg)  
 {  
   int length;  
   int prec;  
   bool ladjust;  
   char padc;  
   long n;  
   unsigned long u;  
   int plus_sign;  
   int sign_char;  
   bool altfmt, truncate;  
   int base;  
   register char c;  
   
   while ((c = *fmt) != '\0')  
     {  
       if (c != '%')  
         {  
           (*putc) (c, putc_arg);  
           fmt++;  
           continue;  
         }  
   
       fmt++;  
   
       length = 0;  
       prec = -1;  
       ladjust = false;  
       padc = ' ';  
       plus_sign = 0;  
       sign_char = 0;  
       altfmt = false;  
   
       while (true)  
         {  
           c = *fmt;  
           if (c == '#')  
             {  
               altfmt = true;  
               padc = '0';  
             }  
           else if (c == '-')  
             {  
               ladjust = true;  
             }  
           else if (c == '+')  
             {  
               plus_sign = '+';  
             }  
           else if (c == ' ')  
             {  
               if (plus_sign == 0)  
                 plus_sign = ' ';  
             }  
           else  
             break;  
           fmt++;  
         }  
   
       if (c == '0')  
         {  
           padc = '0';  
           c = *++fmt;  
         }  
   
       if (isdigit (c))  
         {  
           while (isdigit (c))  
             {  
               length = 10 * length + Ctod (c);  
               c = *++fmt;  
             }  
         }  
       else if (c == '*')  
         {  
           length = va_arg (*argp, int);  
           c = *++fmt;  
           if (length < 0)  
             {  
               ladjust = !ladjust;  
               length = -length;  
             }  
         }  
   
       if (c == '.')  
         {  
           c = *++fmt;  
           if (isdigit (c))  
             {  
               prec = 0;  
               while (isdigit (c))  
                 {  
                   prec = 10 * prec + Ctod (c);  
                   c = *++fmt;  
                 }  
             }  
           else if (c == '*')  
             {  
               prec = va_arg (*argp, int);  
               c = *++fmt;  
             }  
         }  
   
       if (c == 'l')  
         c = *++fmt;             /* need it if sizeof(int) < sizeof(long) */  
   
       truncate = false;  
   
       switch (c)  
         {  
         case 'b':  
         case 'B':  
           {  
             register char *p;  
             bool any;  
             register int i;  
   
             u = va_arg (*argp, unsigned long);  
             p = va_arg (*argp, char *);  
             base = *p++;  
             printnum (u, base, putc, putc_arg);  
   
             if (u == 0)  
               break;  
   
             any = false;  
             while ((i = *p++))  
               {  
                 /* NOTE: The '32' here is because ascii space */  
                 if (*p <= 32)  
                   {  
                     /*  
                      * Bit field  
                      */  
                     register int j;  
                     if (any)  
                       (*putc) (',', putc_arg);  
                     else  
                       {  
                         (*putc) ('<', putc_arg);  
                         any = true;  
                       }  
                     j = *p++;  
                     for (; (c = *p) > 32; p++)  
                       (*putc) (c, putc_arg);  
                     printnum ((unsigned)  
                               ((u >> (j - 1)) & ((2 << (i - j)) - 1)), base,  
                               putc, putc_arg);  
                   }  
                 else if (u & (1 << (i - 1)))  
                   {  
                     if (any)  
                       (*putc) (',', putc_arg);  
                     else  
                       {  
                         (*putc) ('<', putc_arg);  
                         any = true;  
                       }  
                     for (; (c = *p) > 32; p++)  
                       (*putc) (c, putc_arg);  
                   }  
                 else  
                   {  
                     for (; *p > 32; p++)  
                       continue;  
                   }  
               }  
             if (any)  
               (*putc) ('>', putc_arg);  
             break;  
           }  
   
         case 'c':  
           c = va_arg (*argp, int);  
           (*putc) (c, putc_arg);  
           break;  
   
         case 's':  
           {  
             register char *p;  
             register char *p2;  
   
             if (prec == -1)  
               prec = 0x7fffffff;        /* MAXINT */  
   
             p = va_arg (*argp, char *);  
   
             if (p == (char *) 0)  
               p = "";  
   
             if (length > 0 && !ladjust)  
               {  
                 n = 0;  
                 p2 = p;  
   
                 for (; *p != '\0' && n < prec; p++)  
                   n++;  
   
                 p = p2;  
   
                 while (n < length)  
                   {  
                     (*putc) (' ', putc_arg);  
                     n++;  
                   }  
               }  
   
             n = 0;  
   
             while (*p != '\0')  
               {  
                 if (++n > prec)  
                   break;  
   
                 (*putc) (*p++, putc_arg);  
               }  
   
             if (n < length && ladjust)  
               {  
                 while (n < length)  
                   {  
                     (*putc) (' ', putc_arg);  
                     n++;  
                   }  
               }  
   
             break;  
           }  
   
         case 'o':  
           truncate = _doprnt_truncates;  
         case 'O':  
           base = 8;  
           goto print_unsigned;  
   
         case 'd':  
           truncate = _doprnt_truncates;  
         case 'D':  
           base = 10;  
           goto print_signed;  
   
         case 'u':  
           truncate = _doprnt_truncates;  
         case 'U':  
           base = 10;  
           goto print_unsigned;  
   
         case 'x':  
           truncate = _doprnt_truncates;  
         case 'X':  
           base = 16;  
           goto print_unsigned;  
   
         case 'p':  
           truncate = _doprnt_truncates;  
         case 'P':  
           base = 16;  
           goto print_unsigned;  
   
         case 'z':  
           truncate = _doprnt_truncates;  
         case 'Z':  
           base = 16;  
           goto print_signed;  
   
         case 'r':  
           truncate = _doprnt_truncates;  
         case 'R':  
           base = radix;  
           goto print_signed;  
   
         case 'n':  
           truncate = _doprnt_truncates;  
         case 'N':  
           base = radix;  
           goto print_unsigned;  
   
         print_signed:  
           n = va_arg (*argp, long);  
           if (n >= 0)  
             {  
               u = n;  
               sign_char = plus_sign;  
             }  
           else  
             {  
               u = -n;  
               sign_char = '-';  
             }  
           goto print_num;  
   
         print_unsigned:  
           u = va_arg (*argp, unsigned long);  
           goto print_num;  
   
         print_num:  
           {  
             char buf[MAXBUF];   /* build number here */  
             register char *p = &buf[MAXBUF - 1];  
             static char digits[] = "0123456789abcdef";  
             char *prefix = 0;  
   
             if (truncate)  
               u = (long) ((int) (u));  
   
             if (u != 0 && altfmt)  
               {  
                 if (base == 8)  
                   prefix = "0";  
                 else if (base == 16)  
                   prefix = "0x";  
               }  
   
             do  
               {  
                 *p-- = digits[u % base];  
                 u /= base;  
               }  
             while (u != 0);  
   
             length -= (&buf[MAXBUF - 1] - p);  
             if (sign_char)  
               length--;  
             if (prefix)  
               length -= strlen (prefix);  
   
             if (padc == ' ' && !ladjust)  
               {  
                 /* blank padding goes before prefix */  
                 while (--length >= 0)  
                   (*putc) (' ', putc_arg);  
               }  
             if (sign_char)  
               (*putc) (sign_char, putc_arg);  
             if (prefix)  
               while (*prefix)  
                 (*putc) (*prefix++, putc_arg);  
             if (padc == '0')  
               {  
                 /* zero padding goes after sign and prefix */  
                 while (--length >= 0)  
                   (*putc) ('0', putc_arg);  
               }  
             while (++p != &buf[MAXBUF])  
               (*putc) (*p, putc_arg);  
   
             if (ladjust)  
               {  
                 while (--length >= 0)  
                   (*putc) (' ', putc_arg);  
               }  
             break;  
           }  
   
         case '\0':  
           fmt--;  
           break;  
   
         default:  
           (*putc) (c, putc_arg);  
         }  
       fmt++;  
     }  
 }  
21    
22  static void (*putc_fn) (char, void *) = 0;  static void (*putc_fn) (char, void *) = 0;
23  static void *putc_arg = 0;  static void *putc_arg = 0;
# Line 532  vprintf (char *fmt, va_list listp) Line 38  vprintf (char *fmt, va_list listp)
38    if (! putc_fn)    if (! putc_fn)
39      return 0;      return 0;
40    
 #if 1  
41    __lprintf (putc_arg, fmt, listp, putc_fn);    __lprintf (putc_arg, fmt, listp, putc_fn);
 #else  
   _doprnt (fmt, &listp, putc_fn, 16, putc_arg);  
 #endif  
42    return 0;    return 0;
43  }  }
44    
# Line 552  printf (const char *fmt, ...) Line 54  printf (const char *fmt, ...)
54  {  {
55    va_list listp;    va_list listp;
56    va_start (listp, fmt);    va_start (listp, fmt);
 #if 0  
   _doprnt ((char *) fmt, &listp, putc_fn, 16, putc_arg);  
 #else  
57    __lprintf (putc_arg, fmt, listp, putc_fn);    __lprintf (putc_arg, fmt, listp, putc_fn);
 #endif  
58    va_end (listp);    va_end (listp);
59    return 0;    return 0;
60  }  }
# Line 572  vsprintf (char *buf, char *fmt, va_list Line 70  vsprintf (char *buf, char *fmt, va_list
70  {  {
71    char *start_buf = buf;    char *start_buf = buf;
72    
 #if 0  
   _doprnt (fmt, &listp, savechar, 16, (void *) &buf);  
 #else  
73    __lprintf (savechar, fmt, listp, (void *) &buf);    __lprintf (savechar, fmt, listp, (void *) &buf);
 #endif  
74    *buf = '\0';    *buf = '\0';
75    return (int) (buf - start_buf);    return (int) (buf - start_buf);
76  }  }

Legend:
Removed from v.1.1.1.1  
changed lines
  Added in v.1.2

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26