Subversion Repositories HelenOS

Rev

Rev 995 | Rev 1073 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (C) 2001-2004 Jakub Jermar
  3.  * Copyright (C) 2006 Josef Cejka
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  *
  10.  * - Redistributions of source code must retain the above copyright
  11.  *   notice, this list of conditions and the following disclaimer.
  12.  * - Redistributions in binary form must reproduce the above copyright
  13.  *   notice, this list of conditions and the following disclaimer in the
  14.  *   documentation and/or other materials provided with the distribution.
  15.  * - The name of the author may not be used to endorse or promote products
  16.  *   derived from this software without specific prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  19.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  20.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  23.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28.  */
  29.  
  30. #include <stdio.h>
  31. #include <unistd.h>
  32. #include <io/io.h>
  33. #include <stdarg.h>
  34.  
  35. #define __PRINTF_FLAG_PREFIX 0x00000001
  36. #define __PRINTF_FLAG_SIGNED 0x00000002
  37.  
  38. static char digits[] = "0123456789abcdef";  /**< Hexadecimal characters */
  39.  
  40. /** Print hexadecimal digits
  41.  *
  42.  * Print fixed count of hexadecimal digits from
  43.  * the number num. The digits are printed in
  44.  * natural left-to-right order starting with
  45.  * the width-th digit.
  46.  *
  47.  * @param num   Number containing digits.
  48.  * @param width Count of digits to print.
  49.  *
  50.  */
  51. static int print_fixed_hex(const uint64_t num, const int width, uint64_t flags)
  52. {
  53.     int i;
  54.     char buf[18]; /* 16 bytes for number + 2 for optionaly prefix */
  55.     char *bptr;
  56.    
  57.     bptr = buf;
  58.    
  59.     if (flags & __PRINTF_FLAG_PREFIX) {
  60.         buf[0] = '0';
  61.         buf[1] = 'x';
  62.         bptr += 2;
  63.     }
  64.  
  65.     for (i = width*8 - 4; i >= 0; i -= 4)
  66.         *bptr++ = digits[(num>>i) & 0xf];
  67.     *bptr = '\0';
  68.    
  69.     return putstr(buf);
  70. }
  71.  
  72.  
  73. /** Print number in given base
  74.  *
  75.  * Print significant digits of a number in given
  76.  * base.
  77.  *
  78.  * @param num  Number to print.
  79.  * @param base Base to print the number in (should
  80.  *             be in range 2 .. 16).
  81.  *
  82.  */
  83. static int print_number(const unsigned long num, const unsigned int base, uint64_t flags)
  84. {
  85.     int val = num;
  86.     char d[sizeof(unsigned long)*8+1];  /* this is good enough even for base == 2 */
  87.     int i = sizeof(unsigned long)*8-1;
  88.    
  89.     /* FIXME: if signed, print sign */
  90.    
  91.     do {
  92.         d[i--] = digits[val % base];
  93.     } while (val /= base);
  94.    
  95.     d[sizeof(unsigned long)*8] = 0;
  96.  
  97.     return putstr(&d[i + 1]);
  98. }
  99.  
  100.  
  101.  
  102. /** General formatted text print
  103.  *
  104.  * Print text formatted according the fmt parameter
  105.  * and variant arguments. Each formatting directive
  106.  * begins with \% (percentage) character and one of the
  107.  * following character:
  108.  *
  109.  * \%    Prints the percentage character.
  110.  *
  111.  * s    The next variant argument is treated as char*
  112.  *      and printed as a NULL terminated string.
  113.  *
  114.  * c    The next variant argument is treated as a single char.
  115.  *
  116.  * p    The next variant argument is treated as a maximum
  117.  *      bit-width integer with respect to architecture
  118.  *      and printed in full hexadecimal width.
  119.  *
  120.  * P    As with 'p', but '0x' is prefixed.
  121.  *
  122.  * q    The next variant argument is treated as a 64b integer
  123.  *      and printed in full hexadecimal width.
  124.  *
  125.  * Q    As with 'q', but '0x' is prefixed.
  126.  *
  127.  * l    The next variant argument is treated as a 32b integer
  128.  *      and printed in full hexadecimal width.
  129.  *
  130.  * L    As with 'l', but '0x' is prefixed.
  131.  *
  132.  * w    The next variant argument is treated as a 16b integer
  133.  *      and printed in full hexadecimal width.
  134.  *
  135.  * W    As with 'w', but '0x' is prefixed.
  136.  *
  137.  * b    The next variant argument is treated as a 8b integer
  138.  *      and printed in full hexadecimal width.
  139.  *
  140.  * B    As with 'b', but '0x' is prefixed.
  141.  *
  142.  * d    The next variant argument is treated as integer
  143.  *      and printed in standard decimal format (only significant
  144.  *      digits).
  145.  *
  146.  * x    The next variant argument is treated as integer
  147.  *      and printed in standard hexadecimal format (only significant
  148.  *      digits).
  149.  *
  150.  * X    As with 'x', but '0x' is prefixed.
  151.  *
  152.  * All other characters from fmt except the formatting directives
  153.  * are printed in verbatim.
  154.  *
  155.  * @param fmt Formatting NULL terminated string.
  156.  */
  157. int printf(const char *fmt, ...)
  158. {
  159.     int i = 0, j = 0;
  160.     int counter, retval;
  161.     va_list ap;
  162.     char c;
  163.  
  164.     uint64_t flags;
  165.    
  166.     counter = 0;
  167.     va_start(ap, fmt);
  168.  
  169.     while ((c = fmt[i])) {
  170.         /* control character */
  171.         if (c == '%' ) {
  172.             /* print common characters if any processed */ 
  173.             if (i > j) {
  174.                 if ((retval = putnchars(&fmt[j], (size_t)(i - j))) == EOF) { /* error */
  175.                     return -counter;
  176.                 }
  177.                 counter += retval;
  178.             }
  179.            
  180.             j = ++i;
  181.            
  182.             /* parse modifiers */
  183.             flags = 0;
  184.             /*switch (c = fmt[i]) {
  185.                 case '-':  
  186.             }  
  187.             */
  188.             switch (c = fmt[i]) {
  189.  
  190.                 /* percentile itself */
  191.                 case '%':
  192.                     --j;    /* soon will be incremented back */
  193.                     break;
  194.  
  195.                 /*
  196.                 * String and character conversions.
  197.                 */
  198.                 case 's':
  199.                     if ((retval = putstr(va_arg(ap, char*))) == EOF) {
  200.                         return -counter;
  201.                     };
  202.                    
  203.                     counter += retval;
  204.                     break;
  205.                 case 'c':
  206.                     c = va_arg(ap, unsigned long);
  207.                     if ((retval = putnchars(&c, sizeof(char))) == EOF) {
  208.                         return -counter;
  209.                     };
  210.                    
  211.                     counter += retval;
  212.                     break;
  213.  
  214.                 /*
  215.                 * Hexadecimal conversions with fixed width.
  216.                 */
  217.                 case 'P':
  218.                         flags |= __PRINTF_FLAG_PREFIX;
  219.                 case 'p':
  220.                         if ((retval = print_fixed_hex(va_arg(ap, unsigned long), sizeof(unsigned long), flags)) == EOF ) {
  221.                         return -counter;
  222.                     };
  223.  
  224.                     counter += retval;
  225.                     break;
  226.                 case 'Q':
  227.                         flags |= __PRINTF_FLAG_PREFIX;
  228.                 case 'q':
  229.                         if ((retval = print_fixed_hex(va_arg(ap, uint64_t), sizeof(uint64_t), flags)) == EOF ) {
  230.                         return -counter;
  231.                     };
  232.  
  233.                     counter += retval;
  234.                     break;
  235.                 case 'L':
  236.                         flags |= __PRINTF_FLAG_PREFIX;
  237.                 case 'l':
  238.                         if ((retval = print_fixed_hex(va_arg(ap, unsigned long), sizeof(uint32_t), flags)) == EOF ) {
  239.                         return -counter;
  240.                     };
  241.  
  242.                     counter += retval;
  243.                     break;
  244.                 case 'W':
  245.                         flags |= __PRINTF_FLAG_PREFIX;
  246.                 case 'w':
  247.                         if ((retval = print_fixed_hex(va_arg(ap, unsigned long), sizeof(uint16_t), flags)) == EOF ) {
  248.                         return -counter;
  249.                     };
  250.  
  251.                     counter += retval;
  252.                     break;
  253.                 case 'B':
  254.                         flags |= __PRINTF_FLAG_PREFIX;
  255.                 case 'b':
  256.                         if ((retval = print_fixed_hex(va_arg(ap, unsigned long), sizeof(uint8_t), flags)) == EOF ) {
  257.                         return -counter;
  258.                     };
  259.  
  260.                     counter += retval;
  261.                     break;
  262.                 /*
  263.                 * Decimal and hexadecimal conversions.
  264.                 */
  265.                 case 'd':
  266.                 case 'i':
  267.                         flags |= __PRINTF_FLAG_SIGNED;
  268.                         if ((retval = print_number(va_arg(ap,unsigned long), 10, flags)) == EOF ) {
  269.                         return -counter;
  270.                     };
  271.  
  272.                     counter += retval;
  273.                     break;
  274.                 case 'X':
  275.                         flags |= __PRINTF_FLAG_PREFIX;
  276.                 case 'x':
  277.                         if ((retval = print_number(va_arg(ap, unsigned long), 16, flags)) == EOF ) {
  278.                         return -counter;
  279.                     };
  280.  
  281.                     counter += retval;
  282.                     break;
  283.                 /*
  284.                 * Bad formatting.
  285.                 */
  286.                 default:
  287.                     return -counter;
  288.             }
  289.             ++j;
  290.         }  
  291.         ++i;
  292.     }
  293.    
  294.     if (i > j) {
  295.         if ((retval = putnchars(&fmt[j], (size_t)(i - j))) == EOF) { /* error */
  296.             return -counter;
  297.         }
  298.         counter += retval;
  299.     }
  300.    
  301.     va_end(ap);
  302.     return counter;
  303. }
  304.  
  305.