Subversion Repositories HelenOS

Rev

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