Subversion Repositories HelenOS

Rev

Rev 4244 | Rev 4556 | 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.  * Copyright (c) 2009 Martin Decky
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * - Redistributions of source code must retain the above copyright
  12.  *   notice, this list of conditions and the following disclaimer.
  13.  * - Redistributions in binary form must reproduce the above copyright
  14.  *   notice, this list of conditions and the following disclaimer in the
  15.  *   documentation and/or other materials provided with the distribution.
  16.  * - The name of the author may not be used to endorse or promote products
  17.  *   derived from this software without specific prior written permission.
  18.  *
  19.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  20.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  21.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  23.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  28.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29.  */
  30.  
  31. /** @addtogroup generic
  32.  * @{
  33.  */
  34. /**
  35.  * @file
  36.  * @brief Printing functions.
  37.  */
  38.  
  39. #include <printf/printf_core.h>
  40. #include <print.h>
  41. #include <arch/arg.h>
  42. #include <macros.h>
  43. #include <string.h>
  44. #include <arch.h>
  45.  
  46. /** show prefixes 0x or 0 */
  47. #define __PRINTF_FLAG_PREFIX       0x00000001
  48. /** signed / unsigned number */
  49. #define __PRINTF_FLAG_SIGNED       0x00000002
  50. /** print leading zeroes */
  51. #define __PRINTF_FLAG_ZEROPADDED   0x00000004
  52. /** align to left */
  53. #define __PRINTF_FLAG_LEFTALIGNED  0x00000010
  54. /** always show + sign */
  55. #define __PRINTF_FLAG_SHOWPLUS     0x00000020
  56. /** print space instead of plus */
  57. #define __PRINTF_FLAG_SPACESIGN    0x00000040
  58. /** show big characters */
  59. #define __PRINTF_FLAG_BIGCHARS     0x00000080
  60. /** number has - sign */
  61. #define __PRINTF_FLAG_NEGATIVE     0x00000100
  62.  
  63. /**
  64.  * Buffer big enough for 64-bit number printed in base 2, sign, prefix and 0
  65.  * to terminate string... (last one is only for better testing end of buffer by
  66.  * zero-filling subroutine)
  67.  */
  68. #define PRINT_NUMBER_BUFFER_SIZE  (64 + 5)
  69.  
  70. /** Enumeration of possible arguments types.
  71.  */
  72. typedef enum {
  73.     PrintfQualifierByte = 0,
  74.     PrintfQualifierShort,
  75.     PrintfQualifierInt,
  76.     PrintfQualifierLong,
  77.     PrintfQualifierLongLong,
  78.     PrintfQualifierPointer
  79. } qualifier_t;
  80.  
  81. static char nullstr[] = "(NULL)";
  82. static char digits_small[] = "0123456789abcdef";
  83. static char digits_big[] = "0123456789ABCDEF";
  84. static char invalch = U_SPECIAL;
  85.  
  86. /** Print one or more characters without adding newline.
  87.  *
  88.  * @param buf  Buffer holding characters with size of
  89.  *             at least size bytes. NULL is not allowed!
  90.  * @param size Size of the buffer in bytes.
  91.  * @param ps   Output method and its data.
  92.  *
  93.  * @return Number of characters printed.
  94.  *
  95.  */
  96. static int printf_putnchars(const char *buf, size_t size,
  97.     printf_spec_t *ps)
  98. {
  99.     return ps->str_write((void *) buf, size, ps->data);
  100. }
  101.  
  102. /** Print one or more wide characters without adding newline.
  103.  *
  104.  * @param buf  Buffer holding wide characters with size of
  105.  *             at least size bytes. NULL is not allowed!
  106.  * @param size Size of the buffer in bytes.
  107.  * @param ps   Output method and its data.
  108.  *
  109.  * @return Number of wide characters printed.
  110.  *
  111.  */
  112. static int printf_wputnchars(const wchar_t *buf, size_t size,
  113.     printf_spec_t *ps)
  114. {
  115.     return ps->wstr_write((void *) buf, size, ps->data);
  116. }
  117.  
  118. /** Print string without adding a newline.
  119.  *
  120.  * @param str String to print.
  121.  * @param ps  Write function specification and support data.
  122.  *
  123.  * @return Number of characters printed.
  124.  *
  125.  */
  126. static int printf_putstr(const char *str, printf_spec_t *ps)
  127. {
  128.     if (str == NULL)
  129.         return printf_putnchars(nullstr, str_size(nullstr), ps);
  130.    
  131.     return ps->str_write((void *) str, str_size(str), ps->data);
  132. }
  133.  
  134. /** Print one ASCII character.
  135.  *
  136.  * @param c  ASCII character to be printed.
  137.  * @param ps Output method.
  138.  *
  139.  * @return Number of characters printed.
  140.  *
  141.  */
  142. static int printf_putchar(const char ch, printf_spec_t *ps)
  143. {
  144.     if (!ascii_check(ch))
  145.         return ps->str_write((void *) &invalch, 1, ps->data);
  146.    
  147.     return ps->str_write(&ch, 1, ps->data);
  148. }
  149.  
  150. /** Print one wide character.
  151.  *
  152.  * @param c  Wide character to be printed.
  153.  * @param ps Output method.
  154.  *
  155.  * @return Number of characters printed.
  156.  *
  157.  */
  158. static int printf_putwchar(const wchar_t ch, printf_spec_t *ps)
  159. {
  160.     if (!chr_check(ch))
  161.         return ps->str_write((void *) &invalch, 1, ps->data);
  162.    
  163.     return ps->wstr_write(&ch, sizeof(wchar_t), ps->data);
  164. }
  165.  
  166. /** Print one formatted ASCII character.
  167.  *
  168.  * @param ch    Character to print.
  169.  * @param width Width modifier.
  170.  * @param flags Flags that change the way the character is printed.
  171.  *
  172.  * @return Number of characters printed, negative value on failure.
  173.  *
  174.  */
  175. static int print_char(const char ch, int width, uint32_t flags, printf_spec_t *ps)
  176. {
  177.     size_t counter = 0;
  178.     if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
  179.         while (--width > 0) {
  180.             /*
  181.              * One space is consumed by the character itself, hence
  182.              * the predecrement.
  183.              */
  184.             if (printf_putchar(' ', ps) > 0)
  185.                 counter++;
  186.         }
  187.     }
  188.    
  189.     if (printf_putchar(ch, ps) > 0)
  190.         counter++;
  191.    
  192.     while (--width > 0) {
  193.         /*
  194.          * One space is consumed by the character itself, hence
  195.          * the predecrement.
  196.          */
  197.         if (printf_putchar(' ', ps) > 0)
  198.             counter++;
  199.     }
  200.    
  201.     return (int) (counter + 1);
  202. }
  203.  
  204. /** Print one formatted wide character.
  205.  *
  206.  * @param ch    Character to print.
  207.  * @param width Width modifier.
  208.  * @param flags Flags that change the way the character is printed.
  209.  *
  210.  * @return Number of characters printed, negative value on failure.
  211.  *
  212.  */
  213. static int print_wchar(const wchar_t ch, int width, uint32_t flags, printf_spec_t *ps)
  214. {
  215.     size_t counter = 0;
  216.     if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
  217.         while (--width > 0) {
  218.             /*
  219.              * One space is consumed by the character itself, hence
  220.              * the predecrement.
  221.              */
  222.             if (printf_putchar(' ', ps) > 0)
  223.                 counter++;
  224.         }
  225.     }
  226.    
  227.     if (printf_putwchar(ch, ps) > 0)
  228.         counter++;
  229.    
  230.     while (--width > 0) {
  231.         /*
  232.          * One space is consumed by the character itself, hence
  233.          * the predecrement.
  234.          */
  235.         if (printf_putchar(' ', ps) > 0)
  236.             counter++;
  237.     }
  238.    
  239.     return (int) (counter + 1);
  240. }
  241.  
  242. /** Print string.
  243.  *
  244.  * @param str       String to be printed.
  245.  * @param width     Width modifier.
  246.  * @param precision Precision modifier.
  247.  * @param flags     Flags that modify the way the string is printed.
  248.  *
  249.  * @return Number of characters printed, negative value on failure.
  250.  */
  251. static int print_str(char *str, int width, unsigned int precision,
  252.     uint32_t flags, printf_spec_t *ps)
  253. {
  254.     if (str == NULL)
  255.         return printf_putstr(nullstr, ps);
  256.  
  257.     /* Print leading spaces. */
  258.     size_t strw = str_length(str);
  259.     if (precision == 0)
  260.         precision = strw;
  261.  
  262.     /* Left padding */
  263.     size_t counter = 0;
  264.     width -= precision;
  265.     if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
  266.         while (width-- > 0) {
  267.             if (printf_putchar(' ', ps) == 1)
  268.                 counter++;
  269.         }
  270.     }
  271.  
  272.     /* Part of @a str fitting into the alloted space. */
  273.     int retval;
  274.     size_t size = str_lsize(str, precision);
  275.     if ((retval = printf_putnchars(str, size, ps)) < 0)
  276.         return -counter;
  277.  
  278.     counter += retval;
  279.  
  280.     /* Right padding */
  281.     while (width-- > 0) {
  282.         if (printf_putchar(' ', ps) == 1)
  283.             counter++;
  284.     }
  285.  
  286.     return ((int) counter);
  287.  
  288. }
  289.  
  290. /** Print wide string.
  291.  *
  292.  * @param str       Wide string to be printed.
  293.  * @param width     Width modifier.
  294.  * @param precision Precision modifier.
  295.  * @param flags     Flags that modify the way the string is printed.
  296.  *
  297.  * @return Number of wide characters printed, negative value on failure.
  298.  */
  299. static int print_wstr(wchar_t *str, int width, unsigned int precision,
  300.     uint32_t flags, printf_spec_t *ps)
  301. {
  302.     if (str == NULL)
  303.         return printf_putstr(nullstr, ps);
  304.    
  305.     if (*str == U_BOM)
  306.         str++;
  307.    
  308.     /* Print leading spaces. */
  309.     size_t strw = wstr_length(str);
  310.     if (precision == 0)
  311.         precision = strw;
  312.    
  313.     /* Left padding */
  314.     size_t counter = 0;
  315.     width -= precision;
  316.     if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
  317.         while (width-- > 0) {
  318.             if (printf_putchar(' ', ps) == 1)
  319.                 counter++;
  320.         }
  321.     }
  322.    
  323.     /* Part of @a wstr fitting into the alloted space. */
  324.     int retval;
  325.     size_t size = wstr_lsize(str, precision);
  326.     if ((retval = printf_wputnchars(str, size, ps)) < 0)
  327.         return -counter;
  328.    
  329.     counter += retval;
  330.    
  331.     /* Right padding */
  332.     while (width-- > 0) {
  333.         if (printf_putchar(' ', ps) == 1)
  334.             counter++;
  335.     }
  336.  
  337.     return ((int) counter);
  338. }
  339.  
  340. /** Print a number in a given base.
  341.  *
  342.  * Print significant digits of a number in given base.
  343.  *
  344.  * @param num       Number to print.
  345.  * @param width     Width modifier.
  346.  * @param precision Precision modifier.
  347.  * @param base      Base to print the number in (must be between 2 and 16).
  348.  * @param flags     Flags that modify the way the number is printed.
  349.  *
  350.  * @return Number of characters printed.
  351.  *
  352.  */
  353. static int print_number(uint64_t num, int width, int precision, int base,
  354.     uint32_t flags, printf_spec_t *ps)
  355. {
  356.     char *digits;
  357.     if (flags & __PRINTF_FLAG_BIGCHARS)
  358.         digits = digits_big;
  359.     else
  360.         digits = digits_small;
  361.    
  362.     char data[PRINT_NUMBER_BUFFER_SIZE];
  363.     char *ptr = &data[PRINT_NUMBER_BUFFER_SIZE - 1];
  364.    
  365.     /* Size of number with all prefixes and signs */
  366.     int size = 0;
  367.    
  368.     /* Put zero at end of string */
  369.     *ptr-- = 0;
  370.    
  371.     if (num == 0) {
  372.         *ptr-- = '0';
  373.         size++;
  374.     } else {
  375.         do {
  376.             *ptr-- = digits[num % base];
  377.             size++;
  378.         } while (num /= base);
  379.     }
  380.    
  381.     /* Size of plain number */
  382.     int number_size = size;
  383.    
  384.     /*
  385.      * Collect the sum of all prefixes/signs/etc. to calculate padding and
  386.      * leading zeroes.
  387.      */
  388.     if (flags & __PRINTF_FLAG_PREFIX) {
  389.         switch(base) {
  390.         case 2:
  391.             /* Binary formating is not standard, but usefull */
  392.             size += 2;
  393.             break;
  394.         case 8:
  395.             size++;
  396.             break;
  397.         case 16:
  398.             size += 2;
  399.             break;
  400.         }
  401.     }
  402.    
  403.     char sgn = 0;
  404.     if (flags & __PRINTF_FLAG_SIGNED) {
  405.         if (flags & __PRINTF_FLAG_NEGATIVE) {
  406.             sgn = '-';
  407.             size++;
  408.         } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
  409.             sgn = '+';
  410.             size++;
  411.         } else if (flags & __PRINTF_FLAG_SPACESIGN) {
  412.             sgn = ' ';
  413.             size++;
  414.         }
  415.     }
  416.    
  417.     if (flags & __PRINTF_FLAG_LEFTALIGNED)
  418.         flags &= ~__PRINTF_FLAG_ZEROPADDED;
  419.    
  420.     /*
  421.      * If the number is left-aligned or precision is specified then
  422.      * padding with zeros is ignored.
  423.      */
  424.     if (flags & __PRINTF_FLAG_ZEROPADDED) {
  425.         if ((precision == 0) && (width > size))
  426.             precision = width - size + number_size;
  427.     }
  428.    
  429.     /* Print leading spaces */
  430.     if (number_size > precision) {
  431.         /* Print the whole number, not only a part */
  432.         precision = number_size;
  433.     }
  434.    
  435.     width -= precision + size - number_size;
  436.     size_t counter = 0;
  437.    
  438.     if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
  439.         while (width-- > 0) {
  440.             if (printf_putchar(' ', ps) == 1)
  441.                 counter++;
  442.         }
  443.     }
  444.    
  445.     /* Print sign */
  446.     if (sgn) {
  447.         if (printf_putchar(sgn, ps) == 1)
  448.             counter++;
  449.     }
  450.    
  451.     /* Print prefix */
  452.     if (flags & __PRINTF_FLAG_PREFIX) {
  453.         switch(base) {
  454.         case 2:
  455.             /* Binary formating is not standard, but usefull */
  456.             if (printf_putchar('0', ps) == 1)
  457.                 counter++;
  458.             if (flags & __PRINTF_FLAG_BIGCHARS) {
  459.                 if (printf_putchar('B', ps) == 1)
  460.                     counter++;
  461.             } else {
  462.                 if (printf_putchar('b', ps) == 1)
  463.                     counter++;
  464.             }
  465.             break;
  466.         case 8:
  467.             if (printf_putchar('o', ps) == 1)
  468.                 counter++;
  469.             break;
  470.         case 16:
  471.             if (printf_putchar('0', ps) == 1)
  472.                 counter++;
  473.             if (flags & __PRINTF_FLAG_BIGCHARS) {
  474.                 if (printf_putchar('X', ps) == 1)
  475.                     counter++;
  476.             } else {
  477.                 if (printf_putchar('x', ps) == 1)
  478.                     counter++;
  479.             }
  480.             break;
  481.         }
  482.     }
  483.    
  484.     /* Print leading zeroes */
  485.     precision -= number_size;
  486.     while (precision-- > 0) {
  487.         if (printf_putchar('0', ps) == 1)
  488.             counter++;
  489.     }
  490.    
  491.     /* Print the number itself */
  492.     int retval;
  493.     if ((retval = printf_putstr(++ptr, ps)) > 0)
  494.         counter += retval;
  495.    
  496.     /* Print tailing spaces */
  497.    
  498.     while (width-- > 0) {
  499.         if (printf_putchar(' ', ps) == 1)
  500.             counter++;
  501.     }
  502.    
  503.     return ((int) counter);
  504. }
  505.  
  506. /** Print formatted string.
  507.  *
  508.  * Print string formatted according to the fmt parameter and variadic arguments.
  509.  * Each formatting directive must have the following form:
  510.  *
  511.  *  \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
  512.  *
  513.  * FLAGS:@n
  514.  *  - "#" Force to print prefix. For \%o conversion, the prefix is 0, for
  515.  *        \%x and \%X prefixes are 0x and 0X and for conversion \%b the
  516.  *        prefix is 0b.
  517.  *
  518.  *  - "-" Align to left.
  519.  *
  520.  *  - "+" Print positive sign just as negative.
  521.  *
  522.  *  - " " If the printed number is positive and "+" flag is not set,
  523.  *        print space in place of sign.
  524.  *
  525.  *  - "0" Print 0 as padding instead of spaces. Zeroes are placed between
  526.  *        sign and the rest of the number. This flag is ignored if "-"
  527.  *        flag is specified.
  528.  *
  529.  * WIDTH:@n
  530.  *  - Specify the minimal width of a printed argument. If it is bigger,
  531.  *    width is ignored. If width is specified with a "*" character instead of
  532.  *    number, width is taken from parameter list. And integer parameter is
  533.  *    expected before parameter for processed conversion specification. If
  534.  *    this value is negative its absolute value is taken and the "-" flag is
  535.  *    set.
  536.  *
  537.  * PRECISION:@n
  538.  *  - Value precision. For numbers it specifies minimum valid numbers.
  539.  *    Smaller numbers are printed with leading zeroes. Bigger numbers are not
  540.  *    affected. Strings with more than precision characters are cut off. Just
  541.  *    as with width, an "*" can be used used instead of a number. An integer
  542.  *    value is then expected in parameters. When both width and precision are
  543.  *    specified using "*", the first parameter is used for width and the
  544.  *    second one for precision.
  545.  *
  546.  * TYPE:@n
  547.  *  - "hh" Signed or unsigned char.@n
  548.  *  - "h"  Signed or unsigned short.@n
  549.  *  - ""   Signed or unsigned int (default value).@n
  550.  *  - "l"  Signed or unsigned long int.@n
  551.  *         If conversion is "c", the character is wchar_t (wide character).@n
  552.  *         If conversion is "s", the string is wchar_t * (wide string).@n
  553.  *  - "ll" Signed or unsigned long long int.@n
  554.  *
  555.  * CONVERSION:@n
  556.  *  - % Print percentile character itself.
  557.  *
  558.  *  - c Print single character. The character is expected to be plain
  559.  *      ASCII (e.g. only values 0 .. 127 are valid).@n
  560.  *      If type is "l", then the character is expected to be wide character
  561.  *      (e.g. values 0 .. 0x10ffff are valid).
  562.  *
  563.  *  - s Print zero terminated string. If a NULL value is passed as
  564.  *      value, "(NULL)" is printed instead.@n
  565.  *      If type is "l", then the string is expected to be wide string.
  566.  *
  567.  *  - P, p Print value of a pointer. Void * value is expected and it is
  568.  *         printed in hexadecimal notation with prefix (as with \%#X / \%#x
  569.  *         for 32-bit or \%#X / \%#x for 64-bit long pointers).
  570.  *
  571.  *  - b Print value as unsigned binary number. Prefix is not printed by
  572.  *      default. (Nonstandard extension.)
  573.  *
  574.  *  - o Print value as unsigned octal number. Prefix is not printed by
  575.  *      default.
  576.  *
  577.  *  - d, i Print signed decimal number. There is no difference between d
  578.  *         and i conversion.
  579.  *
  580.  *  - u Print unsigned decimal number.
  581.  *
  582.  *  - X, x Print hexadecimal number with upper- or lower-case. Prefix is
  583.  *         not printed by default.
  584.  *
  585.  * All other characters from fmt except the formatting directives are printed
  586.  * verbatim.
  587.  *
  588.  * @param fmt Format NULL-terminated string.
  589.  *
  590.  * @return Number of characters printed, negative value on failure.
  591.  *
  592.  */
  593. int printf_core(const char *fmt, printf_spec_t *ps, va_list ap)
  594. {
  595.     size_t i;        /* Index of the currently processed character from fmt */
  596.     size_t nxt = 0;  /* Index of the next character from fmt */
  597.     size_t j = 0;    /* Index to the first not printed nonformating character */
  598.    
  599.     size_t counter = 0;   /* Number of characters printed */
  600.     int retval;           /* Return values from nested functions */
  601.    
  602.     while (true) {
  603.         i = nxt;
  604.         wchar_t uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
  605.        
  606.         if (uc == 0)
  607.             break;
  608.        
  609.         /* Control character */
  610.         if (uc == '%') {
  611.             /* Print common characters if any processed */
  612.             if (i > j) {
  613.                 if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
  614.                     /* Error */
  615.                     counter = -counter;
  616.                     goto out;
  617.                 }
  618.                 counter += retval;
  619.             }
  620.            
  621.             j = i;
  622.            
  623.             /* Parse modifiers */
  624.             uint32_t flags = 0;
  625.             bool end = false;
  626.            
  627.             do {
  628.                 i = nxt;
  629.                 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
  630.                 switch (uc) {
  631.                 case '#':
  632.                     flags |= __PRINTF_FLAG_PREFIX;
  633.                     break;
  634.                 case '-':
  635.                     flags |= __PRINTF_FLAG_LEFTALIGNED;
  636.                     break;
  637.                 case '+':
  638.                     flags |= __PRINTF_FLAG_SHOWPLUS;
  639.                     break;
  640.                 case ' ':
  641.                     flags |= __PRINTF_FLAG_SPACESIGN;
  642.                     break;
  643.                 case '0':
  644.                     flags |= __PRINTF_FLAG_ZEROPADDED;
  645.                     break;
  646.                 default:
  647.                     end = true;
  648.                 };
  649.             } while (!end);
  650.            
  651.             /* Width & '*' operator */
  652.             int width = 0;
  653.             if (isdigit(uc)) {
  654.                 while (true) {
  655.                     width *= 10;
  656.                     width += uc - '0';
  657.                    
  658.                     i = nxt;
  659.                     uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
  660.                     if (uc == 0)
  661.                         break;
  662.                     if (!isdigit(uc))
  663.                         break;
  664.                 }
  665.             } else if (uc == '*') {
  666.                 /* Get width value from argument list */
  667.                 i = nxt;
  668.                 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
  669.                 width = (int) va_arg(ap, int);
  670.                 if (width < 0) {
  671.                     /* Negative width sets '-' flag */
  672.                     width *= -1;
  673.                     flags |= __PRINTF_FLAG_LEFTALIGNED;
  674.                 }
  675.             }
  676.            
  677.             /* Precision and '*' operator */
  678.             int precision = 0;
  679.             if (uc == '.') {
  680.                 i = nxt;
  681.                 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
  682.                 if (isdigit(uc)) {
  683.                     while (true) {
  684.                         precision *= 10;
  685.                         precision += uc - '0';
  686.                        
  687.                         i = nxt;
  688.                         uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
  689.                         if (uc == 0)
  690.                             break;
  691.                         if (!isdigit(uc))
  692.                             break;
  693.                     }
  694.                 } else if (uc == '*') {
  695.                     /* Get precision value from the argument list */
  696.                     i = nxt;
  697.                     uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
  698.                     precision = (int) va_arg(ap, int);
  699.                     if (precision < 0) {
  700.                         /* Ignore negative precision */
  701.                         precision = 0;
  702.                     }
  703.                 }
  704.             }
  705.            
  706.             qualifier_t qualifier;
  707.            
  708.             switch (uc) {
  709.             /** @todo Unimplemented qualifiers:
  710.              *        t ptrdiff_t - ISO C 99
  711.              */
  712.             case 'h':
  713.                 /* Char or short */
  714.                 qualifier = PrintfQualifierShort;
  715.                 i = nxt;
  716.                 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
  717.                 if (uc == 'h') {
  718.                     i = nxt;
  719.                     uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
  720.                     qualifier = PrintfQualifierByte;
  721.                 }
  722.                 break;
  723.             case 'l':
  724.                 /* Long or long long */
  725.                 qualifier = PrintfQualifierLong;
  726.                 i = nxt;
  727.                 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
  728.                 if (uc == 'l') {
  729.                     i = nxt;
  730.                     uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
  731.                     qualifier = PrintfQualifierLongLong;
  732.                 }
  733.                 break;
  734.             default:
  735.                 /* Default type */
  736.                 qualifier = PrintfQualifierInt;
  737.             }
  738.            
  739.             unsigned int base = 10;
  740.            
  741.             switch (uc) {
  742.             /*
  743.              * String and character conversions.
  744.              */
  745.             case 's':
  746.                 if (qualifier == PrintfQualifierLong)
  747.                     retval = print_wstr(va_arg(ap, wchar_t *), width, precision, flags, ps);
  748.                 else
  749.                     retval = print_str(va_arg(ap, char *), width, precision, flags, ps);
  750.                
  751.                 if (retval < 0) {
  752.                     counter = -counter;
  753.                     goto out;
  754.                 }
  755.                
  756.                 counter += retval;
  757.                 j = nxt;
  758.                 goto next_char;
  759.             case 'c':
  760.                 if (qualifier == PrintfQualifierLong)
  761.                     retval = print_wchar(va_arg(ap, wchar_t), width, flags, ps);
  762.                 else
  763.                     retval = print_char(va_arg(ap, unsigned int), width, flags, ps);
  764.                
  765.                 if (retval < 0) {
  766.                     counter = -counter;
  767.                     goto out;
  768.                 };
  769.                
  770.                 counter += retval;
  771.                 j = nxt;
  772.                 goto next_char;
  773.            
  774.             /*
  775.              * Integer values
  776.              */
  777.             case 'P':
  778.                 /* Pointer */
  779.                 flags |= __PRINTF_FLAG_BIGCHARS;
  780.             case 'p':
  781.                 flags |= __PRINTF_FLAG_PREFIX;
  782.                 base = 16;
  783.                 qualifier = PrintfQualifierPointer;
  784.                 break;
  785.             case 'b':
  786.                 base = 2;
  787.                 break;
  788.             case 'o':
  789.                 base = 8;
  790.                 break;
  791.             case 'd':
  792.             case 'i':
  793.                 flags |= __PRINTF_FLAG_SIGNED;
  794.             case 'u':
  795.                 break;
  796.             case 'X':
  797.                 flags |= __PRINTF_FLAG_BIGCHARS;
  798.             case 'x':
  799.                 base = 16;
  800.                 break;
  801.            
  802.             /* Percentile itself */
  803.             case '%':
  804.                 j = i;
  805.                 goto next_char;
  806.            
  807.             /*
  808.              * Bad formatting.
  809.              */
  810.             default:
  811.                 /*
  812.                  * Unknown format. Now, j is the index of '%'
  813.                  * so we will print whole bad format sequence.
  814.                  */
  815.                 goto next_char;
  816.             }
  817.            
  818.             /* Print integers */
  819.             size_t size;
  820.             uint64_t number;
  821.             switch (qualifier) {
  822.             case PrintfQualifierByte:
  823.                 size = sizeof(unsigned char);
  824.                 number = (uint64_t) va_arg(ap, unsigned int);
  825.                 break;
  826.             case PrintfQualifierShort:
  827.                 size = sizeof(unsigned short);
  828.                 number = (uint64_t) va_arg(ap, unsigned int);
  829.                 break;
  830.             case PrintfQualifierInt:
  831.                 size = sizeof(unsigned int);
  832.                 number = (uint64_t) va_arg(ap, unsigned int);
  833.                 break;
  834.             case PrintfQualifierLong:
  835.                 size = sizeof(unsigned long);
  836.                 number = (uint64_t) va_arg(ap, unsigned long);
  837.                 break;
  838.             case PrintfQualifierLongLong:
  839.                 size = sizeof(unsigned long long);
  840.                 number = (uint64_t) va_arg(ap, unsigned long long);
  841.                 break;
  842.             case PrintfQualifierPointer:
  843.                 size = sizeof(void *);
  844.                 number = (uint64_t) (unsigned long) va_arg(ap, void *);
  845.                 break;
  846.             default:
  847.                 /* Unknown qualifier */
  848.                 counter = -counter;
  849.                 goto out;
  850.             }
  851.            
  852.             if (flags & __PRINTF_FLAG_SIGNED) {
  853.                 if (number & (0x1 << (size * 8 - 1))) {
  854.                     flags |= __PRINTF_FLAG_NEGATIVE;
  855.                    
  856.                     if (size == sizeof(uint64_t)) {
  857.                         number = -((int64_t) number);
  858.                     } else {
  859.                         number = ~number;
  860.                         number &=
  861.                             ~(0xFFFFFFFFFFFFFFFFll <<
  862.                             (size * 8));
  863.                         number++;
  864.                     }
  865.                 }
  866.             }
  867.            
  868.             if ((retval = print_number(number, width, precision,
  869.                 base, flags, ps)) < 0) {
  870.                 counter = -counter;
  871.                 goto out;
  872.             }
  873.            
  874.             counter += retval;
  875.             j = nxt;
  876.         }
  877. next_char:
  878.         ;
  879.     }
  880.    
  881.     if (i > j) {
  882.         if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
  883.             /* Error */
  884.             counter = -counter;
  885.             goto out;
  886.         }
  887.         counter += retval;
  888.     }
  889.    
  890. out:
  891.     return ((int) counter);
  892. }
  893.  
  894. /** @}
  895.  */
  896.