Subversion Repositories HelenOS

Rev

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