Subversion Repositories HelenOS

Rev

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