The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/printf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* 
    2  * Mach Operating System
    3  * Copyright (c) 1993 Carnegie Mellon University
    4  * All Rights Reserved.
    5  * 
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  * 
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  * 
   16  * Carnegie Mellon requests users of this software to return to
   17  * 
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  * 
   23  * any improvements or extensions that they make and grant Carnegie Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /*
   27  * HISTORY
   28  * $Log:        printf.c,v $
   29  * Revision 2.15  93/03/09  10:55:12  danner
   30  *      Lint to quiet GCC.
   31  *      [93/03/07  13:25:20  af]
   32  * 
   33  *      A better, MP-safe sprintf.
   34  *      [93/03/05            af]
   35  * 
   36  * Revision 2.14  93/01/27  09:34:37  danner
   37  *      printf_init(), sprintf() are void.
   38  *      [93/01/25            jfriedl]
   39  * 
   40  *      Updated copyright.
   41  *      [93/01/12            berman]
   42  *      Wrote a version of sprintf() for general use.
   43  *      [92/03/18            berman]
   44  * 
   45  * Revision 2.13  93/01/14  17:35:37  danner
   46  *      64bit cleanup.  Tuned up doprnt slightly.
   47  *      [92/12/01            af]
   48  * 
   49  * Revision 2.12  92/08/03  17:38:32  jfriedl
   50  *      removed silly prototypes
   51  *      [92/08/02            jfriedl]
   52  * 
   53  * Revision 2.11  92/05/21  17:14:57  jfriedl
   54  *      Cleanup to quiet gcc warnings.
   55  *      Changed PUTC arg of _doprnt, etc. to be VOID (which it is)
   56  *      [92/05/16            jfriedl]
   57  * 
   58  * Revision 2.10  92/04/01  19:33:21  rpd
   59  *      Renamed gets to safe_gets.
   60  *      [92/03/31            rpd]
   61  * 
   62  * Revision 2.9  91/06/06  17:07:22  jsb
   63  *      Added gets (derived from boot_gets).
   64  *      [91/05/14  09:18:50  jsb]
   65  * 
   66  * Revision 2.8  91/05/14  16:44:59  mrt
   67  *      Correcting copyright
   68  * 
   69  * Revision 2.7  91/02/05  17:28:14  mrt
   70  *      Changed to new Mach copyright
   71  *      [91/02/01  16:15:41  mrt]
   72  * 
   73  * Revision 2.6  90/10/25  14:45:18  rwd
   74  *      Purged uprintf.
   75  *      [90/10/21            rpd]
   76  * 
   77  * Revision 2.5  90/08/27  22:03:08  dbg
   78  *      Add extra formats to printf: '#- ' prefixes, %z (signed hex),
   79  *      %r and %n (signed and unsigned, current radix).
   80  *      [90/08/20            dbg]
   81  * 
   82  * Revision 2.4  90/01/11  11:43:44  dbg
   83  *      De-linted.
   84  *      [90/01/03            dbg]
   85  * 
   86  * Revision 2.3  89/11/29  14:09:06  af
   87  *      Ooops, a typo.
   88  *      [89/10/29  09:34:26  af]
   89  * 
   90  *      Changed the case for %c to load ints and not chars. Or
   91  *      else it is byte-order dependent since C passes char as ints.
   92  *      [89/10/13            af]
   93  * 
   94  *      Turned the unused 'file descriptor' field for _doprnt and putchar
   95  *      into a more useful pointer to an (optional) specialized putchar
   96  *      routine.  This can be used, for instance, to divert debugging
   97  *      printouts to some specialized interface or IOP.
   98  *      [89/10/09            af]
   99  * 
  100  * Revision 2.2  89/09/25  11:00:58  rwd
  101  *      Added case 'X' same as 'x' for now.
  102  *      [89/09/20            rwd]
  103  * 
  104  * Revision 2.1  89/08/03  15:51:14  rwd
  105  * Created.
  106  * 
  107  *  8-Aug-88  David Golub (dbg) at Carnegie-Mellon University
  108  *      Converted for MACH kernel use.  Removed %r, %R, %b; added %b
  109  *      from Berkeley's kernel to print bit fields in device registers;
  110  *      changed to use varargs.
  111  *
  112  */
  113 
  114 /*
  115  *  Common code for printf et al.
  116  *
  117  *  The calling routine typically takes a variable number of arguments,
  118  *  and passes the address of the first one.  This implementation
  119  *  assumes a straightforward, stack implementation, aligned to the
  120  *  machine's wordsize.  Increasing addresses are assumed to point to
  121  *  successive arguments (left-to-right), as is the case for a machine
  122  *  with a downward-growing stack with arguments pushed right-to-left.
  123  *
  124  *  To write, for example, fprintf() using this routine, the code
  125  *
  126  *      fprintf(fd, format, args)
  127  *      FILE *fd;
  128  *      char *format;
  129  *      {
  130  *      _doprnt(format, &args, fd);
  131  *      }
  132  *
  133  *  would suffice.  (This example does not handle the fprintf's "return
  134  *  value" correctly, but who looks at the return value of fprintf
  135  *  anyway?)
  136  *
  137  *  This version implements the following printf features:
  138  *
  139  *      %d      decimal conversion
  140  *      %u      unsigned conversion
  141  *      %x      hexadecimal conversion
  142  *      %X      hexadecimal conversion with capital letters
  143  *      %o      octal conversion
  144  *      %c      character
  145  *      %s      string
  146  *      %m.n    field width, precision
  147  *      %-m.n   left adjustment
  148  *      %0m.n   zero-padding
  149  *      %*.*    width and precision taken from arguments
  150  *
  151  *  This version does not implement %f, %e, or %g.  It accepts, but
  152  *  ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not
  153  *  work correctly on machines for which sizeof(long) != sizeof(int).
  154  *  It does not even parse %D, %O, or %U; you should be using %ld, %o and
  155  *  %lu if you mean long conversion.
  156  *
  157  *  As mentioned, this version does not return any reasonable value.
  158  *
  159  *  Permission is granted to use, modify, or propagate this code as
  160  *  long as this notice is incorporated.
  161  *
  162  *  Steve Summit 3/25/87
  163  */
  164 
  165 /*
  166  * Added formats for decoding device registers:
  167  *
  168  * printf("reg = %b", regval, "<base><arg>*")
  169  *
  170  * where <base> is the output base expressed as a control character:
  171  * i.e. '\1' gives octal, '\2' gives hex.  Each <arg> is a sequence of
  172  * characters, the first of which gives the bit number to be inspected
  173  * (origin 1), and the rest (up to a control character (<= 32)) give the
  174  * name of the register.  Thus
  175  *      printf("reg = %b\n", 3, "\1\2BITTWO\1BITONE")
  176  * would produce
  177  *      reg = 3<BITTWO,BITONE>
  178  *
  179  * If the second character in <arg> is also a control character, it
  180  * indicates the last bit of a bit field.  In this case, printf will extract
  181  * bits <1> to <2> and print it.  Characters following the second control
  182  * character are printed before the bit field.
  183  *      printf("reg = %b\n", 0xb, "\1\4\3FIELD1=\2BITTWO\1BITONE")
  184  * would produce
  185  *      reg = b<FIELD1=2,BITONE>
  186  */
  187 /*
  188  * Added for general use:
  189  *      #       prefix for alternate format:
  190  *              0x (0X) for hex
  191  *              leading 0 for octal
  192  *      +       print '+' if positive
  193  *      blank   print ' ' if positive
  194  *
  195  *      z       signed hexadecimal
  196  *      r       signed, 'radix'
  197  *      n       unsigned, 'radix'
  198  *
  199  *      D,U,O,Z same as corresponding lower-case versions
  200  *              (compatibility)
  201  */
  202 
  203 #include <mach/boolean.h>
  204 #include <kern/lock.h>
  205 #include <kern/strings.h>
  206 #include <sys/varargs.h>
  207 
  208 #define isdigit(d) ((d) >= '' && (d) <= '9')
  209 #define Ctod(c) ((c) - '')
  210 
  211 #define MAXBUF (sizeof(long int) * 8)            /* enough for binary */
  212 
  213 
  214 void printnum(
  215         register unsigned long  u,
  216         register int            base,
  217         void                    (*putc)( char, vm_offset_t ),
  218         vm_offset_t             putc_arg)
  219 {
  220         char    buf[MAXBUF];    /* build number here */
  221         register char * p = &buf[MAXBUF-1];
  222         static char digs[] = "0123456789abcdef";
  223 
  224         do {
  225             *p-- = digs[u % base];
  226             u /= base;
  227         } while (u != 0);
  228 
  229         while (++p != &buf[MAXBUF])
  230             (*putc)(*p, putc_arg);
  231 
  232 }
  233 
  234 boolean_t       _doprnt_truncates = FALSE;
  235 decl_simple_lock_data(,_doprnt_lock)
  236 
  237 void printf_init()
  238 {
  239         simple_lock_init(&_doprnt_lock);
  240 }
  241 
  242 void _doprnt(
  243         register char   *fmt,
  244         va_list         *argp,
  245                                         /* character output routine */
  246         void            (*putc)( char, vm_offset_t),
  247         int             radix,          /* default radix - for '%r' */
  248         vm_offset_t     putc_arg)
  249 {
  250         int             length;
  251         int             prec;
  252         boolean_t       ladjust;
  253         char            padc;
  254         long            n;
  255         unsigned long   u;
  256         int             plus_sign;
  257         int             sign_char;
  258         boolean_t       altfmt, truncate;
  259         int             base;
  260         register char   c;
  261 
  262 #if 0
  263         /* Make sure that we get *some* printout, no matter what */
  264         simple_lock(&_doprnt_lock);
  265 #else
  266         {
  267                 register int i = 0;
  268                 while (i < 1*1024*1024) {
  269                         if (simple_lock_try(&_doprnt_lock))
  270                                 break;
  271                         i++;
  272                 }
  273         }
  274 #endif
  275 
  276         while ((c = *fmt) != '\0') {
  277             if (c != '%') {
  278                 (*putc)(c, putc_arg);
  279                 fmt++;
  280                 continue;
  281             }
  282 
  283             fmt++;
  284 
  285             length = 0;
  286             prec = -1;
  287             ladjust = FALSE;
  288             padc = ' ';
  289             plus_sign = 0;
  290             sign_char = 0;
  291             altfmt = FALSE;
  292 
  293             while (TRUE) {
  294                 c = *fmt;
  295                 if (c == '#') {
  296                     altfmt = TRUE;
  297                 }
  298                 else if (c == '-') {
  299                     ladjust = TRUE;
  300                 }
  301                 else if (c == '+') {
  302                     plus_sign = '+';
  303                 }
  304                 else if (c == ' ') {
  305                     if (plus_sign == 0)
  306                         plus_sign = ' ';
  307                 }
  308                 else
  309                     break;
  310                 fmt++;
  311             }
  312 
  313             if (c == '') {
  314                 padc = '';
  315                 c = *++fmt;
  316             }
  317 
  318             if (isdigit(c)) {
  319                 while(isdigit(c)) {
  320                     length = 10 * length + Ctod(c);
  321                     c = *++fmt;
  322                 }
  323             }
  324             else if (c == '*') {
  325                 length = va_arg(*argp, int);
  326                 c = *++fmt;
  327                 if (length < 0) {
  328                     ladjust = !ladjust;
  329                     length = -length;
  330                 }
  331             }
  332 
  333             if (c == '.') {
  334                 c = *++fmt;
  335                 if (isdigit(c)) {
  336                     prec = 0;
  337                     while(isdigit(c)) {
  338                         prec = 10 * prec + Ctod(c);
  339                         c = *++fmt;
  340                     }
  341                 }
  342                 else if (c == '*') {
  343                     prec = va_arg(*argp, int);
  344                     c = *++fmt;
  345                 }
  346             }
  347 
  348             if (c == 'l')
  349                 c = *++fmt;     /* need it if sizeof(int) < sizeof(long) */
  350 
  351             truncate = FALSE;
  352 
  353             switch(c) {
  354                 case 'b':
  355                 case 'B':
  356                 {
  357                     register char *p;
  358                     boolean_t     any;
  359                     register int  i;
  360 
  361                     u = va_arg(*argp, unsigned long);
  362                     p = va_arg(*argp, char *);
  363                     base = *p++;
  364                     printnum(u, base, putc, putc_arg);
  365 
  366                     if (u == 0)
  367                         break;
  368 
  369                     any = FALSE;
  370                     while (i = *p++) {
  371                         /* NOTE: The '32' here is because ascii space */
  372                         if (*p <= 32) {
  373                             /*
  374                              * Bit field
  375                              */
  376                             register int j;
  377                             if (any)
  378                                 (*putc)(',', putc_arg);
  379                             else {
  380                                 (*putc)('<', putc_arg);
  381                                 any = TRUE;
  382                             }
  383                             j = *p++;
  384                             for (; (c = *p) > 32; p++)
  385                                 (*putc)(c, putc_arg);
  386                             printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
  387                                         base, putc, putc_arg);
  388                         }
  389                         else if (u & (1<<(i-1))) {
  390                             if (any)
  391                                 (*putc)(',', putc_arg);
  392                             else {
  393                                 (*putc)('<', putc_arg);
  394                                 any = TRUE;
  395                             }
  396                             for (; (c = *p) > 32; p++)
  397                                 (*putc)(c, putc_arg);
  398                         }
  399                         else {
  400                             for (; *p > 32; p++)
  401                                 continue;
  402                         }
  403                     }
  404                     if (any)
  405                         (*putc)('>', putc_arg);
  406                     break;
  407                 }
  408 
  409                 case 'c':
  410                     c = va_arg(*argp, int);
  411                     (*putc)(c, putc_arg);
  412                     break;
  413 
  414                 case 's':
  415                 {
  416                     register char *p;
  417                     register char *p2;
  418 
  419                     if (prec == -1)
  420                         prec = 0x7fffffff;      /* MAXINT */
  421 
  422                     p = va_arg(*argp, char *);
  423 
  424                     if (p == (char *)0)
  425                         p = "";
  426 
  427                     if (length > 0 && !ladjust) {
  428                         n = 0;
  429                         p2 = p;
  430 
  431                         for (; *p != '\0' && n < prec; p++)
  432                             n++;
  433 
  434                         p = p2;
  435 
  436                         while (n < length) {
  437                             (*putc)(' ', putc_arg);
  438                             n++;
  439                         }
  440                     }
  441 
  442                     n = 0;
  443 
  444                     while (*p != '\0') {
  445                         if (++n > prec)
  446                             break;
  447 
  448                         (*putc)(*p++, putc_arg);
  449                     }
  450 
  451                     if (n < length && ladjust) {
  452                         while (n < length) {
  453                             (*putc)(' ', putc_arg);
  454                             n++;
  455                         }
  456                     }
  457 
  458                     break;
  459                 }
  460 
  461                 case 'o':
  462                     truncate = _doprnt_truncates;
  463                 case 'O':
  464                     base = 8;
  465                     goto print_unsigned;
  466 
  467                 case 'd':
  468                     truncate = _doprnt_truncates;
  469                 case 'D':
  470                     base = 10;
  471                     goto print_signed;
  472 
  473                 case 'u':
  474                     truncate = _doprnt_truncates;
  475                 case 'U':
  476                     base = 10;
  477                     goto print_unsigned;
  478 
  479                 case 'x':
  480                     truncate = _doprnt_truncates;
  481                 case 'X':
  482                     base = 16;
  483                     goto print_unsigned;
  484 
  485                 case 'z':
  486                     truncate = _doprnt_truncates;
  487                 case 'Z':
  488                     base = 16;
  489                     goto print_signed;
  490 
  491                 case 'r':
  492                     truncate = _doprnt_truncates;
  493                 case 'R':
  494                     base = radix;
  495                     goto print_signed;
  496 
  497                 case 'n':
  498                     truncate = _doprnt_truncates;
  499                 case 'N':
  500                     base = radix;
  501                     goto print_unsigned;
  502 
  503                 print_signed:
  504                     n = va_arg(*argp, long);
  505                     if (n >= 0) {
  506                         u = n;
  507                         sign_char = plus_sign;
  508                     }
  509                     else {
  510                         u = -n;
  511                         sign_char = '-';
  512                     }
  513                     goto print_num;
  514 
  515                 print_unsigned:
  516                     u = va_arg(*argp, unsigned long);
  517                     goto print_num;
  518 
  519                 print_num:
  520                 {
  521                     char        buf[MAXBUF];    /* build number here */
  522                     register char *     p = &buf[MAXBUF-1];
  523                     static char digits[] = "0123456789abcdef";
  524                     char *prefix = 0;
  525 
  526                     if (truncate) u = (long)((int)(u));
  527 
  528                     if (u != 0 && altfmt) {
  529                         if (base == 8)
  530                             prefix = "";
  531                         else if (base == 16)
  532                             prefix = "0x";
  533                     }
  534 
  535                     do {
  536                         *p-- = digits[u % base];
  537                         u /= base;
  538                     } while (u != 0);
  539 
  540                     length -= (&buf[MAXBUF-1] - p);
  541                     if (sign_char)
  542                         length--;
  543                     if (prefix)
  544                         length -= strlen(prefix);
  545 
  546                     if (padc == ' ' && !ladjust) {
  547                         /* blank padding goes before prefix */
  548                         while (--length >= 0)
  549                             (*putc)(' ', putc_arg);
  550                     }
  551                     if (sign_char)
  552                         (*putc)(sign_char, putc_arg);
  553                     if (prefix)
  554                         while (*prefix)
  555                             (*putc)(*prefix++, putc_arg);
  556                     if (padc == '') {
  557                         /* zero padding goes after sign and prefix */
  558                         while (--length >= 0)
  559                             (*putc)('', putc_arg);
  560                     }
  561                     while (++p != &buf[MAXBUF])
  562                         (*putc)(*p, putc_arg);
  563 
  564                     if (ladjust) {
  565                         while (--length >= 0)
  566                             (*putc)(' ', putc_arg);
  567                     }
  568                     break;
  569                 }
  570 
  571                 case '\0':
  572                     fmt--;
  573                     break;
  574 
  575                 default:
  576                     (*putc)(c, putc_arg);
  577             }
  578         fmt++;
  579         }
  580 
  581         simple_unlock(&_doprnt_lock);
  582 }
  583 
  584 /*
  585  * Printing (to console)
  586  */
  587 extern void     cnputc( char, /*not really*/vm_offset_t);
  588 
  589 /*VARARGS1*/
  590 void printf(fmt, va_alist)
  591         char *  fmt;
  592         va_dcl
  593 {
  594         va_list listp;
  595         va_start(listp);
  596         _doprnt(fmt, &listp, cnputc, 16, 0);
  597         va_end(listp);
  598 }
  599 
  600 int     indent = 0;
  601 
  602 /*
  603  * Printing (to console) with indentation.
  604  */
  605 /*VARARGS1*/
  606 void iprintf(fmt, va_alist)
  607         char *  fmt;
  608         va_dcl
  609 {
  610         va_list listp;
  611         register int i;
  612 
  613         for (i = indent; i > 0; ){
  614             if (i >= 8) {
  615                 printf("\t");
  616                 i -= 8;
  617             }
  618             else {
  619                 printf(" ");
  620                 i--;
  621             }
  622         }
  623         va_start(listp);
  624         _doprnt(fmt, &listp, cnputc, 16, 0);
  625         va_end(listp);
  626 }
  627 
  628 /*
  629  * Printing to generic buffer
  630  * Returns #bytes printed.
  631  * Strings are zero-terminated.
  632  */
  633 static void
  634 sputc(
  635         char            c,
  636         vm_offset_t     arg)
  637 {
  638         register char   **bufp = (char **) arg;
  639         register char   *p = *bufp;
  640         *p++ = c;
  641         *bufp = p;
  642 }
  643 
  644 int
  645 sprintf( buf, fmt, va_alist)
  646         char    *buf;
  647         char    *fmt;
  648         va_dcl
  649 {
  650         va_list listp;
  651         char    *start = buf;
  652 
  653         va_start(listp);
  654         _doprnt(fmt, &listp, sputc, 16, (vm_offset_t)&buf);
  655         va_end(listp);
  656 
  657         *buf = 0;
  658         return (buf - start);
  659 }
  660 
  661 
  662 void safe_gets(str, maxlen)
  663         char *str;
  664         int  maxlen;
  665 {
  666         register char *lp;
  667         register int c;
  668         char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
  669 
  670         lp = str;
  671         for (;;) {
  672                 c = cngetc();
  673                 switch (c) {
  674                 case '\n':
  675                 case '\r':
  676                         printf("\n");
  677                         *lp++ = 0;
  678                         return;
  679                         
  680                 case '\b':
  681                 case '#':
  682                 case '\177':
  683                         if (lp > str) {
  684                                 printf("\b \b");
  685                                 lp--;
  686                         }
  687                         continue;
  688 
  689                 case '@':
  690                 case 'u'&037:
  691                         lp = str;
  692                         printf("\n\r");
  693                         continue;
  694 
  695                 default:
  696                         if (c >= ' ' && c < '\177') {
  697                                 if (lp < strmax) {
  698                                         *lp++ = c;
  699                                         printf("%c", c);
  700                                 }
  701                                 else {
  702                                         printf("%c", '\007'); /* beep */
  703                                 }
  704                         }
  705                 }
  706         }
  707 }

Cache object: 18b039c8ae0a7722be15df041d0b249e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.