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

Cache object: 54917055f0a6098767ed8fce3e9c98c8


[ 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.