Subversion Repositories HelenOS

Rev

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