Ignore:
Timestamp:
2009-04-04T22:04:28Z (15 years ago)
Author:
Jiri Svoboda <jirik.svoboda@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
b27eb71
Parents:
4527fb5
Message:

Copy printf with Unicode support to userspace.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/libc/generic/io/printf_core.c

    r4527fb5 rf2b8cdc  
    22 * Copyright (c) 2001-2004 Jakub Jermar
    33 * Copyright (c) 2006 Josef Cejka
     4 * Copyright (c) 2009 Martin Decky
    45 * All rights reserved.
    56 *
     
    2829 */
    2930
    30 /** @addtogroup libc
     31/** @addtogroup generic
    3132 * @{
    3233 */
    3334/**
    3435 * @file
    35  * @brief       Printing functions.
     36 * @brief Printing functions.
    3637 */
    3738
     
    4243#include <string.h>
    4344
    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                                                          */
     45/** show prefixes 0x or 0 */
     46#define __PRINTF_FLAG_PREFIX       0x00000001
     47/** signed / unsigned number */
     48#define __PRINTF_FLAG_SIGNED       0x00000002
     49/** print leading zeroes */
     50#define __PRINTF_FLAG_ZEROPADDED   0x00000004
     51/** align to left */
     52#define __PRINTF_FLAG_LEFTALIGNED  0x00000010
     53/** always show + sign */
     54#define __PRINTF_FLAG_SHOWPLUS     0x00000020
     55/** print space instead of plus */
     56#define __PRINTF_FLAG_SPACESIGN    0x00000040
     57/** show big characters */
     58#define __PRINTF_FLAG_BIGCHARS     0x00000080
     59/** number has - sign */
     60#define __PRINTF_FLAG_NEGATIVE     0x00000100
     61
     62/**
     63 * Buffer big enough for 64-bit number printed in base 2, sign, prefix and 0
     64 * to terminate string... (last one is only for better testing end of buffer by
     65 * zero-filling subroutine)
     66 */
     67#define PRINT_NUMBER_BUFFER_SIZE  (64 + 5)
     68
    5869/** Enumeration of possible arguments types.
    5970 */
     
    6475        PrintfQualifierLong,
    6576        PrintfQualifierLongLong,
    66         PrintfQualifierSizeT,
    6777        PrintfQualifierPointer
    6878} qualifier_t;
    6979
    70 static char digits_small[] = "0123456789abcdef";        /**< Small hexadecimal characters */
    71 static char digits_big[] = "0123456789ABCDEF";          /**< Big hexadecimal characters */
    72 
    73 /** Print count chars from buffer without adding newline
    74  * @param buf Buffer with size at least count bytes - NULL pointer NOT allowed!
    75  * @param count
    76  * @param ps output method and its data
    77  * @return number of printed characters
    78  */
    79 static int printf_putnchars(const char * buf, size_t count,
    80     struct printf_spec *ps)
    81 {
    82         return ps->write((void *)buf, count, ps->data);
    83 }
    84 
    85 /** Print string without added newline
    86  * @param str string to print
    87  * @param ps write function specification and support data
    88  * @return number of printed characters
    89  */
    90 static int printf_putstr(const char * str, struct printf_spec *ps)
    91 {
    92         size_t count;
    93        
     80static char nullstr[] = "(NULL)";
     81static char digits_small[] = "0123456789abcdef";
     82static char digits_big[] = "0123456789ABCDEF";
     83static char invalch = U_SPECIAL;
     84
     85/** Print one or more characters without adding newline.
     86 *
     87 * @param buf  Buffer holding characters with size of
     88 *             at least size bytes. NULL is not allowed!
     89 * @param size Size of the buffer in bytes.
     90 * @param ps   Output method and its data.
     91 *
     92 * @return Number of characters printed.
     93 *
     94 */
     95static int printf_putnchars(const char *buf, size_t size,
     96    printf_spec_t *ps)
     97{
     98        return ps->str_write((void *) buf, size, ps->data);
     99}
     100
     101/** Print one or more wide characters without adding newline.
     102 *
     103 * @param buf  Buffer holding wide characters with size of
     104 *             at least size bytes. NULL is not allowed!
     105 * @param size Size of the buffer in bytes.
     106 * @param ps   Output method and its data.
     107 *
     108 * @return Number of wide characters printed.
     109 *
     110 */
     111static int printf_wputnchars(const wchar_t *buf, size_t size,
     112    printf_spec_t *ps)
     113{
     114        return ps->wstr_write((void *) buf, size, ps->data);
     115}
     116
     117/** Print string without adding a newline.
     118 *
     119 * @param str String to print.
     120 * @param ps  Write function specification and support data.
     121 *
     122 * @return Number of characters printed.
     123 *
     124 */
     125static int printf_putstr(const char *str, printf_spec_t *ps)
     126{
    94127        if (str == NULL)
    95                 return printf_putnchars("(NULL)", 6, ps);
    96 
    97         count = strlen(str);
    98 
    99         return ps->write((void *) str, count, ps->data);
    100 }
    101 
    102 /** Print one character to output
    103  * @param c one character
    104  * @param ps output method
    105  * @return number of printed characters
    106  */
    107 static int printf_putchar(int c, struct printf_spec *ps)
    108 {
    109         unsigned char ch = c;
    110        
    111         return ps->write((void *) &ch, 1, ps->data);
    112 }
    113 
    114 /** Print one formatted character
    115  * @param c character to print
    116  * @param width
    117  * @param flags
    118  * @return number of printed characters
    119  */
    120 static int print_char(char c, int width, uint64_t flags, struct printf_spec *ps)
    121 {
    122         int counter = 0;
    123        
     128                return printf_putnchars(nullstr, str_size(nullstr), ps);
     129       
     130        return ps->str_write((void *) str, str_size(str), ps->data);
     131}
     132
     133/** Print one ASCII character.
     134 *
     135 * @param c  ASCII character to be printed.
     136 * @param ps Output method.
     137 *
     138 * @return Number of characters printed.
     139 *
     140 */
     141static int printf_putchar(const char ch, printf_spec_t *ps)
     142{
     143        if (!ascii_check(ch))
     144                return ps->str_write((void *) &invalch, 1, ps->data);
     145       
     146        return ps->str_write(&ch, 1, ps->data);
     147}
     148
     149/** Print one wide character.
     150 *
     151 * @param c  Wide character to be printed.
     152 * @param ps Output method.
     153 *
     154 * @return Number of characters printed.
     155 *
     156 */
     157static int printf_putwchar(const wchar_t ch, printf_spec_t *ps)
     158{
     159        if (!chr_check(ch))
     160                return ps->str_write((void *) &invalch, 1, ps->data);
     161       
     162        return ps->wstr_write(&ch, sizeof(wchar_t), ps->data);
     163}
     164
     165/** Print one formatted ASCII character.
     166 *
     167 * @param ch    Character to print.
     168 * @param width Width modifier.
     169 * @param flags Flags that change the way the character is printed.
     170 *
     171 * @return Number of characters printed, negative value on failure.
     172 *
     173 */
     174static int print_char(const char ch, int width, uint32_t flags, printf_spec_t *ps)
     175{
     176        count_t counter = 0;
    124177        if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
     178                while (--width > 0) {
     179                        /*
     180                         * One space is consumed by the character itself, hence
     181                         * the predecrement.
     182                         */
     183                        if (printf_putchar(' ', ps) > 0)
     184                                counter++;
     185                }
     186        }
     187       
     188        if (printf_putchar(ch, ps) > 0)
     189                counter++;
     190       
     191        while (--width > 0) {
    125192                /*
    126                  * One space is consumed by the character itself, hence the
    127                  * predecrement.
     193                 * One space is consumed by the character itself, hence
     194                 * the predecrement.
    128195                 */
     196                if (printf_putchar(' ', ps) > 0)
     197                        counter++;
     198        }
     199       
     200        return (int) (counter + 1);
     201}
     202
     203/** Print one formatted wide character.
     204 *
     205 * @param ch    Character to print.
     206 * @param width Width modifier.
     207 * @param flags Flags that change the way the character is printed.
     208 *
     209 * @return Number of characters printed, negative value on failure.
     210 *
     211 */
     212static int print_wchar(const wchar_t ch, int width, uint32_t flags, printf_spec_t *ps)
     213{
     214        count_t counter = 0;
     215        if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
    129216                while (--width > 0) {
    130                         if (printf_putchar(' ', ps) > 0)       
    131                                 ++counter;
    132                 }
    133         }
    134        
    135         if (printf_putchar(c, ps) > 0)
     217                        /*
     218                         * One space is consumed by the character itself, hence
     219                         * the predecrement.
     220                         */
     221                        if (printf_putchar(' ', ps) > 0)
     222                                counter++;
     223                }
     224        }
     225       
     226        if (printf_putwchar(ch, ps) > 0)
    136227                counter++;
    137         /*
    138          * One space is consumed by the character itself, hence the
    139          * predecrement.
    140          */
     228       
    141229        while (--width > 0) {
     230                /*
     231                 * One space is consumed by the character itself, hence
     232                 * the predecrement.
     233                 */
    142234                if (printf_putchar(' ', ps) > 0)
    143                         ++counter;
    144         }
    145        
    146         return ++counter;
    147 }
    148 
    149 /** Print one string
    150  * @param s string
    151  * @param width
    152  * @param precision
    153  * @param flags
    154  * @return number of printed characters
    155  */
    156 static int print_string(char *s, int width, int precision, uint64_t flags,
    157     struct printf_spec *ps)
    158 {
    159         int counter = 0;
    160         size_t size;
     235                        counter++;
     236        }
     237       
     238        return (int) (counter + 1);
     239}
     240
     241/** Print string.
     242 *
     243 * @param str       String to be printed.
     244 * @param width     Width modifier.
     245 * @param precision Precision modifier.
     246 * @param flags     Flags that modify the way the string is printed.
     247 *
     248 * @return Number of characters printed, negative value on failure.
     249 */
     250static int print_str(char *str, int width, unsigned int precision,
     251        uint32_t flags, printf_spec_t *ps)
     252{
     253        if (str == NULL)
     254                return printf_putstr(nullstr, ps);
     255
     256        /* Print leading spaces. */
     257        count_t strw = str_length(str);
     258        if (precision == 0)
     259                precision = strw;
     260
     261        /* Left padding */
     262        count_t counter = 0;
     263        width -= precision;
     264        if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
     265                while (width-- > 0) {
     266                        if (printf_putchar(' ', ps) == 1)
     267                                counter++;
     268                }
     269        }
     270
     271        /* Part of @a str fitting into the alloted space. */
    161272        int retval;
    162 
    163         if (s == NULL) {
    164                 return printf_putstr("(NULL)", ps);
    165         }
    166        
    167         size = strlen(s);
    168 
    169         /* print leading spaces */
    170 
    171         if (precision == 0)
    172                 precision = size;
    173 
     273        size_t size = str_lsize(str, precision);
     274        if ((retval = printf_putnchars(str, size, ps)) < 0)
     275                return -counter;
     276
     277        counter += retval;
     278
     279        /* Right padding */
     280        while (width-- > 0) {
     281                if (printf_putchar(' ', ps) == 1)
     282                        counter++;
     283        }
     284
     285        return ((int) counter);
     286
     287}
     288
     289/** Print wide string.
     290 *
     291 * @param str       Wide string to be printed.
     292 * @param width     Width modifier.
     293 * @param precision Precision modifier.
     294 * @param flags     Flags that modify the way the string is printed.
     295 *
     296 * @return Number of wide characters printed, negative value on failure.
     297 */
     298static int print_wstr(wchar_t *str, int width, unsigned int precision,
     299        uint32_t flags, printf_spec_t *ps)
     300{
     301        if (str == NULL)
     302                return printf_putstr(nullstr, ps);
     303
     304        /* Print leading spaces. */
     305        size_t strw = wstr_length(str);
     306        if (precision == 0)
     307                precision = strw;
     308
     309        /* Left padding */
     310        count_t counter = 0;
    174311        width -= precision;
    175        
    176312        if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
    177                 while (width-- > 0) {   
    178                         if (printf_putchar(' ', ps) == 1)       
     313                while (width-- > 0) {
     314                        if (printf_putchar(' ', ps) == 1)
    179315                                counter++;
    180316                }
    181317        }
    182318
    183         if ((retval = printf_putnchars(s, size < precision ? size : precision,
    184             ps)) < 0) {
     319        /* Part of @a wstr fitting into the alloted space. */
     320        int retval;
     321        size_t size = wstr_lsize(str, precision);
     322        if ((retval = printf_wputnchars(str, size, ps)) < 0)
    185323                return -counter;
    186         }
    187 
    188         counter += retval;     
    189 
     324
     325        counter += retval;
     326
     327        /* Right padding */
    190328        while (width-- > 0) {
    191                 if (printf_putchar(' ', ps) == 1)       
    192                         ++counter;
    193         }
    194        
    195         return counter;
    196 }
    197 
    198 
    199 /** Print number in given base
    200  *
    201  * Print significant digits of a number in given
    202  * base.
    203  *
    204  * @param num  Number to print.
    205  * @param width
    206  * @param precision
    207  * @param base Base to print the number in (should
    208  *             be in range 2 .. 16).
    209  * @param flags output modifiers
    210  * @return number of printed characters
     329                if (printf_putchar(' ', ps) == 1)
     330                        counter++;
     331        }
     332
     333        return ((int) counter);
     334}
     335
     336/** Print a number in a given base.
     337 *
     338 * Print significant digits of a number in given base.
     339 *
     340 * @param num       Number to print.
     341 * @param width     Width modifier.
     342 * @param precision Precision modifier.
     343 * @param base      Base to print the number in (must be between 2 and 16).
     344 * @param flags     Flags that modify the way the number is printed.
     345 *
     346 * @return Number of characters printed.
    211347 *
    212348 */
    213349static int print_number(uint64_t num, int width, int precision, int base,
    214     uint64_t flags, struct printf_spec *ps)
    215 {
    216         char *digits = digits_small;
    217         char d[PRINT_NUMBER_BUFFER_SIZE];       /* this is good enough even for
    218                                                  * base == 2, prefix and sign */
    219         char *ptr = &d[PRINT_NUMBER_BUFFER_SIZE - 1];
    220         int size = 0; /* size of number with all prefixes and signs */
    221         int number_size; /* size of plain number */
    222         char sgn;
    223         int retval;
    224         int counter = 0;
    225        
    226         if (flags & __PRINTF_FLAG_BIGCHARS)
    227                 digits = digits_big;   
    228        
    229         *ptr-- = 0; /* Put zero at end of string */
    230 
     350    uint32_t flags, printf_spec_t *ps)
     351{
     352        char *digits;
     353        if (flags & __PRINTF_FLAG_BIGCHARS)
     354                digits = digits_big;
     355        else
     356                digits = digits_small;
     357       
     358        char data[PRINT_NUMBER_BUFFER_SIZE];
     359        char *ptr = &data[PRINT_NUMBER_BUFFER_SIZE - 1];
     360       
     361        /* Size of number with all prefixes and signs */
     362        int size = 0;
     363       
     364        /* Put zero at end of string */
     365        *ptr-- = 0;
     366       
    231367        if (num == 0) {
    232368                *ptr-- = '0';
     
    239375        }
    240376       
    241         number_size = size;
    242 
     377        /* Size of plain number */
     378        int number_size = size;
     379       
    243380        /*
    244          * Collect sum of all prefixes/signs/... to calculate padding and
    245          * leading zeroes
     381         * Collect the sum of all prefixes/signs/etc. to calculate padding and
     382         * leading zeroes.
    246383         */
    247384        if (flags & __PRINTF_FLAG_PREFIX) {
    248385                switch(base) {
    249                 case 2: /* Binary formating is not standard, but usefull */
     386                case 2:
     387                        /* Binary formating is not standard, but usefull */
    250388                        size += 2;
    251389                        break;
     
    258396                }
    259397        }
    260 
    261         sgn = 0;
     398       
     399        char sgn = 0;
    262400        if (flags & __PRINTF_FLAG_SIGNED) {
    263401                if (flags & __PRINTF_FLAG_NEGATIVE) {
     
    272410                }
    273411        }
    274 
    275         if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     412       
     413        if (flags & __PRINTF_FLAG_LEFTALIGNED)
    276414                flags &= ~__PRINTF_FLAG_ZEROPADDED;
    277         }
    278 
     415       
    279416        /*
    280          * If number is leftaligned or precision is specified then zeropadding
    281          * is ignored.
     417         * If the number is left-aligned or precision is specified then
     418         * padding with zeros is ignored.
    282419         */
    283420        if (flags & __PRINTF_FLAG_ZEROPADDED) {
    284                 if ((precision == 0) && (width > size)) {
     421                if ((precision == 0) && (width > size))
    285422                        precision = width - size + number_size;
    286                 }
    287         }
    288 
    289         /* print leading spaces */
    290 
    291         /* We must print whole number not only a part. */
    292         if (number_size > precision)
     423        }
     424       
     425        /* Print leading spaces */
     426        if (number_size > precision) {
     427                /* Print the whole number, not only a part */
    293428                precision = number_size;
    294 
     429        }
     430       
    295431        width -= precision + size - number_size;
     432        count_t counter = 0;
    296433       
    297434        if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
    298                 while (width-- > 0) {   
    299                         if (printf_putchar(' ', ps) == 1)       
     435                while (width-- > 0) {
     436                        if (printf_putchar(' ', ps) == 1)
    300437                                counter++;
    301438                }
    302439        }
    303440       
    304         /* print sign */
     441        /* Print sign */
    305442        if (sgn) {
    306443                if (printf_putchar(sgn, ps) == 1)
     
    308445        }
    309446       
    310         /* print prefix */
    311        
     447        /* Print prefix */
    312448        if (flags & __PRINTF_FLAG_PREFIX) {
    313449                switch(base) {
    314                 case 2: /* Binary formating is not standard, but usefull */
     450                case 2:
     451                        /* Binary formating is not standard, but usefull */
    315452                        if (printf_putchar('0', ps) == 1)
    316453                                counter++;
     
    340477                }
    341478        }
    342 
    343         /* print leading zeroes */
     479       
     480        /* Print leading zeroes */
    344481        precision -= number_size;
    345         while (precision-- > 0) {       
     482        while (precision-- > 0) {
    346483                if (printf_putchar('0', ps) == 1)
    347484                        counter++;
    348485        }
    349 
    350        
    351         /* print number itself */
    352 
    353         if ((retval = printf_putstr(++ptr, ps)) > 0) {
     486       
     487        /* Print the number itself */
     488        int retval;
     489        if ((retval = printf_putstr(++ptr, ps)) > 0)
    354490                counter += retval;
    355         }
    356        
    357         /* print ending spaces */
    358        
    359         while (width-- > 0) {   
    360                 if (printf_putchar(' ', ps) == 1)       
     491       
     492        /* Print tailing spaces */
     493       
     494        while (width-- > 0) {
     495                if (printf_putchar(' ', ps) == 1)
    361496                        counter++;
    362497        }
    363 
    364         return counter;
    365 }
    366 
     498       
     499        return ((int) counter);
     500}
    367501
    368502/** Print formatted string.
     
    370504 * Print string formatted according to the fmt parameter and variadic arguments.
    371505 * Each formatting directive must have the following form:
    372  * 
    373  *      \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
     506 *
     507 *  \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
    374508 *
    375509 * FLAGS:@n
    376  *      - "#" Force to print prefix.
    377  *      For conversion \%o the prefix is 0, for %x and \%X prefixes are 0x and
    378  *      0X and for conversion \%b the prefix is 0b.
    379  *
    380  *      - "-"   Align to left.
    381  *
    382  *      - "+"   Print positive sign just as negative.
    383  *
    384  *      - " "   If the printed number is positive and "+" flag is not set,
    385  *              print space in place of sign.
    386  *
    387  *      - "0"   Print 0 as padding instead of spaces. Zeroes are placed between
    388  *              sign and the rest of the number. This flag is ignored if "-"
    389  *              flag is specified.
    390  * 
     510 *  - "#" Force to print prefix. For \%o conversion, the prefix is 0, for
     511 *        \%x and \%X prefixes are 0x and 0X and for conversion \%b the
     512 *        prefix is 0b.
     513 *
     514 *  - "-" Align to left.
     515 *
     516 *  - "+" Print positive sign just as negative.
     517 *
     518 *  - " " If the printed number is positive and "+" flag is not set,
     519 *        print space in place of sign.
     520 *
     521 *  - "0" Print 0 as padding instead of spaces. Zeroes are placed between
     522 *        sign and the rest of the number. This flag is ignored if "-"
     523 *        flag is specified.
     524 *
    391525 * WIDTH:@n
    392  *      - Specify minimal width of printed argument. If it is bigger, width is
    393  *        ignored. If width is specified with a "*" character instead of number,
    394  *        width is taken from parameter list. And integer parameter is expected
    395  *        before parameter for processed conversion specification. If this value
    396  *        is negative its absolute value is taken and the "-" flag is set.
     526 *  - Specify the minimal width of a printed argument. If it is bigger,
     527 *    width is ignored. If width is specified with a "*" character instead of
     528 *    number, width is taken from parameter list. And integer parameter is
     529 *    expected before parameter for processed conversion specification. If
     530 *    this value is negative its absolute value is taken and the "-" flag is
     531 *    set.
    397532 *
    398533 * PRECISION:@n
    399  *      - Value precision. For numbers it specifies minimum valid numbers.
    400  *        Smaller numbers are printed with leading zeroes. Bigger numbers are
    401  *        not affected. Strings with more than precision characters are cut off.
    402  *        Just as with width, an "*" can be used used instead of a number. An
    403  *        integer value is then expected in parameters. When both width and
    404  *        precision are specified using "*", the first parameter is used for
    405  *        width and the second one for precision.
    406  * 
     534 *  - Value precision. For numbers it specifies minimum valid numbers.
     535 *    Smaller numbers are printed with leading zeroes. Bigger numbers are not
     536 *    affected. Strings with more than precision characters are cut off. Just
     537 *    as with width, an "*" can be used used instead of a number. An integer
     538 *    value is then expected in parameters. When both width and precision are
     539 *    specified using "*", the first parameter is used for width and the
     540 *    second one for precision.
     541 *
    407542 * TYPE:@n
    408  *      - "hh"  Signed or unsigned char.@n
    409  *      - "h"   Signed or usigned short.@n
    410  *      - ""    Signed or usigned int (default value).@n
    411  *      - "l"   Signed or usigned long int.@n
    412  *      - "ll"  Signed or usigned long long int.@n
    413  *      - "z"   Type size_t.@n
    414  *
    415  * 
     543 *  - "hh" Signed or unsigned char.@n
     544 *  - "h"  Signed or unsigned short.@n
     545 *  - ""   Signed or unsigned int (default value).@n
     546 *  - "l"  Signed or unsigned long int.@n
     547 *         If conversion is "c", the character is wchar_t (wide character).@n
     548 *         If conversion is "s", the string is wchar_t * (wide string).@n
     549 *  - "ll" Signed or unsigned long long int.@n
     550 *
    416551 * CONVERSION:@n
    417  *      - %     Print percentile character itself.
    418  *
    419  *      - c     Print single character.
    420  *
    421  *      - s     Print zero terminated string. If a NULL value is passed as
    422  *              value, "(NULL)" is printed instead.
    423  *
    424  *      - P, p  Print value of a pointer. Void * value is expected and it is
    425  *              printed in hexadecimal notation with prefix (as with '\%#X' or
    426  *              '\%#x' for 32bit or '\%#X' or '\%#x' for 64bit long pointers).
    427  *
    428  *      - b     Print value as unsigned binary number. Prefix is not printed by
    429  *              default. (Nonstandard extension.)
    430  *
    431  *      - o     Print value as unsigned octal number. Prefix is not printed by
    432  *              default.
    433  *
    434  *      - d, i  Print signed decimal number. There is no difference between d
    435  *              and i conversion.
    436  *
    437  *      - u     Print unsigned decimal number.
    438  *
    439  *      - X, x  Print hexadecimal number with upper- or lower-case. Prefix is
    440  *              not printed by default.
    441  *
    442  * All other characters from fmt except the formatting directives are printed in
     552 *  - % Print percentile character itself.
     553 *
     554 *  - c Print single character. The character is expected to be plain
     555 *      ASCII (e.g. only values 0 .. 127 are valid).@n
     556 *      If type is "l", then the character is expected to be wide character
     557 *      (e.g. values 0 .. 0x10ffff are valid).
     558 *
     559 *  - s Print zero terminated string. If a NULL value is passed as
     560 *      value, "(NULL)" is printed instead.@n
     561 *      If type is "l", then the string is expected to be wide string.
     562 *
     563 *  - P, p Print value of a pointer. Void * value is expected and it is
     564 *         printed in hexadecimal notation with prefix (as with \%#X / \%#x
     565 *         for 32-bit or \%#X / \%#x for 64-bit long pointers).
     566 *
     567 *  - b Print value as unsigned binary number. Prefix is not printed by
     568 *      default. (Nonstandard extension.)
     569 *
     570 *  - o Print value as unsigned octal number. Prefix is not printed by
     571 *      default.
     572 *
     573 *  - d, i Print signed decimal number. There is no difference between d
     574 *         and i conversion.
     575 *
     576 *  - u Print unsigned decimal number.
     577 *
     578 *  - X, x Print hexadecimal number with upper- or lower-case. Prefix is
     579 *         not printed by default.
     580 *
     581 * All other characters from fmt except the formatting directives are printed
    443582 * verbatim.
    444583 *
    445  * @param fmt Formatting NULL terminated string.
    446  * @return Number of printed characters or negative value on failure.
    447  */
    448 int printf_core(const char *fmt, struct printf_spec *ps, va_list ap)
    449 {
    450         /* i is the index of the currently processed char from fmt */
    451         int i = 0;
    452         /* j is the index to the first not printed nonformating character */
    453         int j = 0;
    454 
    455         int end;
    456         int counter;    /* counter of printed characters */
    457         int retval;     /* used to store return values from called functions */
    458         char c;
    459         qualifier_t qualifier;  /* type of argument */
    460         int base;       /* base in which will be a numeric parameter printed */
    461         uint64_t number; /* argument value */
    462         size_t  size;   /* byte size of integer parameter */
    463         int width, precision;
    464         uint64_t flags;
    465        
    466         counter = 0;
    467        
    468         while ((c = fmt[i])) {
    469                 /* control character */
    470                 if (c == '%' ) {
    471                         /* print common characters if any processed */ 
     584 * @param fmt Format NULL-terminated string.
     585 *
     586 * @return Number of characters printed, negative value on failure.
     587 *
     588 */
     589int printf_core(const char *fmt, printf_spec_t *ps, va_list ap)
     590{
     591        size_t i;        /* Index of the currently processed character from fmt */
     592        size_t nxt = 0;  /* Index of the next character from fmt */
     593        size_t j = 0;    /* Index to the first not printed nonformating character */
     594       
     595        count_t counter = 0;  /* Number of characters printed */
     596        int retval;           /* Return values from nested functions */
     597       
     598        while (true) {
     599                i = nxt;
     600                wchar_t uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
     601               
     602                if (uc == 0)
     603                        break;
     604               
     605                /* Control character */
     606                if (uc == '%') {
     607                        /* Print common characters if any processed */
    472608                        if (i > j) {
    473                                 if ((retval = printf_putnchars(&fmt[j],
    474                                     (size_t)(i - j), ps)) < 0) { /* error */
    475                                         goto minus_out;
     609                                if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
     610                                        /* Error */
     611                                        counter = -counter;
     612                                        goto out;
    476613                                }
    477614                                counter += retval;
    478615                        }
    479                
     616                       
    480617                        j = i;
    481                         /* parse modifiers */
    482                         flags = 0;
    483                         end = 0;
     618                       
     619                        /* Parse modifiers */
     620                        uint32_t flags = 0;
     621                        bool end = false;
    484622                       
    485623                        do {
    486                                 ++i;
    487                                 switch (c = fmt[i]) {
     624                                i = nxt;
     625                                uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
     626                                switch (uc) {
    488627                                case '#':
    489628                                        flags |= __PRINTF_FLAG_PREFIX;
     
    502641                                        break;
    503642                                default:
    504                                         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])) {
     643                                        end = true;
     644                                };
     645                        } while (!end);
     646                       
     647                        /* Width & '*' operator */
     648                        int width = 0;
     649                        if (isdigit(uc)) {
     650                                while (true) {
    513651                                        width *= 10;
    514                                         width += fmt[i++] - '0';
     652                                        width += uc - '0';
     653                                       
     654                                        i = nxt;
     655                                        uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
     656                                        if (uc == 0)
     657                                                break;
     658                                        if (!isdigit(uc))
     659                                                break;
    515660                                }
    516                         } else if (fmt[i] == '*') {
    517                                 /* get width value from argument list*/
    518                                 i++;
    519                                 width = (int)va_arg(ap, int);
     661                        } else if (uc == '*') {
     662                                /* Get width value from argument list */
     663                                i = nxt;
     664                                uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
     665                                width = (int) va_arg(ap, int);
    520666                                if (width < 0) {
    521                                         /* negative width sets '-' flag */
     667                                        /* Negative width sets '-' flag */
    522668                                        width *= -1;
    523669                                        flags |= __PRINTF_FLAG_LEFTALIGNED;
     
    525671                        }
    526672                       
    527                         /* precision and '*' operator */       
    528                         precision = 0;
    529                         if (fmt[i] == '.') {
    530                                 ++i;
    531                                 if (isdigit(fmt[i])) {
    532                                         while (isdigit(fmt[i])) {
     673                        /* Precision and '*' operator */
     674                        int precision = 0;
     675                        if (uc == '.') {
     676                                i = nxt;
     677                                uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
     678                                if (isdigit(uc)) {
     679                                        while (true) {
    533680                                                precision *= 10;
    534                                                 precision += fmt[i++] - '0';
     681                                                precision += uc - '0';
     682                                               
     683                                                i = nxt;
     684                                                uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
     685                                                if (uc == 0)
     686                                                        break;
     687                                                if (!isdigit(uc))
     688                                                        break;
    535689                                        }
    536                                 } else if (fmt[i] == '*') {
    537                                         /* get precision value from argument */
    538                                         i++;
    539                                         precision = (int)va_arg(ap, int);
     690                                } else if (uc == '*') {
     691                                        /* Get precision value from the argument list */
     692                                        i = nxt;
     693                                        uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
     694                                        precision = (int) va_arg(ap, int);
    540695                                        if (precision < 0) {
    541                                                 /* negative precision ignored */
     696                                                /* Ignore negative precision */
    542697                                                precision = 0;
    543698                                        }
    544699                                }
    545700                        }
    546 
    547                         switch (fmt[i++]) {
    548                         /** @todo unimplemented qualifiers:
    549                          * t ptrdiff_t - ISO C 99
     701                       
     702                        qualifier_t qualifier;
     703                       
     704                        switch (uc) {
     705                        /** @todo Unimplemented qualifiers:
     706                         *        t ptrdiff_t - ISO C 99
    550707                         */
    551                         case 'h':       /* char or short */
     708                        case 'h':
     709                                /* Char or short */
    552710                                qualifier = PrintfQualifierShort;
    553                                 if (fmt[i] == 'h') {
    554                                         i++;
     711                                i = nxt;
     712                                uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
     713                                if (uc == 'h') {
     714                                        i = nxt;
     715                                        uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    555716                                        qualifier = PrintfQualifierByte;
    556717                                }
    557718                                break;
    558                         case 'l':       /* long or long long*/
     719                        case 'l':
     720                                /* Long or long long */
    559721                                qualifier = PrintfQualifierLong;
    560                                 if (fmt[i] == 'l') {
    561                                         i++;
     722                                i = nxt;
     723                                uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
     724                                if (uc == 'l') {
     725                                        i = nxt;
     726                                        uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
    562727                                        qualifier = PrintfQualifierLongLong;
    563728                                }
    564729                                break;
    565                         case 'z':       /* size_t */
    566                                 qualifier = PrintfQualifierSizeT;
    567                                 break;
    568730                        default:
    569                                 /* set default type */
     731                                /* Default type */
    570732                                qualifier = PrintfQualifierInt;
    571                                 --i;
    572                         }       
    573                        
    574                         base = 10;
    575 
    576                         switch (c = fmt[i]) {
    577 
     733                        }
     734                       
     735                        unsigned int base = 10;
     736                       
     737                        switch (uc) {
    578738                        /*
    579739                         * String and character conversions.
    580740                         */
    581741                        case 's':
    582                                 if ((retval = print_string(va_arg(ap, char*),
    583                                     width, precision, flags, ps)) < 0) {
    584                                         goto minus_out;
     742                                if (qualifier == PrintfQualifierLong)
     743                                        retval = print_wstr(va_arg(ap, wchar_t *), width, precision, flags, ps);
     744                                else
     745                                        retval = print_str(va_arg(ap, char *), width, precision, flags, ps);
     746                               
     747                                if (retval < 0) {
     748                                        counter = -counter;
     749                                        goto out;
    585750                                }
    586                                        
     751                               
    587752                                counter += retval;
    588                                 j = i + 1;
     753                                j = nxt;
    589754                                goto next_char;
    590755                        case 'c':
    591                                 c = va_arg(ap, unsigned int);
    592                                 retval = print_char(c, width, flags, ps);
     756                                if (qualifier == PrintfQualifierLong)
     757                                        retval = print_wchar(va_arg(ap, wchar_t), width, flags, ps);
     758                                else
     759                                        retval = print_char(va_arg(ap, unsigned int), width, flags, ps);
     760                               
    593761                                if (retval < 0) {
    594                                         goto minus_out;
    595                                 }
    596 
     762                                        counter = -counter;
     763                                        goto out;
     764                                };
     765                               
    597766                                counter += retval;
    598                                 j = i + 1;
     767                                j = nxt;
    599768                                goto next_char;
    600 
    601                         /* 
     769                       
     770                        /*
    602771                         * Integer values
    603772                         */
    604                         case 'P': /* pointer */
    605                                 flags |= __PRINTF_FLAG_BIGCHARS;
     773                        case 'P':
     774                                /* Pointer */
     775                                flags |= __PRINTF_FLAG_BIGCHARS;
    606776                        case 'p':
    607777                                flags |= __PRINTF_FLAG_PREFIX;
    608778                                base = 16;
    609779                                qualifier = PrintfQualifierPointer;
    610                                 break; 
    611                         case 'b': 
     780                                break;
     781                        case 'b':
    612782                                base = 2;
    613783                                break;
     
    617787                        case 'd':
    618788                        case 'i':
    619                                 flags |= __PRINTF_FLAG_SIGNED; 
     789                                flags |= __PRINTF_FLAG_SIGNED;
    620790                        case 'u':
    621791                                break;
     
    625795                                base = 16;
    626796                                break;
    627                         /* percentile itself */
    628                         case '%':
     797                       
     798                        /* Percentile itself */
     799                        case '%':
    629800                                j = i;
    630801                                goto next_char;
     802                       
    631803                        /*
    632804                         * Bad formatting.
     
    634806                        default:
    635807                                /*
    636                                  * Unknown format. Now, j is the index of '%',
    637                                  * so we will print the whole bad format
    638                                  * sequence.
     808                                 * Unknown format. Now, j is the index of '%'
     809                                 * so we will print whole bad format sequence.
    639810                                 */
    640                                 goto next_char;         
    641                         }
    642                
    643                
     811                                goto next_char;
     812                        }
     813                       
    644814                        /* Print integers */
     815                        size_t size;
     816                        uint64_t number;
    645817                        switch (qualifier) {
    646818                        case PrintfQualifierByte:
    647819                                size = sizeof(unsigned char);
    648                                 number = (uint64_t)va_arg(ap, unsigned int);
     820                                number = (uint64_t) va_arg(ap, unsigned int);
    649821                                break;
    650822                        case PrintfQualifierShort:
    651823                                size = sizeof(unsigned short);
    652                                 number = (uint64_t)va_arg(ap, unsigned int);
     824                                number = (uint64_t) va_arg(ap, unsigned int);
    653825                                break;
    654826                        case PrintfQualifierInt:
    655827                                size = sizeof(unsigned int);
    656                                 number = (uint64_t)va_arg(ap, unsigned int);
     828                                number = (uint64_t) va_arg(ap, unsigned int);
    657829                                break;
    658830                        case PrintfQualifierLong:
    659831                                size = sizeof(unsigned long);
    660                                 number = (uint64_t)va_arg(ap, unsigned long);
     832                                number = (uint64_t) va_arg(ap, unsigned long);
    661833                                break;
    662834                        case PrintfQualifierLongLong:
    663835                                size = sizeof(unsigned long long);
    664                                 number = (uint64_t)va_arg(ap,
    665                                     unsigned long long);
     836                                number = (uint64_t) va_arg(ap, unsigned long long);
    666837                                break;
    667838                        case PrintfQualifierPointer:
    668839                                size = sizeof(void *);
    669                                 number = (uint64_t)(unsigned long)va_arg(ap,
    670                                     void *);
    671                                 break;
    672                         case PrintfQualifierSizeT:
    673                                 size = sizeof(size_t);
    674                                 number = (uint64_t)va_arg(ap, size_t);
    675                                 break;
    676                         default: /* Unknown qualifier */
    677                                 goto minus_out;
    678                                        
     840                                number = (uint64_t) (unsigned long) va_arg(ap, void *);
     841                                break;
     842                        default:
     843                                /* Unknown qualifier */
     844                                counter = -counter;
     845                                goto out;
    679846                        }
    680847                       
     
    682849                                if (number & (0x1 << (size * 8 - 1))) {
    683850                                        flags |= __PRINTF_FLAG_NEGATIVE;
    684                                
     851                                       
    685852                                        if (size == sizeof(uint64_t)) {
    686                                                 number = -((int64_t)number);
     853                                                number = -((int64_t) number);
    687854                                        } else {
    688855                                                number = ~number;
     
    694861                                }
    695862                        }
    696 
     863                       
    697864                        if ((retval = print_number(number, width, precision,
    698                             base, flags, ps)) < 0 ) {
    699                                 goto minus_out;
    700                         }
    701 
     865                            base, flags, ps)) < 0) {
     866                                counter = -counter;
     867                                goto out;
     868                        }
     869                       
    702870                        counter += retval;
    703                         j = i + 1;
    704                 }       
     871                        j = nxt;
     872                }
    705873next_char:
    706                        
    707                 ++i;
     874                ;
    708875        }
    709876       
    710877        if (i > j) {
    711                 retval = printf_putnchars(&fmt[j], (size_t)(i - j), ps);
    712                 if (retval < 0) { /* error */
    713                         goto minus_out;
     878                if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
     879                        /* Error */
     880                        counter = -counter;
     881                        goto out;
    714882                }
    715883                counter += retval;
    716884        }
    717885       
    718         return counter;
    719 minus_out:
    720         return -counter;
     886out:
     887        return ((int) counter);
    721888}
    722889
Note: See TracChangeset for help on using the changeset viewer.