Subversion Repositories HelenOS

Rev

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