Subversion Repositories HelenOS

Rev

Rev 2441 | Rev 2572 | 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.     if ((retval = printf_putnchars(s, size < precision ? size : precision,
  201.         ps)) < 0) {
  202.         return -counter;
  203.     }
  204.     counter += retval; 
  205.  
  206.     while (width-- > 0) {
  207.         if (printf_putchar(' ', ps) == 1)  
  208.             ++counter;
  209.     }
  210.    
  211.     return counter;
  212. }
  213.  
  214.  
  215. /** Print number in given base
  216.  *
  217.  * Print significant digits of a number in given
  218.  * base.
  219.  *
  220.  * @param num  Number to print.
  221.  * @param width
  222.  * @param precision
  223.  * @param base Base to print the number in (should
  224.  *             be in range 2 .. 16).
  225.  * @param flags output modifiers
  226.  * @return number of written characters or EOF
  227.  *
  228.  */
  229. static int print_number(uint64_t num, int width, int precision, int base , uint64_t flags, struct printf_spec *ps)
  230. {
  231.     char *digits = digits_small;
  232.     char d[PRINT_NUMBER_BUFFER_SIZE];   /* this is good enough even for base == 2, prefix and sign */
  233.     char *ptr = &d[PRINT_NUMBER_BUFFER_SIZE - 1];
  234.     int size = 0; /* size of number with all prefixes and signs */
  235.     int number_size; /* size of plain number */
  236.     char sgn;
  237.     int retval;
  238.     int counter = 0;
  239.    
  240.     if (flags & __PRINTF_FLAG_BIGCHARS)
  241.         digits = digits_big;   
  242.    
  243.     *ptr-- = 0; /* Put zero at end of string */
  244.  
  245.     if (num == 0) {
  246.         *ptr-- = '0';
  247.         size++;
  248.     } else {
  249.         do {
  250.             *ptr-- = digits[num % base];
  251.             size++;
  252.         } while (num /= base);
  253.     }
  254.    
  255.     number_size = size;
  256.  
  257.     /* Collect sum of all prefixes/signs/... to calculate padding and leading zeroes */
  258.     if (flags & __PRINTF_FLAG_PREFIX) {
  259.         switch(base) {
  260.         case 2: /* Binary formating is not standard, but usefull */
  261.             size += 2;
  262.             break;
  263.         case 8:
  264.             size++;
  265.             break;
  266.         case 16:
  267.             size += 2;
  268.             break;
  269.         }
  270.     }
  271.  
  272.     sgn = 0;
  273.     if (flags & __PRINTF_FLAG_SIGNED) {
  274.         if (flags & __PRINTF_FLAG_NEGATIVE) {
  275.             sgn = '-';
  276.             size++;
  277.         } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
  278.                 sgn = '+';
  279.                 size++;
  280.             } else if (flags & __PRINTF_FLAG_SPACESIGN) {
  281.                     sgn = ' ';
  282.                     size++;
  283.                 }
  284.     }
  285.  
  286.     if (flags & __PRINTF_FLAG_LEFTALIGNED) {
  287.         flags &= ~__PRINTF_FLAG_ZEROPADDED;
  288.     }
  289.  
  290.     /* if number is leftaligned or precision is specified then zeropadding is ignored */
  291.     if (flags & __PRINTF_FLAG_ZEROPADDED) {
  292.         if ((precision == 0) && (width > size)) {
  293.             precision = width - size + number_size;
  294.         }
  295.     }
  296.  
  297.     /* print leading spaces */
  298.     if (number_size > precision) /* We must print whole number not only a part */
  299.         precision = number_size;
  300.  
  301.     width -= precision + size - number_size;
  302.    
  303.     if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
  304.         while (width-- > 0) {  
  305.             if (printf_putchar(' ', ps) == 1)  
  306.                 counter++;
  307.         }
  308.     }
  309.    
  310.    
  311.     /* print sign */
  312.     if (sgn) {
  313.         if (printf_putchar(sgn, ps) == 1)
  314.             counter++;
  315.     }
  316.    
  317.     /* print prefix */
  318.    
  319.     if (flags & __PRINTF_FLAG_PREFIX) {
  320.         switch(base) {
  321.         case 2: /* Binary formating is not standard, but usefull */
  322.             if (printf_putchar('0', ps) == 1)
  323.                 counter++;
  324.             if (flags & __PRINTF_FLAG_BIGCHARS) {
  325.                 if (printf_putchar('B', ps) == 1)
  326.                     counter++;
  327.             } else {
  328.                 if (printf_putchar('b', ps) == 1)
  329.                     counter++;
  330.             }
  331.             break;
  332.         case 8:
  333.             if (printf_putchar('o', ps) == 1)
  334.                 counter++;
  335.             break;
  336.         case 16:
  337.             if (printf_putchar('0', ps) == 1)
  338.                 counter++;
  339.             if (flags & __PRINTF_FLAG_BIGCHARS) {
  340.                 if (printf_putchar('X', ps) == 1)
  341.                     counter++;
  342.             } else {
  343.                 if (printf_putchar('x', ps) == 1)
  344.                     counter++;
  345.             }
  346.             break;
  347.         }
  348.     }
  349.  
  350.     /* print leading zeroes */
  351.     precision -= number_size;
  352.     while (precision-- > 0) {  
  353.         if (printf_putchar('0', ps) == 1)
  354.             counter++;
  355.     }
  356.  
  357.    
  358.     /* print number itself */
  359.  
  360.     if ((retval = printf_putstr(++ptr, ps)) > 0) {
  361.         counter += retval;
  362.     }
  363.    
  364.     /* print ending spaces */
  365.    
  366.     while (width-- > 0) {  
  367.         if (printf_putchar(' ', ps) == 1)  
  368.             counter++;
  369.     }
  370.  
  371.     return counter;
  372. }
  373.  
  374.  
  375. /** Print formatted string.
  376.  *
  377.  * Print string formatted according to the fmt parameter
  378.  * and variadic arguments. Each formatting directive
  379.  * must have the following form:
  380.  *
  381.  *  \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
  382.  *
  383.  * FLAGS:@n
  384.  *  - "#" Force to print prefix.
  385.  *  For conversion \%o the prefix is 0, for \%x and \%X prefixes are 0x and 0X
  386.  *  and for conversion \%b the prefix is 0b.
  387.  *
  388.  *  - "-"   Align to left.
  389.  *
  390.  *  - "+"   Print positive sign just as negative.
  391.  *
  392.  *  - " "   If the printed number is positive and "+" flag is not set, print space in
  393.  *  place of sign.
  394.  *
  395.  *  - "0"   Print 0 as padding instead of spaces. Zeroes are placed between sign and the
  396.  *  rest of the number. This flag is ignored if "-" flag is specified.
  397.  *
  398.  * WIDTH:@n
  399.  *  - Specify minimal width of printed argument. If it is bigger, width is ignored.
  400.  * If width is specified with a "*" character instead of number, width is taken from
  401.  * parameter list. And integer parameter is expected before parameter for processed
  402.  * conversion specification. If this value is negative its absolute value is taken
  403.  * and the "-" flag is set.
  404.  *
  405.  * PRECISION:@n
  406.  *  - Value precision. For numbers it specifies minimum valid numbers.
  407.  * Smaller numbers are printed with leading zeroes. Bigger numbers are not affected.
  408.  * Strings with more than precision characters are cut off.
  409.  * Just as with width, an "*" can be used used instead of a number.
  410.  * An integer value is then expected in parameters. When both width and precision
  411.  * are specified using "*", the first parameter is used for width and the second one
  412.  * for precision.
  413.  *
  414.  * TYPE:@n
  415.  *  - "hh"  Signed or unsigned char.@n
  416.  *  - "h"   Signed or unsigned short.@n
  417.  *  - ""    Signed or unsigned int (default value).@n
  418.  *  - "l"   Signed or unsigned long int.@n
  419.  *  - "ll"  Signed or unsigned long long int.@n
  420.  *  - "z"   unative_t (non-standard extension).@n
  421.  *
  422.  *
  423.  * CONVERSION:@n
  424.  *  - % Print percentile character itself.
  425.  *
  426.  *  - c Print single character.
  427.  *
  428.  *  - s Print zero terminated string. If a NULL value is passed as value, "(NULL)" is printed instead.
  429.  *
  430.  *  - P, p  Print value of a pointer. Void * value is expected and it is printed in hexadecimal notation with prefix
  431.  *  (as with \%#X / \%#x for 32bit or \%#X / \%#x for 64bit long pointers).
  432.  *
  433.  *  - b Print value as unsigned binary number. Prefix is not printed by default. (Nonstandard extension.)
  434.  *
  435.  *  - o Print value as unsigned octal number. Prefix is not printed by default.
  436.  *
  437.  *  - d,i   Print signed decimal number. There is no difference between d and i conversion.
  438.  *
  439.  *  - u Print unsigned decimal number.
  440.  *
  441.  *  - X, x  Print hexadecimal number with upper- or lower-case. Prefix is not printed by default.
  442.  *
  443.  * All other characters from fmt except the formatting directives
  444.  * are printed in verbatim.
  445.  *
  446.  * @param fmt Formatting NULL terminated string.
  447.  * @return Number of printed characters or negative value on failure.
  448.  */
  449. int printf_core(const char *fmt, struct printf_spec *ps, va_list ap)
  450. {
  451.     int i = 0, j = 0; /**< i is index of currently processed char from fmt, j is index to the first not printed nonformating character */
  452.     int end;
  453.     int counter; /**< counter of printed characters */
  454.     int retval; /**< used to store return values from called functions */
  455.     char c;
  456.     qualifier_t qualifier;  /* type of argument */
  457.     int base;   /**< base in which will be parameter (numbers only) printed */
  458.     uint64_t number; /**< argument value */
  459.     size_t  size; /**< byte size of integer parameter */
  460.     int width, precision;
  461.     uint64_t flags;
  462.    
  463.     counter = 0;
  464.        
  465.     while ((c = fmt[i])) {
  466.         /* control character */
  467.         if (c == '%' ) {
  468.             /* print common characters if any processed */ 
  469.             if (i > j) {
  470.                 if ((retval = printf_putnchars(&fmt[j], (size_t)(i - j), ps)) < 0) { /* error */
  471.                     counter = -counter;
  472.                     goto out;
  473.                 }
  474.                 counter += retval;
  475.             }
  476.        
  477.             j = i;
  478.             /* parse modifiers */
  479.             flags = 0;
  480.             end = 0;
  481.            
  482.             do {
  483.                 ++i;
  484.                 switch (c = fmt[i]) {
  485.                 case '#': flags |= __PRINTF_FLAG_PREFIX; break;
  486.                 case '-': flags |= __PRINTF_FLAG_LEFTALIGNED; break;
  487.                 case '+': flags |= __PRINTF_FLAG_SHOWPLUS; break;
  488.                 case ' ': flags |= __PRINTF_FLAG_SPACESIGN; break;
  489.                 case '0': flags |= __PRINTF_FLAG_ZEROPADDED; break;
  490.                 default: end = 1;
  491.                 }; 
  492.                
  493.             } while (end == 0);
  494.            
  495.             /* width & '*' operator */
  496.             width = 0;
  497.             if (isdigit(fmt[i])) {
  498.                 while (isdigit(fmt[i])) {
  499.                     width *= 10;
  500.                     width += fmt[i++] - '0';
  501.                 }
  502.             } else if (fmt[i] == '*') {
  503.                 /* get width value from argument list*/
  504.                 i++;
  505.                 width = (int)va_arg(ap, int);
  506.                 if (width < 0) {
  507.                     /* negative width means to set '-' flag */
  508.                     width *= -1;
  509.                     flags |= __PRINTF_FLAG_LEFTALIGNED;
  510.                 }
  511.             }
  512.            
  513.             /* precision and '*' operator */   
  514.             precision = 0;
  515.             if (fmt[i] == '.') {
  516.                 ++i;
  517.                 if (isdigit(fmt[i])) {
  518.                     while (isdigit(fmt[i])) {
  519.                         precision *= 10;
  520.                         precision += fmt[i++] - '0';
  521.                     }
  522.                 } else if (fmt[i] == '*') {
  523.                     /* get precision value from argument list*/
  524.                     i++;
  525.                     precision = (int)va_arg(ap, int);
  526.                     if (precision < 0) {
  527.                         /* negative precision means to ignore it */
  528.                         precision = 0;
  529.                     }
  530.                 }
  531.             }
  532.  
  533.             switch (fmt[i++]) {
  534.             /** TODO: unimplemented qualifiers:
  535.              * t ptrdiff_t - ISO C 99
  536.              */
  537.             case 'h':   /* char or short */
  538.                 qualifier = PrintfQualifierShort;
  539.                 if (fmt[i] == 'h') {
  540.                     i++;
  541.                     qualifier = PrintfQualifierByte;
  542.                 }
  543.                 break;
  544.             case 'l':   /* long or long long*/
  545.                 qualifier = PrintfQualifierLong;
  546.                 if (fmt[i] == 'l') {
  547.                     i++;
  548.                     qualifier = PrintfQualifierLongLong;
  549.                 }
  550.                 break;
  551.             case 'z':   /* unative_t */
  552.                 qualifier = PrintfQualifierNative;
  553.                 break;
  554.             default:
  555.                 qualifier = PrintfQualifierInt; /* default type */
  556.                 --i;
  557.             }  
  558.            
  559.             base = 10;
  560.  
  561.             switch (c = fmt[i]) {
  562.  
  563.             /*
  564.             * String and character conversions.
  565.             */
  566.             case 's':
  567.                 if ((retval = print_string(va_arg(ap, char*), width, precision, flags, ps)) < 0) {
  568.                     counter = -counter;
  569.                     goto out;
  570.                 };
  571.  
  572.                 counter += retval;
  573.                 j = i + 1;
  574.                 goto next_char;
  575.             case 'c':
  576.                 c = va_arg(ap, unsigned int);
  577.                 if ((retval = print_char(c, width, flags, ps)) < 0) {
  578.                     counter = -counter;
  579.                     goto out;
  580.                 };
  581.                    
  582.                 counter += retval;
  583.                 j = i + 1;
  584.                 goto next_char;
  585.  
  586.             /*
  587.              * Integer values
  588.              */
  589.             case 'P': /* pointer */
  590.                     flags |= __PRINTF_FLAG_BIGCHARS;
  591.             case 'p':
  592.                 flags |= __PRINTF_FLAG_PREFIX;
  593.                 base = 16;
  594.                 qualifier = PrintfQualifierPointer;
  595.                 break; 
  596.             case 'b':
  597.                 base = 2;
  598.                 break;
  599.             case 'o':
  600.                 base = 8;
  601.                 break;
  602.             case 'd':
  603.             case 'i':
  604.                 flags |= __PRINTF_FLAG_SIGNED;  
  605.             case 'u':
  606.                 break;
  607.             case 'X':
  608.                 flags |= __PRINTF_FLAG_BIGCHARS;
  609.             case 'x':
  610.                 base = 16;
  611.                 break;
  612.             /* percentile itself */
  613.             case '%':
  614.                 j = i;
  615.                 goto next_char;
  616.             /*
  617.              * Bad formatting.
  618.              */
  619.             default:
  620.                 /* Unknown format
  621.                  * now, j is index of '%' so we will
  622.                  * print whole bad format sequence
  623.                  */
  624.                 goto next_char;    
  625.             }
  626.        
  627.        
  628.         /* Print integers */
  629.             /* print number */
  630.             switch (qualifier) {
  631.             case PrintfQualifierByte:
  632.                 size = sizeof(unsigned char);
  633.                 number = (uint64_t)va_arg(ap, unsigned int);
  634.                 break;
  635.             case PrintfQualifierShort:
  636.                 size = sizeof(unsigned short);
  637.                 number = (uint64_t)va_arg(ap, unsigned int);
  638.                 break;
  639.             case PrintfQualifierInt:
  640.                 size = sizeof(unsigned int);
  641.                 number = (uint64_t)va_arg(ap, unsigned int);
  642.                 break;
  643.             case PrintfQualifierLong:
  644.                 size = sizeof(unsigned long);
  645.                 number = (uint64_t)va_arg(ap, unsigned long);
  646.                 break;
  647.             case PrintfQualifierLongLong:
  648.                 size = sizeof(unsigned long long);
  649.                 number = (uint64_t)va_arg(ap, unsigned long long);
  650.                 break;
  651.             case PrintfQualifierPointer:
  652.                 size = sizeof(void *);
  653.                 number = (uint64_t)(unsigned long)va_arg(ap, void *);
  654.                 break;
  655.             case PrintfQualifierNative:
  656.                 size = sizeof(unative_t);
  657.                 number = (uint64_t)va_arg(ap, unative_t);
  658.                 break;
  659.             default: /* Unknown qualifier */
  660.                 counter = -counter;
  661.                 goto out;
  662.             }
  663.            
  664.             if (flags & __PRINTF_FLAG_SIGNED) {
  665.                 if (number & (0x1 << (size*8 - 1))) {
  666.                     flags |= __PRINTF_FLAG_NEGATIVE;
  667.                
  668.                     if (size == sizeof(uint64_t)) {
  669.                         number = -((int64_t)number);
  670.                     } else {
  671.                         number = ~number;
  672.                         number &= (~((0xFFFFFFFFFFFFFFFFll) <<  (size * 8)));
  673.                         number++;
  674.                     }
  675.                 }
  676.             }
  677.  
  678.             if ((retval = print_number(number, width, precision, base, flags, ps)) < 0) {
  679.                 counter = -counter;
  680.                 goto out;
  681.             };
  682.  
  683.             counter += retval;
  684.             j = i + 1;
  685.         }  
  686. next_char:
  687.            
  688.         ++i;
  689.     }
  690.    
  691.     if (i > j) {
  692.         if ((retval = printf_putnchars(&fmt[j], (unative_t)(i - j), ps)) < 0) { /* error */
  693.             counter = -counter;
  694.             goto out;
  695.            
  696.         }
  697.         counter += retval;
  698.     }
  699.  
  700. out:
  701.    
  702.     return counter;
  703. }
  704.  
  705. /** @}
  706.  */
  707.