Ignore:
Timestamp:
2009-03-24T14:43:25Z (15 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
8f29e336
Parents:
74c8da2c
Message:

Unicode aware printf and family functions
(this breaks some things, but will be fixed soon)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/printf/printf_core.c

    r74c8da2c reec616b  
    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 generic 
     31/** @addtogroup generic
    3132 * @{
    3233 */
    3334/**
    3435 * @file
    35  * @brief       Printing functions.
     36 * @brief Printing functions.
    3637 */
    3738
    3839#include <printf/printf_core.h>
    39 #include <putchar.h>
    4040#include <print.h>
    4141#include <arch/arg.h>
     
    4545
    4646/** show prefixes 0x or 0 */
    47 #define __PRINTF_FLAG_PREFIX            0x00000001
     47#define __PRINTF_FLAG_PREFIX       0x00000001
    4848/** signed / unsigned number */
    49 #define __PRINTF_FLAG_SIGNED            0x00000002
     49#define __PRINTF_FLAG_SIGNED       0x00000002
    5050/** print leading zeroes */
    51 #define __PRINTF_FLAG_ZEROPADDED        0x00000004
     51#define __PRINTF_FLAG_ZEROPADDED   0x00000004
    5252/** align to left */
    53 #define __PRINTF_FLAG_LEFTALIGNED       0x00000010
     53#define __PRINTF_FLAG_LEFTALIGNED  0x00000010
    5454/** always show + sign */
    55 #define __PRINTF_FLAG_SHOWPLUS          0x00000020
     55#define __PRINTF_FLAG_SHOWPLUS     0x00000020
    5656/** print space instead of plus */
    57 #define __PRINTF_FLAG_SPACESIGN         0x00000040
     57#define __PRINTF_FLAG_SPACESIGN    0x00000040
    5858/** show big characters */
    59 #define __PRINTF_FLAG_BIGCHARS          0x00000080
     59#define __PRINTF_FLAG_BIGCHARS     0x00000080
    6060/** number has - sign */
    61 #define __PRINTF_FLAG_NEGATIVE          0x00000100
     61#define __PRINTF_FLAG_NEGATIVE     0x00000100
    6262
    6363/**
     
    6666 * zero-filling subroutine)
    6767 */
    68 #define PRINT_NUMBER_BUFFER_SIZE        (64 + 5)       
     68#define PRINT_NUMBER_BUFFER_SIZE  (64 + 5)
    6969
    7070/** Enumeration of possible arguments types.
     
    7979} qualifier_t;
    8080
     81static char nullstr[] = "(NULL)";
    8182static char digits_small[] = "0123456789abcdef";
    8283static char digits_big[] = "0123456789ABCDEF";
    8384
    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        
     85/** Print one or more UTF-8 characters without adding newline.
     86 *
     87 * @param buf  Buffer holding UTF-8 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 UTF-8 characters printed.
     93 *
     94 */
     95static int printf_putnchars_utf8(const char *buf, size_t size,
     96    printf_spec_t *ps)
     97{
     98        return ps->write_utf8((void *) buf, size, ps->data);
     99}
     100
     101/** Print one or more UTF-32 characters without adding newline.
     102 *
     103 * @param buf  Buffer holding UTF-32 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 UTF-32 characters printed.
     109 *
     110 */
     111static int printf_putnchars_utf32(const wchar_t *buf, size_t size,
     112    printf_spec_t *ps)
     113{
     114        return ps->write_utf32((void *) buf, size, ps->data);
     115}
     116
     117/** Print UTF-8 string without adding a newline.
     118 *
     119 * @param str UTF-8 string to print.
     120 * @param ps  Write function specification and support data.
     121 *
     122 * @return Number of UTF-8 characters printed.
     123 *
     124 */
     125static int printf_putstr(const char *str, printf_spec_t *ps)
     126{
     127        if (str == NULL)
     128                return printf_putnchars_utf8(nullstr, strlen(nullstr), ps);
     129       
     130        return ps->write_utf8((void *) str, strlen(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->write_utf8((void *) &invalch, 1, ps->data);
     145       
     146        return ps->write_utf8(&ch, 1, ps->data);
     147}
     148
     149/** Print one UTF-32 character.
     150 *
     151 * @param c  UTF-32 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 (!unicode_check(ch))
     160                return ps->write_utf8((void *) &invalch, 1, ps->data);
     161       
     162        return ps->write_utf32(&ch, 1, 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;
    144177        if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
    145178                while (--width > 0) {
     
    148181                         * the predecrement.
    149182                         */
    150                         if (printf_putchar(' ', ps) > 0)       
    151                                 ++counter;
    152                 }
    153         }
    154        
    155         if (printf_putchar(c, ps) > 0)
     183                        if (printf_putchar(' ', ps) > 0)
     184                                counter++;
     185                }
     186        }
     187       
     188        if (printf_putchar(ch, ps) > 0)
    156189                counter++;
    157 
     190       
    158191        while (--width > 0) {
     192                /*
     193                 * One space is consumed by the character itself, hence
     194                 * the predecrement.
     195                 */
     196                if (printf_putchar(' ', ps) > 0)
     197                        counter++;
     198        }
     199       
     200        return (int) (counter + 1);
     201}
     202
     203/** Print one formatted UTF-32 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)) {
     216                while (--width > 0) {
    159217                        /*
    160218                         * One space is consumed by the character itself, hence
    161219                         * the predecrement.
    162220                         */
     221                        if (printf_putchar(' ', ps) > 0)
     222                                counter++;
     223                }
     224        }
     225       
     226        if (printf_putwchar(ch, ps) > 0)
     227                counter++;
     228       
     229        while (--width > 0) {
     230                /*
     231                 * One space is consumed by the character itself, hence
     232                 * the predecrement.
     233                 */
    163234                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;
     235                        counter++;
     236        }
     237       
     238        return (int) (counter + 1);
     239}
     240
     241/** Print UTF-8 string.
     242 *
     243 * @param str       UTF-8 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 UTF-8 characters printed, negative value on failure.
     249 */
     250static int print_utf8(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        size_t size = strlen_utf8(str);
     258        if (precision == 0)
     259                precision = size;
     260       
     261        count_t counter = 0;
     262        width -= precision;
     263        if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
     264                while (width-- > 0) {
     265                        if (printf_putchar(' ', ps) == 1)
     266                                counter++;
     267                }
     268        }
     269       
    184270        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)
     271        size_t bytes = utf8_count_bytes(str, min(size, precision));
     272        if ((retval = printf_putnchars_utf8(str, bytes, ps)) < 0)
     273                return -counter;
     274       
     275        counter += retval;
     276       
     277        while (width-- > 0) {
     278                if (printf_putchar(' ', ps) == 1)
     279                        counter++;
     280        }
     281       
     282        return ((int) counter);
     283}
     284
     285/** Print UTF-32 string.
     286 *
     287 * @param str       UTF-32 string to be printed.
     288 * @param width     Width modifier.
     289 * @param precision Precision modifier.
     290 * @param flags     Flags that modify the way the string is printed.
     291 *
     292 * @return Number of UTF-32 characters printed, negative value on failure.
     293 */
     294static int print_utf32(wchar_t *str, int width, unsigned int precision,
     295        uint32_t flags, printf_spec_t *ps)
     296{
     297        if (str == NULL)
     298                return printf_putstr(nullstr, ps);
     299       
     300        /* Print leading spaces */
     301        size_t size = strlen_utf32(str);
     302        if (precision == 0)
    195303                precision = size;
    196 
     304       
     305        count_t counter = 0;
    197306        width -= precision;
    198        
    199307        if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
    200                 while (width-- > 0) {   
    201                         if (printf_putchar(' ', ps) == 1)       
     308                while (width-- > 0) {
     309                        if (printf_putchar(' ', ps) == 1)
    202310                                counter++;
    203311                }
    204312        }
    205 
    206         if ((retval = printf_putnchars(s, min(size, precision), ps)) < 0) {
     313       
     314        int retval;
     315        size_t bytes = min(size, precision) * sizeof(wchar_t);
     316        if ((retval = printf_putnchars_utf32(str, bytes, ps)) < 0)
    207317                return -counter;
    208         }
    209         counter += retval;     
    210 
     318       
     319        counter += retval;
     320       
    211321        while (width-- > 0) {
    212                 if (printf_putchar(' ', ps) == 1)       
    213                         ++counter;
    214         }
    215        
    216         return counter;
    217 }
    218 
     322                if (printf_putchar(' ', ps) == 1)
     323                        counter++;
     324        }
     325       
     326        return ((int) counter);
     327}
    219328
    220329/** Print a number in a given base.
     
    222331 * Print significant digits of a number in given base.
    223332 *
    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.
     333 * @param num       Number to print.
     334 * @param width     Width modifier.
     335 * @param precision Precision modifier.
     336 * @param base      Base to print the number in (must be between 2 and 16).
     337 * @param flags     Flags that modify the way the number is printed.
     338 *
     339 * @return Number of characters printed.
    231340 *
    232341 */
    233342static 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 
     343    uint32_t flags, printf_spec_t *ps)
     344{
     345        char *digits;
     346        if (flags & __PRINTF_FLAG_BIGCHARS)
     347                digits = digits_big;
     348        else
     349                digits = digits_small;
     350       
     351        char data[PRINT_NUMBER_BUFFER_SIZE];
     352        char *ptr = &data[PRINT_NUMBER_BUFFER_SIZE - 1];
     353       
     354        /* Size of number with all prefixes and signs */
     355        int size = 0;
     356       
     357        /* Put zero at end of string */
     358        *ptr-- = 0;
     359       
    250360        if (num == 0) {
    251361                *ptr-- = '0';
     
    258368        }
    259369       
    260         number_size = size;
    261 
     370        /* Size of plain number */
     371        int number_size = size;
     372       
    262373        /*
    263          * Collect the sum of all prefixes/signs/... to calculate padding and
     374         * Collect the sum of all prefixes/signs/etc. to calculate padding and
    264375         * leading zeroes.
    265376         */
    266377        if (flags & __PRINTF_FLAG_PREFIX) {
    267378                switch(base) {
    268                 case 2: /* Binary formating is not standard, but usefull */
     379                case 2:
     380                        /* Binary formating is not standard, but usefull */
    269381                        size += 2;
    270382                        break;
     
    277389                }
    278390        }
    279 
    280         sgn = 0;
     391       
     392        char sgn = 0;
    281393        if (flags & __PRINTF_FLAG_SIGNED) {
    282394                if (flags & __PRINTF_FLAG_NEGATIVE) {
     
    291403                }
    292404        }
    293 
    294         if (flags & __PRINTF_FLAG_LEFTALIGNED) {
     405       
     406        if (flags & __PRINTF_FLAG_LEFTALIGNED)
    295407                flags &= ~__PRINTF_FLAG_ZEROPADDED;
    296         }
    297 
     408       
    298409        /*
    299          * If the number is leftaligned or precision is specified then
    300          * zeropadding is ignored.
     410         * If the number is left-aligned or precision is specified then
     411         * padding with zeros is ignored.
    301412         */
    302413        if (flags & __PRINTF_FLAG_ZEROPADDED) {
    303                 if ((precision == 0) && (width > size)) {
     414                if ((precision == 0) && (width > size))
    304415                        precision = width - size + number_size;
    305                 }
    306         }
    307 
    308         /* print leading spaces */
     416        }
     417       
     418        /* Print leading spaces */
    309419        if (number_size > precision) {
    310                 /* print the whole number not only a part */
     420                /* Print the whole number, not only a part */
    311421                precision = number_size;
    312422        }
    313 
     423       
    314424        width -= precision + size - number_size;
     425        count_t counter = 0;
    315426       
    316427        if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
    317                 while (width-- > 0) {   
    318                         if (printf_putchar(' ', ps) == 1)       
     428                while (width-- > 0) {
     429                        if (printf_putchar(' ', ps) == 1)
    319430                                counter++;
    320431                }
    321432        }
    322433       
    323        
    324         /* print sign */
     434        /* Print sign */
    325435        if (sgn) {
    326436                if (printf_putchar(sgn, ps) == 1)
     
    328438        }
    329439       
    330         /* print prefix */
    331        
     440        /* Print prefix */
    332441        if (flags & __PRINTF_FLAG_PREFIX) {
    333442                switch(base) {
    334                 case 2: /* Binary formating is not standard, but usefull */
     443                case 2:
     444                        /* Binary formating is not standard, but usefull */
    335445                        if (printf_putchar('0', ps) == 1)
    336446                                counter++;
     
    360470                }
    361471        }
    362 
    363         /* print leading zeroes */
     472       
     473        /* Print leading zeroes */
    364474        precision -= number_size;
    365         while (precision-- > 0) {       
     475        while (precision-- > 0) {
    366476                if (printf_putchar('0', ps) == 1)
    367477                        counter++;
    368478        }
    369 
    370        
    371         /* print number itself */
    372 
    373         if ((retval = printf_putstr(++ptr, ps)) > 0) {
     479       
     480        /* Print the number itself */
     481        int retval;
     482        if ((retval = printf_putstr(++ptr, ps)) > 0)
    374483                counter += retval;
    375         }
    376        
    377         /* print ending spaces */
    378        
    379         while (width-- > 0) {   
    380                 if (printf_putchar(' ', ps) == 1)       
     484       
     485        /* Print tailing spaces */
     486       
     487        while (width-- > 0) {
     488                if (printf_putchar(' ', ps) == 1)
    381489                        counter++;
    382490        }
    383 
    384         return counter;
    385 }
    386 
     491       
     492        return ((int) counter);
     493}
    387494
    388495/** Print formatted string.
     
    390497 * Print string formatted according to the fmt parameter and variadic arguments.
    391498 * Each formatting directive must have the following form:
    392  * 
    393  *      \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
     499 *
     500 *  \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
    394501 *
    395502 * 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  * 
     503 *  - "#" Force to print prefix. For \%o conversion, the prefix is 0, for
     504 *        \%x and \%X prefixes are 0x and 0X and for conversion \%b the
     505 *        prefix is 0b.
     506 *
     507 *  - "-" Align to left.
     508 *
     509 *  - "+" Print positive sign just as negative.
     510 *
     511 *  - " " If the printed number is positive and "+" flag is not set,
     512 *        print space in place of sign.
     513 *
     514 *  - "0" Print 0 as padding instead of spaces. Zeroes are placed between
     515 *        sign and the rest of the number. This flag is ignored if "-"
     516 *        flag is specified.
     517 *
    411518 * 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.
     519 *  - Specify the minimal width of a printed argument. If it is bigger,
     520 *    width is ignored. If width is specified with a "*" character instead of
     521 *    number, width is taken from parameter list. And integer parameter is
     522 *    expected before parameter for processed conversion specification. If
     523 *    this value is negative its absolute value is taken and the "-" flag is
     524 *    set.
    418525 *
    419526 * 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  * 
     527 *  - Value precision. For numbers it specifies minimum valid numbers.
     528 *    Smaller numbers are printed with leading zeroes. Bigger numbers are not
     529 *    affected. Strings with more than precision characters are cut off. Just
     530 *    as with width, an "*" can be used used instead of a number. An integer
     531 *    value is then expected in parameters. When both width and precision are
     532 *    specified using "*", the first parameter is used for width and the
     533 *    second one for precision.
     534 *
    428535 * 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  *
     536 *  - "hh" Signed or unsigned char.@n
     537 *  - "h"  Signed or unsigned short.@n
     538 *  - ""   Signed or unsigned int (default value).@n
     539 *  - "l"  Signed or unsigned long int.@n
     540 *         If conversion is "c", the character is wchar_t (UTF-32).@n
     541 *         If conversion is "s", the string is wchar_t * (UTF-32).@n
     542 *  - "ll" Signed or unsigned long long int.@n
     543 *
    436544 * 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  *
     545 *  - % Print percentile character itself.
     546 *
     547 *  - c Print single character. The character is expected to be plain
     548 *      ASCII (e.g. only values 0 .. 127 are valid).@n
     549 *      If type is "l", then the character is expected to be UTF-32
     550 *      (e.g. values 0 .. 0x10ffff are valid).
     551 *
     552 *  - s Print zero terminated string. If a NULL value is passed as
     553 *      value, "(NULL)" is printed instead.@n
     554 *      The string is expected to be correctly encoded UTF-8 (or plain
     555 *      ASCII, which is a subset of UTF-8).@n
     556 *      If type is "l", then the string is expected to be correctly
     557 *      encoded UTF-32.
     558 *
     559 *  - P, p Print value of a pointer. Void * value is expected and it is
     560 *         printed in hexadecimal notation with prefix (as with \%#X / \%#x
     561 *         for 32-bit or \%#X / \%#x for 64-bit long pointers).
     562 *
     563 *  - b Print value as unsigned binary number. Prefix is not printed by
     564 *      default. (Nonstandard extension.)
     565 *
     566 *  - o Print value as unsigned octal number. Prefix is not printed by
     567 *      default.
     568 *
     569 *  - d, i Print signed decimal number. There is no difference between d
     570 *         and i conversion.
     571 *
     572 *  - u Print unsigned decimal number.
     573 *
     574 *  - X, x Print hexadecimal number with upper- or lower-case. Prefix is
     575 *         not printed by default.
     576 *
    462577 * All other characters from fmt except the formatting directives are printed in
    463578 * verbatim.
    464579 *
    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 */ 
     580 * @param fmt Formatting NULL terminated string (UTF-8 or plain ASCII).
     581 *
     582 * @return Number of UTF-8 characters printed, negative value on failure.
     583 *
     584 */
     585int printf_core(const char *fmt, printf_spec_t *ps, va_list ap)
     586{
     587        index_t i = 0;  /* Index of the currently processed character from fmt */
     588        index_t j = 0;  /* Index to the first not printed nonformating character */
     589       
     590        wchar_t uc;           /* Current UTF-32 character decoded from fmt */
     591        count_t counter = 0;  /* Number of UTF-8 characters printed */
     592        int retval;           /* Return values from nested functions */
     593       
     594        while ((uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT)) != 0) {
     595                /* Control character */
     596                if (uc == '%') {
     597                        /* Print common characters if any processed */
    489598                        if (i > j) {
    490                                 if ((retval = printf_putnchars(&fmt[j],
    491                                     (size_t)(i - j), ps)) < 0) { /* error */
     599                                if ((retval = printf_putnchars_utf8(&fmt[j], i - j, ps)) < 0) {
     600                                        /* Error */
    492601                                        counter = -counter;
    493602                                        goto out;
     
    495604                                counter += retval;
    496605                        }
    497                
     606                       
    498607                        j = i;
    499                         /* parse modifiers */
    500                         flags = 0;
    501                         end = 0;
     608                       
     609                        /* Parse modifiers */
     610                        uint32_t flags = 0;
     611                        bool end = false;
    502612                       
    503613                        do {
    504                                 ++i;
    505                                 switch (c = fmt[i]) {
     614                                i++;
     615                                switch ((uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT)) != 0) {
    506616                                case '#':
    507617                                        flags |= __PRINTF_FLAG_PREFIX;
     
    520630                                        break;
    521631                                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])) {
     632                                        end = true;
     633                                };
     634                        } while (!end);
     635                       
     636                        /* Width & '*' operator */
     637                        int width = 0;
     638                        if (isdigit(uc)) {
     639                                while ((uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT)) != 0) {
     640                                        if (!isdigit(uc))
     641                                                break;
     642                                       
    531643                                        width *= 10;
    532                                         width += fmt[i++] - '0';
     644                                        width += uc - '0';
     645                                        i++;
    533646                                }
    534                         } else if (fmt[i] == '*') {
    535                                 /* get width value from argument list */
     647                        } else if (uc == '*') {
     648                                /* Get width value from argument list */
    536649                                i++;
     650                                uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT);
    537651                                width = (int) va_arg(ap, int);
    538652                                if (width < 0) {
    539                                         /* negative width sets '-' flag */
     653                                        /* Negative width sets '-' flag */
    540654                                        width *= -1;
    541655                                        flags |= __PRINTF_FLAG_LEFTALIGNED;
     
    543657                        }
    544658                       
    545                         /* precision and '*' operator */       
    546                         precision = 0;
    547                         if (fmt[i] == '.') {
    548                                 ++i;
    549                                 if (isdigit(fmt[i])) {
    550                                         while (isdigit(fmt[i])) {
     659                        /* Precision and '*' operator */
     660                        int precision = 0;
     661                        if (uc == '.') {
     662                                i++;
     663                                uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT);
     664                                if (isdigit(uc)) {
     665                                        while ((uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT)) != 0) {
     666                                                if (!isdigit(uc))
     667                                                        break;
     668                                               
    551669                                                precision *= 10;
    552                                                 precision += fmt[i++] - '0';
     670                                                precision += uc - '0';
     671                                                i++;
    553672                                        }
    554673                                } else if (fmt[i] == '*') {
    555                                         /*
    556                                          * Get precision value from the argument
    557                                          * list.
    558                                          */
     674                                        /* Get precision value from the argument list */
    559675                                        i++;
     676                                        uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT);
    560677                                        precision = (int) va_arg(ap, int);
    561678                                        if (precision < 0) {
    562                                                 /* ignore negative precision */
     679                                                /* Ignore negative precision */
    563680                                                precision = 0;
    564681                                        }
    565682                                }
    566683                        }
    567 
    568                         switch (fmt[i++]) {
    569                         /** @todo unimplemented qualifiers:
    570                          * t ptrdiff_t - ISO C 99
     684                       
     685                        qualifier_t qualifier;
     686                       
     687                        switch (uc) {
     688                        /** @todo Unimplemented qualifiers:
     689                         *        t ptrdiff_t - ISO C 99
    571690                         */
    572                         case 'h':       /* char or short */
     691                        case 'h':
     692                                /* Char or short */
    573693                                qualifier = PrintfQualifierShort;
    574                                 if (fmt[i] == 'h') {
     694                                i++;
     695                                uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT);
     696                                if (uc == 'h') {
    575697                                        i++;
     698                                        uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT);
    576699                                        qualifier = PrintfQualifierByte;
    577700                                }
    578701                                break;
    579                         case 'l':       /* long or long long*/
     702                        case 'l':
     703                                /* Long or long long */
    580704                                qualifier = PrintfQualifierLong;
    581                                 if (fmt[i] == 'l') {
     705                                i++;
     706                                uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT);
     707                                if (uc == 'l') {
    582708                                        i++;
     709                                        uc = utf8_decode(fmt, &i, UTF8_NO_LIMIT);
    583710                                        qualifier = PrintfQualifierLongLong;
    584711                                }
    585712                                break;
    586713                        default:
    587                                 /* default type */
    588                                 qualifier = PrintfQualifierInt;
    589                                 --i;
    590                         }       
    591                        
    592                         base = 10;
    593 
    594                         switch (c = fmt[i]) {
    595 
     714                                /* Default type */
     715                                qualifier = PrintfQualifierInt;
     716                        }
     717                       
     718                        unsigned int base = 10;
     719                       
     720                        switch (uc) {
    596721                        /*
    597                         * String and character conversions.
    598                         */
     722                         * String and character conversions.
     723                         */
    599724                        case 's':
    600                                 if ((retval = print_string(va_arg(ap, char *),
    601                                     width, precision, flags, ps)) < 0) {
     725                                if (qualifier == PrintfQualifierLong)
     726                                        retval = print_utf32(va_arg(ap, wchar_t *), width, precision, flags, ps);
     727                                else
     728                                        retval = print_utf8(va_arg(ap, char *), width, precision, flags, ps);
     729                               
     730                                if (retval < 0) {
    602731                                        counter = -counter;
    603732                                        goto out;
    604                                 };
    605 
     733                                }
     734                               
    606735                                counter += retval;
    607                                 j = i + 1; 
     736                                j = i + 1;
    608737                                goto next_char;
    609738                        case 'c':
    610                                 c = va_arg(ap, unsigned int);
    611                                 retval = print_char(c, width, flags, ps);
     739                                if (qualifier == PrintfQualifierLong)
     740                                        retval = print_wchar(va_arg(ap, wchar_t), width, flags, ps);
     741                                else
     742                                        retval = print_char(va_arg(ap, unsigned int), width, flags, ps);
     743                               
    612744                                if (retval < 0) {
    613745                                        counter = -counter;
    614746                                        goto out;
    615747                                };
    616                                        
     748                               
    617749                                counter += retval;
    618750                                j = i + 1;
    619751                                goto next_char;
    620 
    621                         /* 
     752                       
     753                        /*
    622754                         * Integer values
    623755                         */
    624                         case 'P': /* pointer */
     756                        case 'P':
     757                                /* Pointer */
    625758                                flags |= __PRINTF_FLAG_BIGCHARS;
    626759                        case 'p':
     
    628761                                base = 16;
    629762                                qualifier = PrintfQualifierPointer;
    630                                 break; 
    631                         case 'b': 
     763                                break;
     764                        case 'b':
    632765                                base = 2;
    633766                                break;
     
    637770                        case 'd':
    638771                        case 'i':
    639                                 flags |= __PRINTF_FLAG_SIGNED; 
     772                                flags |= __PRINTF_FLAG_SIGNED;
    640773                        case 'u':
    641774                                break;
     
    645778                                base = 16;
    646779                                break;
    647                         /* percentile itself */
    648                         case '%':
     780                       
     781                        /* Percentile itself */
     782                        case '%':
    649783                                j = i;
    650784                                goto next_char;
     785                       
    651786                        /*
    652787                         * Bad formatting.
     
    657792                                 * so we will print whole bad format sequence.
    658793                                 */
    659                                 goto next_char;         
    660                         }
    661                
    662                
    663                 /* Print integers */
    664                         /* print number */
     794                                goto next_char;
     795                        }
     796                       
     797                        /* Print integers */
     798                        size_t size;
     799                        uint64_t number;
    665800                        switch (qualifier) {
    666801                        case PrintfQualifierByte:
     
    688823                                number = (uint64_t) (unsigned long) va_arg(ap, void *);
    689824                                break;
    690                         default: /* Unknown qualifier */
     825                        default:
     826                                /* Unknown qualifier */
    691827                                counter = -counter;
    692828                                goto out;
     
    696832                                if (number & (0x1 << (size * 8 - 1))) {
    697833                                        flags |= __PRINTF_FLAG_NEGATIVE;
    698                                
     834                                       
    699835                                        if (size == sizeof(uint64_t)) {
    700836                                                number = -((int64_t) number);
     
    708844                                }
    709845                        }
    710 
     846                       
    711847                        if ((retval = print_number(number, width, precision,
    712848                            base, flags, ps)) < 0) {
     
    714850                                goto out;
    715851                        }
    716 
     852                       
    717853                        counter += retval;
    718854                        j = i + 1;
    719                 }       
     855                }
    720856next_char:
    721                        
    722                 ++i;
     857               
     858                i++;
    723859        }
    724860       
    725861        if (i > j) {
    726                 if ((retval = printf_putnchars(&fmt[j], (unative_t) (i - j),
    727                     ps)) < 0) { /* error */
     862                if ((retval = printf_putnchars_utf8(&fmt[j], i - j, ps)) < 0) {
     863                        /* Error */
    728864                        counter = -counter;
    729865                        goto out;
    730                        
    731866                }
    732867                counter += retval;
    733868        }
    734 
     869       
    735870out:
    736         return counter;
     871        return ((int) counter);
    737872}
    738873
Note: See TracChangeset for help on using the changeset viewer.