Subversion Repositories HelenOS

Rev

Rev 1010 | Rev 1173 | 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  /* show prefixes 0x or 0*/
  36. #define __PRINTF_FLAG_SIGNED        0x00000002  /* signed / unsigned number */
  37. #define __PRINTF_FLAG_ZEROPADDED    0x00000004  /* print leading zeroes */
  38. #define __PRINTF_FLAG_LEFTALIGNED   0x00000010  /* align to left */
  39. #define __PRINTF_FLAG_SHOWPLUS      0x00000020  /* always show + sign */
  40. #define __PRINTF_FLAG_SPACESIGN     0x00000040  /* print space instead of plus */
  41. #define __PRINTF_FLAG_BIGCHARS      0x00000080  /* show big characters */
  42. #define __PRINTF_FLAG_NEGATIVE      0x00000100  /* number has - sign */
  43.  
  44. #define PRINT_NUMBER_BUFFER_SIZE    (64+5)      /* Buffer big enought for 64 bit number
  45.                              * printed in base 2, sign, prefix and
  46.                              * 0 to terminate string.. (last one is only for better testing
  47.                              * end of buffer by zero-filling subroutine)
  48.                              */
  49. typedef enum {
  50.     PrintfQualifierByte = 0,
  51.     PrintfQualifierShort,
  52.     PrintfQualifierInt,
  53.     PrintfQualifierLong,
  54.     PrintfQualifierLongLong,
  55.     PrintfQualifierSizeT,
  56.     PrintfQualifierPointer
  57. } qualifier_t;
  58.  
  59. static char digits_small[] = "0123456789abcdef";    /* Small hexadecimal characters */
  60. static char digits_big[] = "0123456789ABCDEF";  /* Big hexadecimal characters */
  61.  
  62. /** Print number in given base
  63.  *
  64.  * Print significant digits of a number in given
  65.  * base.
  66.  *
  67.  * @param num  Number to print.
  68.  * @param size not used, in future releases will be replaced with precision and width params
  69.  * @param base Base to print the number in (should
  70.  *             be in range 2 .. 16).
  71.  * @param flags output modifiers
  72.  * @return number of written characters or EOF
  73.  *
  74.  */
  75. static int print_number(uint64_t num, size_t size, int base , uint64_t flags)
  76. {
  77.     /* FIXME: This is only first version.
  78.      * Printf does not have support for specification of size
  79.      * and precision, so this function writes with parameters defined by
  80.      * their type size.
  81.      */
  82.     char *digits = digits_small;
  83.     char d[PRINT_NUMBER_BUFFER_SIZE];   /* this is good enough even for base == 2, prefix and sign */
  84.     char *ptr = &d[PRINT_NUMBER_BUFFER_SIZE - 1];
  85.    
  86.     if (flags & __PRINTF_FLAG_BIGCHARS)
  87.         digits = digits_big;   
  88.    
  89.     *ptr-- = 0; /* Put zero at end of string */
  90.  
  91.     if (num == 0) {
  92.         *ptr-- = '0';
  93.     } else {
  94.         do {
  95.             *ptr-- = digits[num % base];
  96.         } while (num /= base);
  97.     }
  98.     if (flags & __PRINTF_FLAG_PREFIX) { /*FIXME*/
  99.         switch(base) {
  100.             case 2: /* Binary formating is not standard, but usefull */
  101.                 *ptr = 'b';
  102.                 if (flags & __PRINTF_FLAG_BIGCHARS) *ptr = 'B';
  103.                 ptr--;
  104.                 *ptr-- = '0';
  105.                 break;
  106.             case 8:
  107.                 *ptr-- = 'o';
  108.                 break;
  109.             case 16:
  110.                 *ptr = 'x';
  111.                 if (flags & __PRINTF_FLAG_BIGCHARS) *ptr = 'X';
  112.                 ptr--;
  113.                 *ptr-- = '0';
  114.                 break;
  115.         }
  116.     }
  117.    
  118.     if (flags & __PRINTF_FLAG_SIGNED) {
  119.         if (flags & __PRINTF_FLAG_NEGATIVE) {
  120.             *ptr-- = '-';
  121.         } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
  122.                 *ptr-- = '+';
  123.             } else if (flags & __PRINTF_FLAG_SPACESIGN) {
  124.                     *ptr-- = ' ';
  125.                 }
  126.     }
  127.  
  128.     /* Print leading zeroes */
  129.  
  130.     if (flags & __PRINTF_FLAG_LEFTALIGNED) {
  131.         flags &= ~__PRINTF_FLAG_ZEROPADDED;
  132.     }
  133.     if (flags & __PRINTF_FLAG_ZEROPADDED) {
  134.             while (ptr != d ) {
  135.             *ptr-- = '0';
  136.         }
  137.     }
  138.    
  139.     return putstr(++ptr);
  140. }
  141.  
  142.  
  143.  
  144. /** General formatted text print
  145.  *
  146.  * Print text formatted according the fmt parameter
  147.  * and variant arguments. Each formatting directive
  148.  * begins with \% (percentage) character and one of the
  149.  * following character:
  150.  *
  151.  * \%    Prints the percentage character.
  152.  *
  153.  * s    The next variant argument is treated as char*
  154.  *      and printed as a NULL terminated string.
  155.  *
  156.  * c    The next variant argument is treated as a single char.
  157.  *
  158.  * p    The next variant argument is treated as a maximum
  159.  *      bit-width integer with respect to architecture
  160.  *      and printed in full hexadecimal width.
  161.  *
  162.  * P    As with 'p', but '0x' is prefixed.
  163.  *
  164.  * q    The next variant argument is treated as a 64b integer
  165.  *      and printed in full hexadecimal width.
  166.  *
  167.  * Q    As with 'q', but '0x' is prefixed.
  168.  *
  169.  * l    The next variant argument is treated as a 32b integer
  170.  *      and printed in full hexadecimal width.
  171.  *
  172.  * L    As with 'l', but '0x' is prefixed.
  173.  *
  174.  * w    The next variant argument is treated as a 16b integer
  175.  *      and printed in full hexadecimal width.
  176.  *
  177.  * W    As with 'w', but '0x' is prefixed.
  178.  *
  179.  * b    The next variant argument is treated as a 8b integer
  180.  *      and printed in full hexadecimal width.
  181.  *
  182.  * B    As with 'b', but '0x' is prefixed.
  183.  *
  184.  * d    The next variant argument is treated as integer
  185.  *      and printed in standard decimal format (only significant
  186.  *      digits).
  187.  *
  188.  * x    The next variant argument is treated as integer
  189.  *      and printed in standard hexadecimal format (only significant
  190.  *      digits).
  191.  *
  192.  * X    As with 'x', but '0x' is prefixed.
  193.  *
  194.  * All other characters from fmt except the formatting directives
  195.  * are printed in verbatim.
  196.  *
  197.  * @param fmt Formatting NULL terminated string.
  198.  */
  199. int printf(const char *fmt, ...)
  200. {
  201.     int i = 0, j = 0; /* i is index of currently processed char from fmt, j is index to the first not printed nonformating character */
  202.     int end;
  203.     int counter; /* counter of printed characters */
  204.     int retval; /* used to store return values from called functions */
  205.     va_list ap;
  206.     char c;
  207.     qualifier_t qualifier;  /* type of argument */
  208.     int base;   /* base in which will be parameter (numbers only) printed */
  209.     uint64_t number; /* argument value */
  210.     size_t  size; /* byte size of integer parameter */
  211.     uint64_t flags;
  212.    
  213.     counter = 0;
  214.     va_start(ap, fmt);
  215.  
  216.     while ((c = fmt[i])) {
  217.         /* control character */
  218.         if (c == '%' ) {
  219.             /* print common characters if any processed */ 
  220.             if (i > j) {
  221.                 if ((retval = putnchars(&fmt[j], (size_t)(i - j))) == EOF) { /* error */
  222.                     return -counter;
  223.                 }
  224.                 counter += retval;
  225.             }
  226.        
  227.             j = i;
  228.             /* parse modifiers */
  229.             flags = 0;
  230.             end = 0;
  231.            
  232.             do {
  233.                 ++i;
  234.                 switch (c = fmt[i]) {
  235.                     case '#': flags |= __PRINTF_FLAG_PREFIX; break;
  236.                     case '-': flags |= __PRINTF_FLAG_LEFTALIGNED; break;
  237.                     case '+': flags |= __PRINTF_FLAG_SHOWPLUS; break;
  238.                     case ' ': flags |= __PRINTF_FLAG_SPACESIGN; break;
  239.                     case '0': flags |= __PRINTF_FLAG_ZEROPADDED; break;
  240.                     default: end = 1;
  241.                 }; 
  242.                
  243.             } while (end == 0);
  244.             /* TODO: width & '*' operator */
  245.             /* TODO: precision and '*' operator */ 
  246.  
  247.             switch (fmt[i++]) {
  248.                 case 'h':   /* char or short */
  249.                     qualifier = PrintfQualifierShort;
  250.                     if (fmt[i] == 'h') {
  251.                         i++;
  252.                         qualifier = PrintfQualifierByte;
  253.                     }
  254.                     break;
  255.                 case 'l':   /* long or long long*/
  256.                     qualifier = PrintfQualifierLong;
  257.                     if (fmt[i] == 'l') {
  258.                         i++;
  259.                         qualifier = PrintfQualifierLongLong;
  260.                     }
  261.                     break;
  262.                 case 'z':   /* size_t */
  263.                     qualifier = PrintfQualifierSizeT;
  264.                     break;
  265.                 default:
  266.                     qualifier = PrintfQualifierInt; /* default type */
  267.                     --i;
  268.             }  
  269.            
  270.             base = 10;
  271.  
  272.             switch (c = fmt[i]) {
  273.  
  274.                 /*
  275.                 * String and character conversions.
  276.                 */
  277.                 case 's':
  278.                     if ((retval = putstr(va_arg(ap, char*))) == EOF) {
  279.                         return -counter;
  280.                     };
  281.                    
  282.                     counter += retval;
  283.                     j = i + 1;
  284.                     goto next_char;
  285.                 case 'c':
  286.                     c = va_arg(ap, unsigned long);
  287.                     if ((retval = putnchars(&c, sizeof(char))) == EOF) {
  288.                         return -counter;
  289.                     };
  290.                    
  291.                     counter += retval;
  292.                     j = i + 1;
  293.                     goto next_char;
  294.  
  295.                 /*
  296.                  * Integer values
  297.                 */
  298.                 case 'P': /* pointer */
  299.                         flags |= __PRINTF_FLAG_BIGCHARS;
  300.                 case 'p':
  301.                     flags |= __PRINTF_FLAG_PREFIX;
  302.                     base = 16;
  303.                     qualifier = PrintfQualifierPointer;
  304.                     break; 
  305.                 case 'b':
  306.                     base = 2;
  307.                     break;
  308.                 case 'o':
  309.                     base = 8;
  310.                     break;
  311.                 case 'd':
  312.                 case 'i':
  313.                     flags |= __PRINTF_FLAG_SIGNED;  
  314.                 case 'u':
  315.                     break;
  316.                 case 'X':
  317.                     flags |= __PRINTF_FLAG_BIGCHARS;
  318.                 case 'x':
  319.                     base = 16;
  320.                     break;
  321.                 /* percentile itself */
  322.                 case '%':
  323.                     j = i;
  324.                     goto next_char;
  325.                 /*
  326.                 * Bad formatting.
  327.                 */
  328.                 default:
  329.                     /* Unknown format
  330.                      *  now, the j is index of '%' so we will
  331.                      * print whole bad format sequence
  332.                      */
  333.                     goto next_char;    
  334.             }
  335.        
  336.        
  337.         /* Print integers */
  338.             /* print number */
  339.             switch (qualifier) {
  340.                 case PrintfQualifierByte:
  341.                     size = sizeof(unsigned char);
  342.                     number = (uint64_t)va_arg(ap, unsigned int);
  343.                     break;
  344.                 case PrintfQualifierShort:
  345.                     size = sizeof(unsigned short);
  346.                     number = (uint64_t)va_arg(ap, unsigned int);
  347.                     break;
  348.                 case PrintfQualifierInt:
  349.                     size = sizeof(unsigned int);
  350.                     number = (uint64_t)va_arg(ap, unsigned int);
  351.                     break;
  352.                 case PrintfQualifierLong:
  353.                     size = sizeof(unsigned long);
  354.                     number = (uint64_t)va_arg(ap, unsigned long);
  355.                     break;
  356.                 case PrintfQualifierLongLong:
  357.                     size = sizeof(unsigned long long);
  358.                     number = (uint64_t)va_arg(ap, unsigned long long);
  359.                     break;
  360.                 case PrintfQualifierPointer:
  361.                     size = sizeof(void *);
  362.                     number = (uint64_t)(unsigned long)va_arg(ap, void *);
  363.                     break;
  364.                 case PrintfQualifierSizeT:
  365.                     size = sizeof(size_t);
  366.                     number = (uint64_t)va_arg(ap, size_t);
  367.                     break;
  368.                 default: /* Unknown qualifier */
  369.                     return -counter;
  370.                    
  371.             }
  372.            
  373.             if (flags & __PRINTF_FLAG_SIGNED) {
  374.                 if (number & (0x1 << (size*8 - 1))) {
  375.                     flags |= __PRINTF_FLAG_NEGATIVE;
  376.                
  377.                     if (size == sizeof(uint64_t)) {
  378.                         number = -((int64_t)number);
  379.                     } else {
  380.                         number = ~number;
  381.                         number &= (~((0xFFFFFFFFFFFFFFFFll) <<  (size * 8)));
  382.                         number++;
  383.                     }
  384.                 }
  385.             }
  386.  
  387.             if ((retval = print_number(number, size, base, flags)) == EOF ) {
  388.                 return -counter;
  389.             };
  390.  
  391.             counter += retval;
  392.             j = i + 1;
  393.         }  
  394. next_char:
  395.            
  396.         ++i;
  397.     }
  398.    
  399.     if (i > j) {
  400.         if ((retval = putnchars(&fmt[j], (size_t)(i - j))) == EOF) { /* error */
  401.             return -counter;
  402.         }
  403.         counter += retval;
  404.     }
  405.    
  406.     va_end(ap);
  407.     return counter;
  408. }
  409.  
  410.