Annotation of embedaddon/strongswan/src/libstrongswan/utils/printf_hook/printf_hook_builtin.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2013 Martin Willi
                      3:  * Copyright (C) 2013 revosec AG
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: /**
                     17:  * Copyright (C) 2002-2006 H. Peter Anvin
                     18:  *
                     19:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                     20:  * of this software and associated documentation files (the "Software"), to deal
                     21:  * in the Software without restriction, including without limitation the rights
                     22:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     23:  * copies of the Software, and to permit persons to whom the Software is
                     24:  * furnished to do so, subject to the following conditions:
                     25:  *
                     26:  * The above copyright notice and this permission notice shall be included in
                     27:  * all copies or substantial portions of the Software.
                     28:  *
                     29:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     30:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     31:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
                     32:  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     33:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     34:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     35:  * THE SOFTWARE.
                     36:  */
                     37: 
                     38: #include "printf_hook.h"
                     39: 
                     40: #include <utils/utils.h>
                     41: #include <utils/debug.h>
                     42: #include <collections/hashtable.h>
                     43: 
                     44: #include <inttypes.h>
                     45: #include <limits.h>
                     46: #include <stdio.h>
                     47: #include <stdarg.h>
                     48: #include <string.h>
                     49: #include <errno.h>
                     50: #include <math.h>
                     51: 
                     52: #define PRINTF_BUF_LEN 8192
                     53: #define ARGS_MAX 3
                     54: 
                     55: typedef struct private_printf_hook_t private_printf_hook_t;
                     56: typedef struct printf_hook_handler_t printf_hook_handler_t;
                     57: 
                     58: /**
                     59:  * private data of printf_hook
                     60:  */
                     61: struct private_printf_hook_t {
                     62: 
                     63:        /**
                     64:         * public functions
                     65:         */
                     66:        printf_hook_t public;
                     67: };
                     68: 
                     69: /**
                     70:  * struct with information about a registered handler
                     71:  */
                     72: struct printf_hook_handler_t {
                     73: 
                     74:        /**
                     75:         * callback function
                     76:         */
                     77:        printf_hook_function_t hook;
                     78: 
                     79:        /**
                     80:         * number of arguments
                     81:         */
                     82:        int numargs;
                     83: 
                     84:        /**
                     85:         * types of the arguments
                     86:         */
                     87:        int argtypes[ARGS_MAX];
                     88: };
                     89: 
                     90: /**
                     91:  * Data to pass to a printf hook.
                     92:  */
                     93: struct printf_hook_data_t {
                     94: 
                     95:        /**
                     96:         * Output buffer
                     97:         */
                     98:        char *q;
                     99: 
                    100:        /**
                    101:         * Remaining bytes in q
                    102:         */
                    103:        size_t n;
                    104: };
                    105: 
                    106: /**
                    107:  * Registered hooks (char => printf_hook_handler_t)
                    108:  */
                    109: static hashtable_t *hooks;
                    110: 
                    111: /**
                    112:  * builtin-printf variant of print_in_hook()
                    113:  */
                    114: size_t print_in_hook(printf_hook_data_t *data, char *fmt, ...)
                    115: {
                    116:        int written;
                    117:        va_list args;
                    118: 
                    119:        va_start(args, fmt);
                    120:        written = builtin_vsnprintf(data->q, data->n, fmt, args);
                    121:        va_end(args);
                    122: 
                    123:        if (written > data->n)
                    124:        {
                    125:                data->q += data->n;
                    126:                data->n = 0;
                    127:        }
                    128:        else
                    129:        {
                    130:                data->q += written;
                    131:                data->n -= written;
                    132:        }
                    133:        return written;
                    134: }
                    135: 
                    136: METHOD(printf_hook_t, add_handler, void,
                    137:        private_printf_hook_t *this, char spec, printf_hook_function_t hook, ...)
                    138: {
                    139:        int i = -1;
                    140:        bool failed = FALSE;
                    141:        printf_hook_handler_t *handler;
                    142:        printf_hook_argtype_t argtype;
                    143:        va_list args;
                    144: 
                    145:        INIT(handler,
                    146:                .hook = hook,
                    147:        );
                    148: 
                    149:        va_start(args, hook);
                    150:        while (!failed)
                    151:        {
                    152:                argtype = va_arg(args, printf_hook_argtype_t);
                    153: 
                    154:                if (argtype == PRINTF_HOOK_ARGTYPE_END)
                    155:                {
                    156:                        break;
                    157:                }
                    158:                if (++i >= countof(handler->argtypes))
                    159:                {
                    160:                        DBG1(DBG_LIB, "Too many arguments for printf hook with "
                    161:                                 "specifier '%c', not registered!", spec);
                    162:                        failed = TRUE;
                    163:                        break;
                    164:                }
                    165:                handler->argtypes[i] = argtype;
                    166:        }
                    167:        va_end(args);
                    168: 
                    169:        handler->numargs = i + 1;
                    170:        if (!failed && handler->numargs > 0)
                    171:        {
                    172:                free(hooks->put(hooks, (void*)(uintptr_t)spec, handler));
                    173:        }
                    174:        else
                    175:        {
                    176:                free(handler);
                    177:        }
                    178: }
                    179: 
                    180: /**
                    181:  * Printf format modifier flags
                    182:  */
                    183: typedef enum {
                    184:        FL_ZERO         = 0x01,
                    185:        FL_MINUS        = 0x02,
                    186:        FL_PLUS         = 0x04,
                    187:        FL_TICK         = 0x08,
                    188:        FL_SPACE        = 0x10,
                    189:        FL_HASH         = 0x20,
                    190:        FL_SIGNED       = 0x40,
                    191:        FL_UPPER        = 0x80,
                    192: } bpf_flag_t;
                    193: 
                    194: /**
                    195:  * Size of format string arguments
                    196:  */
                    197: typedef enum {
                    198:        RNK_CHAR                = -2,
                    199:        RNK_SHORT               = -1,
                    200:        RNK_INT                 =  0,
                    201:        RNK_LONG                =  1,
                    202:        RNK_LONGLONG    =  2,
                    203: 
                    204:        RNK_INTMAX              = RNK_LONGLONG,
                    205:        RNK_SIZE_T              = RNK_LONG,
                    206:        RNK_PTRDIFF_T   = RNK_LONG,
                    207: 
                    208:        RNK_MIN                 = RNK_CHAR,
                    209:        RNK_MAX                 = RNK_LONGLONG,
                    210: } bpf_rank_t;
                    211: 
                    212: /**
                    213:  * Printf specifier Parser state
                    214:  */
                    215: typedef enum {
                    216:        /* Ground state */
                    217:        ST_NORMAL,
                    218:        /* Special flags */
                    219:        ST_FLAGS,
                    220:        /* Field width */
                    221:        ST_WIDTH,
                    222:        /* Field precision */
                    223:        ST_PREC,
                    224:        /* Length or conversion modifiers */
                    225:        ST_MODIFIERS,
                    226: } bpf_state_t;
                    227: 
                    228: #define EMIT(x) ({ if (o<n){*q++ = (x);} o++; })
                    229: 
                    230: static const char lcdigits[] = "0123456789abcdef";
                    231: static const char ucdigits[] = "0123456789ABCDEF";
                    232: 
                    233: /**
                    234:  * Write an integer argument to q, using flags, base, width and precision
                    235:  */
                    236: static size_t format_int(char *q, size_t n, uintmax_t val, bpf_flag_t flags,
                    237:                                                 int base, int width, int prec)
                    238: {
                    239:        char *qq;
                    240:        size_t o = 0, oo;
                    241:        const char *digits;
                    242:        uintmax_t tmpval;
                    243:        int minus = 0;
                    244:        int ndigits = 0, nchars;
                    245:        int tickskip, b4tick;
                    246: 
                    247:        /* Select type of digits */
                    248:        digits = (flags & FL_UPPER) ? ucdigits : lcdigits;
                    249: 
                    250:        /* If signed, separate out the minus */
                    251:        if (flags & FL_SIGNED && (intmax_t) val < 0)
                    252:        {
                    253:                minus = 1;
                    254:                val = (uintmax_t) (-(intmax_t) val);
                    255:        }
                    256: 
                    257:        /* Count the number of digits needed.  This returns zero for 0. */
                    258:        tmpval = val;
                    259:        while (tmpval)
                    260:        {
                    261:                tmpval /= base;
                    262:                ndigits++;
                    263:        }
                    264: 
                    265:        /* Adjust ndigits for size of output */
                    266:        if (flags & FL_HASH && base == 8)
                    267:        {
                    268:                if (prec < ndigits + 1)
                    269:                {
                    270:                        prec = ndigits + 1;
                    271:                }
                    272:        }
                    273: 
                    274:        if (ndigits < prec)
                    275:        {
                    276:                /* Mandatory number padding */
                    277:                ndigits = prec;
                    278:        }
                    279:        else if (val == 0)
                    280:        {
                    281:                /* Zero still requires space */
                    282:                ndigits = 1;
                    283:        }
                    284: 
                    285:        /* For ', figure out what the skip should be */
                    286:        if (flags & FL_TICK)
                    287:        {
                    288:                if (base == 16)
                    289:                {
                    290:                        tickskip = 4;
                    291:                }
                    292:                else
                    293:                {
                    294:                        tickskip = 3;
                    295:                }
                    296:        }
                    297:        else
                    298:        {
                    299:                /* No tick marks */
                    300:                tickskip = ndigits;
                    301:        }
                    302: 
                    303:        /* Tick marks aren't digits, but generated by the number converter */
                    304:        ndigits += (ndigits - 1) / tickskip;
                    305: 
                    306:        /* Now compute the number of nondigits */
                    307:        nchars = ndigits;
                    308: 
                    309:        if (minus || (flags & (FL_PLUS | FL_SPACE)))
                    310:        {
                    311:                /* Need space for sign */
                    312:                nchars++;
                    313:        }
                    314:        if ((flags & FL_HASH) && base == 16)
                    315:        {
                    316:                /* Add 0x for hex */
                    317:                nchars += 2;
                    318:        }
                    319: 
                    320:        /* Emit early space padding */
                    321:        if (!(flags & (FL_MINUS | FL_ZERO)) && width > nchars)
                    322:        {
                    323:                while (width > nchars)
                    324:                {
                    325:                        EMIT(' ');
                    326:                        width--;
                    327:                }
                    328:        }
                    329: 
                    330:        /* Emit nondigits */
                    331:        if (minus)
                    332:        {
                    333:                EMIT('-');
                    334:        }
                    335:        else if (flags & FL_PLUS)
                    336:        {
                    337:                EMIT('+');
                    338:        }
                    339:        else if (flags & FL_SPACE)
                    340:        {
                    341:                EMIT(' ');
                    342:        }
                    343: 
                    344:        if ((flags & FL_HASH) && base == 16)
                    345:        {
                    346:                EMIT('0');
                    347:                EMIT((flags & FL_UPPER) ? 'X' : 'x');
                    348:        }
                    349: 
                    350:        /* Emit zero padding */
                    351:        if ((flags & (FL_MINUS | FL_ZERO)) == FL_ZERO && width > ndigits)
                    352:        {
                    353:                while (width > nchars)
                    354:                {
                    355:                        EMIT('0');
                    356:                        width--;
                    357:                }
                    358:        }
                    359: 
                    360:        /* Generate the number.  This is done from right to left. */
                    361:        /* Advance the pointer to end of number */
                    362:        q += ndigits;
                    363:        o += ndigits;
                    364:        /* Temporary values */
                    365:        qq = q;
                    366:        oo = o;
                    367: 
                    368:        b4tick = tickskip;
                    369:        while (ndigits > 0)
                    370:        {
                    371:                if (!b4tick--)
                    372:                {
                    373:                        qq--;
                    374:                        oo--;
                    375:                        ndigits--;
                    376:                        if (oo < n)
                    377:                        {
                    378:                                *qq = '_';
                    379:                        }
                    380:                        b4tick = tickskip - 1;
                    381:                }
                    382:                qq--;
                    383:                oo--;
                    384:                ndigits--;
                    385:                if (oo < n)
                    386:                {
                    387:                        *qq = digits[val % base];
                    388:                }
                    389:                val /= base;
                    390:        }
                    391: 
                    392:        /* Emit late space padding */
                    393:        while ((flags & FL_MINUS) && width > nchars)
                    394:        {
                    395:                EMIT(' ');
                    396:                width--;
                    397:        }
                    398: 
                    399:        return o;
                    400: }
                    401: 
                    402: /**
                    403:  * Write an double argument to q, using flags, base, width and precision
                    404:  */
                    405: static size_t format_double(char *q, size_t n, double val, bpf_flag_t flags,
                    406:                                                        int base, int width, int prec)
                    407: {
                    408:        char *qq;
                    409:        size_t o = 0, oo;
                    410:        const char *digits;
                    411:        uintmax_t tmpval;
                    412:        int minus = 0;
                    413:        int ndigits = 0, nchars;
                    414: 
                    415:        /* Select type of digits */
                    416:        digits = (flags & FL_UPPER) ? ucdigits : lcdigits;
                    417: 
                    418:        if (prec < 0)
                    419:        {
                    420:                /* default precision */
                    421:                prec = 6;
                    422:        }
                    423:        if (val < 0)
                    424:        {
                    425:                minus = 1;
                    426:        }
                    427: 
                    428:        tmpval = (uintmax_t)fabs(val);
                    429:        while (tmpval)
                    430:        {
                    431:                tmpval /= base;
                    432:                ndigits++;
                    433:        }
                    434:        if (val == 0)
                    435:        {
                    436:                ndigits++;
                    437:        }
                    438: 
                    439:        /* Now compute the number of nondigits */
                    440:        nchars = ndigits;
                    441: 
                    442:        if (prec)
                    443:        {
                    444:                /* Space for decimal-point and digits after that */
                    445:                nchars += prec + 1;
                    446:        }
                    447:        if (minus || (flags & (FL_PLUS | FL_SPACE)))
                    448:        {
                    449:                /* Need space for sign */
                    450:                nchars++;
                    451:        }
                    452:        if ((flags & FL_HASH) && base == 16)
                    453:        {
                    454:                /* Add 0x for hex */
                    455:                nchars += 2;
                    456:        }
                    457: 
                    458:        /* Emit early space padding */
                    459:        if (!(flags & (FL_MINUS | FL_ZERO)) && width > nchars)
                    460:        {
                    461:                while (width > nchars)
                    462:                {
                    463:                        EMIT(' ');
                    464:                        width--;
                    465:                }
                    466:        }
                    467: 
                    468:        /* Emit nondigits */
                    469:        if (minus)
                    470:        {
                    471:                EMIT('-');
                    472:        }
                    473:        else if (flags & FL_PLUS)
                    474:        {
                    475:                EMIT('+');
                    476:        }
                    477:        else if (flags & FL_SPACE)
                    478:        {
                    479:                EMIT(' ');
                    480:        }
                    481: 
                    482:        if ((flags & FL_HASH) && base == 16)
                    483:        {
                    484:                EMIT('0');
                    485:                EMIT((flags & FL_UPPER) ? 'X' : 'x');
                    486:        }
                    487: 
                    488:        /* Emit zero padding */
                    489:        if ((flags & (FL_MINUS | FL_ZERO)) == FL_ZERO && width > ndigits)
                    490:        {
                    491:                while (width > nchars)
                    492:                {
                    493:                        EMIT('0');
                    494:                        width--;
                    495:                }
                    496:        }
                    497: 
                    498:        /* Generate the number.  This is done from right to left. */
                    499:        /* Advance the pointer to end of number */
                    500:        q += ndigits;
                    501:        o += ndigits;
                    502:        /* Temporary values */
                    503:        qq = q;
                    504:        oo = o;
                    505: 
                    506:        tmpval = (uintmax_t)fabs(val);
                    507:        if (!prec)
                    508:        {
                    509:                /* round up if no additional digits */
                    510:                if (fabs(val) - tmpval >= 0.5)
                    511:                {
                    512:                        tmpval++;
                    513:                }
                    514:        }
                    515:        while (ndigits > 0)
                    516:        {
                    517:                qq--;
                    518:                oo--;
                    519:                ndigits--;
                    520:                if (oo < n)
                    521:                {
                    522:                        *qq = digits[tmpval % base];
                    523:                }
                    524:                tmpval /= base;
                    525:        }
                    526: 
                    527:        if (prec)
                    528:        {
                    529:                EMIT('.');
                    530: 
                    531:                q += prec;
                    532:                o += prec;
                    533:                qq = q;
                    534:                oo = o;
                    535: 
                    536:                tmpval = (uintmax_t)(fabs(val) * pow(base, prec));
                    537:                /* round up if required */
                    538:                if (fabs(val) * pow(base, prec) - tmpval >= 0.5)
                    539:                {
                    540:                        tmpval++;
                    541:                }
                    542:                while (prec > 0)
                    543:                {
                    544:                        qq--;
                    545:                        oo--;
                    546:                        prec--;
                    547:                        if (oo < n)
                    548:                        {
                    549:                                *qq = digits[tmpval % base];
                    550:                        }
                    551:                        tmpval /= base;
                    552:                }
                    553:        }
                    554: 
                    555:        /* Emit late space padding */
                    556:        while ((flags & FL_MINUS) && width > nchars)
                    557:        {
                    558:                EMIT(' ');
                    559:                width--;
                    560:        }
                    561: 
                    562:        return o;
                    563: }
                    564: 
                    565: int builtin_vsnprintf(char *buffer, size_t n, const char *format, va_list ap)
                    566: {
                    567:        const char *p = format;
                    568:        char ch;
                    569:        char *q = buffer;
                    570:        /* Number of characters output */
                    571:        size_t o = 0;
                    572:        uintmax_t val = 0;
                    573:        /* Default rank */
                    574:        int rank = RNK_INT;
                    575:        int width = 0;
                    576:        int prec = -1;
                    577:        int base;
                    578:        size_t sz;
                    579:        bpf_flag_t flags = 0;
                    580:        bpf_state_t state = ST_NORMAL;
                    581:        /* %s string argument */
                    582:        const char *sarg;
                    583:        /* %c char argument */
                    584:        char carg;
                    585:        /* String length */
                    586:        int slen;
                    587: 
                    588:        while ((ch = *p++))
                    589:        {
                    590:                switch (state)
                    591:                {
                    592:                        case ST_NORMAL:
                    593:                        {
                    594:                                if (ch == '%')
                    595:                                {
                    596:                                        state = ST_FLAGS;
                    597:                                        flags = 0;
                    598:                                        rank = RNK_INT;
                    599:                                        width = 0;
                    600:                                        prec = -1;
                    601:                                }
                    602:                                else
                    603:                                {
                    604:                                        EMIT(ch);
                    605:                                }
                    606:                                break;
                    607:                        }
                    608:                        case ST_FLAGS:
                    609:                        {
                    610:                                switch (ch)
                    611:                                {
                    612:                                        case '-':
                    613:                                                flags |= FL_MINUS;
                    614:                                                break;
                    615:                                        case '+':
                    616:                                                flags |= FL_PLUS;
                    617:                                                break;
                    618:                                        case '\'':
                    619:                                                flags |= FL_TICK;
                    620:                                                break;
                    621:                                        case ' ':
                    622:                                                flags |= FL_SPACE;
                    623:                                                break;
                    624:                                        case '#':
                    625:                                                flags |= FL_HASH;
                    626:                                                break;
                    627:                                        case '0':
                    628:                                                flags |= FL_ZERO;
                    629:                                                break;
                    630:                                        default:
                    631:                                                state = ST_WIDTH;
                    632:                                                /* Process this character again */
                    633:                                                p--;
                    634:                                                break;
                    635:                                }
                    636:                                break;
                    637:                        }
                    638:                        case ST_WIDTH:
                    639:                        {
                    640:                                if (ch >= '0' && ch <= '9')
                    641:                                {
                    642:                                        width = width * 10 + (ch - '0');
                    643:                                }
                    644:                                else if (ch == '*')
                    645:                                {
                    646:                                        width = va_arg(ap, int);
                    647:                                        if (width < 0)
                    648:                                        {
                    649:                                                width = -width;
                    650:                                                flags |= FL_MINUS;
                    651:                                        }
                    652:                                }
                    653:                                else if (ch == '.')
                    654:                                {
                    655:                                        /* Precision given */
                    656:                                        prec = 0;
                    657:                                        state = ST_PREC;
                    658:                                }
                    659:                                else
                    660:                                {
                    661:                                        state = ST_MODIFIERS;
                    662:                                        /* Process this character again */
                    663:                                        p--;
                    664:                                }
                    665:                                break;
                    666:                        }
                    667:                        case ST_PREC:
                    668:                        {
                    669:                                if (ch >= '0' && ch <= '9')
                    670:                                {
                    671:                                        prec = prec * 10 + (ch - '0');
                    672:                                }
                    673:                                else if (ch == '*')
                    674:                                {
                    675:                                        prec = va_arg(ap, int);
                    676:                                        if (prec < 0)
                    677:                                        {
                    678:                                                prec = -1;
                    679:                                        }
                    680:                                }
                    681:                                else
                    682:                                {
                    683:                                        state = ST_MODIFIERS;
                    684:                                        /* Process this character again */
                    685:                                        p--;
                    686:                                }
                    687:                                break;
                    688:                        }
                    689:                        case ST_MODIFIERS:
                    690:                        {
                    691:                                switch (ch)
                    692:                                {
                    693:                                        /* Length modifiers - nonterminal sequences */
                    694:                                        case 'h':
                    695:                                                rank--;
                    696:                                                break;
                    697:                                        case 'l':
                    698:                                                rank++;
                    699:                                                break;
                    700:                                        case 'j':
                    701:                                                rank = RNK_INTMAX;
                    702:                                                break;
                    703:                                        case 'z':
                    704:                                                rank = RNK_SIZE_T;
                    705:                                                break;
                    706:                                        case 't':
                    707:                                                rank = RNK_PTRDIFF_T;
                    708:                                                break;
                    709:                                        case 'L':
                    710:                                        case 'q':
                    711:                                                rank += 2;
                    712:                                                break;
                    713:                                        default:
                    714:                                        {
                    715:                                                /* Output modifiers - terminal sequences */
                    716: 
                    717:                                                /* Next state will be normal */
                    718:                                                state = ST_NORMAL;
                    719: 
                    720:                                                /* Canonicalize rank */
                    721:                                                if (rank < RNK_MIN)
                    722:                                                {
                    723:                                                        rank = RNK_MIN;
                    724:                                                }
                    725:                                                else if (rank > RNK_MAX)
                    726:                                                {
                    727:                                                        rank = RNK_MAX;
                    728:                                                }
                    729: 
                    730:                                                switch (ch)
                    731:                                                {
                    732:                                                        case 'p':
                    733:                                                        {
                    734:                                                                /* Pointer */
                    735:                                                                base = 16;
                    736:                                                                prec = (CHAR_BIT*sizeof(void *)+3)/4;
                    737:                                                                flags |= FL_HASH;
                    738:                                                                val = (uintmax_t)(uintptr_t)
                    739:                                                                        va_arg(ap, void *);
                    740:                                                                goto is_integer;
                    741:                                                        }
                    742:                                                        case 'd':
                    743:                                                        case 'i':
                    744:                                                        {
                    745:                                                                /* Signed decimal output */
                    746:                                                                base = 10;
                    747:                                                                flags |= FL_SIGNED;
                    748:                                                                switch (rank)
                    749:                                                                {
                    750:                                                                        case RNK_CHAR:
                    751:                                                                                /* Yes, all these casts are
                    752:                                                                                   needed... */
                    753:                                                                                val = (uintmax_t)(intmax_t)(signed char)
                    754:                                                                                                va_arg(ap, signed int);
                    755:                                                                                break;
                    756:                                                                        case RNK_SHORT:
                    757:                                                                                val = (uintmax_t)(intmax_t)(signed short)
                    758:                                                                                                va_arg(ap, signed int);
                    759:                                                                                break;
                    760:                                                                        case RNK_INT:
                    761:                                                                                val = (uintmax_t)(intmax_t)
                    762:                                                                                                va_arg(ap, signed int);
                    763:                                                                                break;
                    764:                                                                        case RNK_LONG:
                    765:                                                                                val = (uintmax_t)(intmax_t)
                    766:                                                                                                va_arg(ap, signed long);
                    767:                                                                                break;
                    768:                                                                        case RNK_LONGLONG:
                    769:                                                                                val = (uintmax_t)(intmax_t)
                    770:                                                                                                va_arg(ap, signed long long);
                    771:                                                                                break;
                    772:                                                                }
                    773:                                                                goto is_integer;
                    774:                                                        }
                    775:                                                        case 'o':
                    776:                                                        {
                    777:                                                                /* Octal */
                    778:                                                                base = 8;
                    779:                                                                goto is_unsigned;
                    780:                                                        }
                    781:                                                        case 'u':
                    782:                                                        {
                    783:                                                                /* Unsigned decimal */
                    784:                                                                base = 10;
                    785:                                                                goto is_unsigned;
                    786:                                                        }
                    787:                                                        case 'X':
                    788:                                                        {
                    789:                                                                /* Upper case hexadecimal */
                    790:                                                                flags |= FL_UPPER;
                    791:                                                                /* fall through */
                    792:                                                        }
                    793:                                                        case 'x':
                    794:                                                        {
                    795:                                                                /* Hexadecimal */
                    796:                                                                base = 16;
                    797:                                                                goto is_unsigned;
                    798:                                                        }
                    799:                                                        is_unsigned:
                    800:                                                        {
                    801:                                                                switch (rank) {
                    802:                                                                        case RNK_CHAR:
                    803:                                                                                val = (uintmax_t)(unsigned char)
                    804:                                                                                                va_arg(ap, unsigned int);
                    805:                                                                                break;
                    806:                                                                        case RNK_SHORT:
                    807:                                                                                val = (uintmax_t)(unsigned short)
                    808:                                                                                                va_arg(ap, unsigned int);
                    809:                                                                                break;
                    810:                                                                        case RNK_INT:
                    811:                                                                                val = (uintmax_t)
                    812:                                                                                                va_arg(ap, unsigned int);
                    813:                                                                                break;
                    814:                                                                        case RNK_LONG:
                    815:                                                                                val = (uintmax_t)
                    816:                                                                                                va_arg(ap, unsigned long);
                    817:                                                                                break;
                    818:                                                                        case RNK_LONGLONG:
                    819:                                                                                val = (uintmax_t)
                    820:                                                                                                va_arg(ap, unsigned long long);
                    821:                                                                                break;
                    822:                                                                }
                    823:                                                                goto is_integer;
                    824:                                                        }
                    825:                                                        is_integer:
                    826:                                                        {
                    827:                                                                sz = format_int(q, (o < n) ? n - o : 0,
                    828:                                                                                                val, flags, base, width, prec);
                    829:                                                                q += sz;
                    830:                                                                o += sz;
                    831:                                                                break;
                    832:                                                        }
                    833:                                                        case 'c':
                    834:                                                        {
                    835:                                                                /* Character */
                    836:                                                                carg = (char)va_arg(ap, int);
                    837:                                                                sarg = &carg;
                    838:                                                                slen = 1;
                    839:                                                                goto is_string;
                    840:                                                        }
                    841:                                                        case 's':
                    842:                                                        {
                    843:                                                                /* String */
                    844:                                                                sarg = va_arg(ap, const char *);
                    845:                                                                sarg = sarg ? sarg : "(null)";
                    846:                                                                slen = prec != -1 ? strnlen(sarg, prec)
                    847:                                                                                                  : strlen(sarg);
                    848:                                                                goto is_string;
                    849:                                                        }
                    850:                                                        case 'm':
                    851:                                                        {
                    852:                                                                /* glibc error string */
                    853:                                                                sarg = strerror(errno);
                    854:                                                                slen = strlen(sarg);
                    855:                                                                goto is_string;
                    856:                                                        }
                    857:                                                        is_string:
                    858:                                                        {
                    859:                                                                char sch;
                    860:                                                                int i;
                    861: 
                    862:                                                                if (prec != -1 && slen > prec)
                    863:                                                                {
                    864:                                                                        slen = prec;
                    865:                                                                }
                    866: 
                    867:                                                                if (width > slen && !(flags & FL_MINUS))
                    868:                                                                {
                    869:                                                                        char pad = (flags & FL_ZERO) ? '0' : ' ';
                    870:                                                                        while (width > slen)
                    871:                                                                        {
                    872:                                                                                EMIT(pad);
                    873:                                                                                width--;
                    874:                                                                        }
                    875:                                                                }
                    876:                                                                for (i = slen; i; i--)
                    877:                                                                {
                    878:                                                                        sch = *sarg++;
                    879:                                                                        EMIT(sch);
                    880:                                                                }
                    881:                                                                if (width > slen && (flags & FL_MINUS))
                    882:                                                                {
                    883:                                                                        while (width > slen)
                    884:                                                                        {
                    885:                                                                                EMIT(' ');
                    886:                                                                                width--;
                    887:                                                                        }
                    888:                                                                }
                    889:                                                                break;
                    890:                                                        }
                    891:                                                        case 'A':
                    892:                                                        {
                    893:                                                                base = 16;
                    894:                                                                flags |= FL_UPPER;
                    895:                                                                goto is_double;
                    896:                                                        }
                    897:                                                        case 'E':
                    898:                                                        case 'G':
                    899:                                                        {
                    900:                                                                /* currently not supported, fall */
                    901:                                                        }
                    902:                                                        case 'F':
                    903:                                                        {
                    904:                                                                base = 10;
                    905:                                                                flags |= FL_UPPER;
                    906:                                                                goto is_double;
                    907:                                                        }
                    908:                                                        case 'a':
                    909:                                                        {
                    910:                                                                base = 16;
                    911:                                                                goto is_double;
                    912:                                                        }
                    913:                                                        case 'e':
                    914:                                                        case 'g':
                    915:                                                        {
                    916:                                                                /* currently not supported, fall */
                    917:                                                        }
                    918:                                                        case 'f':
                    919:                                                        {
                    920:                                                                base = 10;
                    921:                                                                goto is_double;
                    922:                                                        }
                    923:                                                        is_double:
                    924:                                                        {
                    925:                                                                double dval;
                    926: 
                    927:                                                                dval = va_arg(ap, double);
                    928:                                                                if (isinf(dval))
                    929:                                                                {
                    930:                                                                        if (isgreater(dval, 0.0))
                    931:                                                                        {
                    932:                                                                                sarg = flags & FL_UPPER ? "INF" : "inf";
                    933:                                                                        }
                    934:                                                                        else
                    935:                                                                        {
                    936:                                                                                sarg = flags & FL_UPPER ? "-INF" : "-inf";
                    937:                                                                        }
                    938:                                                                        slen = strlen(sarg);
                    939:                                                                        goto is_string;
                    940:                                                                }
                    941:                                                                if (isnan(dval))
                    942:                                                                {
                    943:                                                                        sarg = flags & FL_UPPER ? "NAN" : "nan";
                    944:                                                                        slen = strlen(sarg);
                    945:                                                                        goto is_string;
                    946:                                                                }
                    947:                                                                sz = format_double(q, (o < n) ? n - o : 0,
                    948:                                                                                                dval, flags, base, width, prec);
                    949:                                                                q += sz;
                    950:                                                                o += sz;
                    951:                                                                break;
                    952:                                                        }
                    953:                                                        case 'n':
                    954:                                                        {
                    955:                                                                /* Output the number of characters written */
                    956:                                                                switch (rank)
                    957:                                                                {
                    958:                                                                        case RNK_CHAR:
                    959:                                                                                *va_arg(ap, signed char *) = o;
                    960:                                                                                break;
                    961:                                                                        case RNK_SHORT:
                    962:                                                                                *va_arg(ap, signed short *) = o;
                    963:                                                                                break;
                    964:                                                                        case RNK_INT:
                    965:                                                                                *va_arg(ap, signed int *) = o;
                    966:                                                                                break;
                    967:                                                                        case RNK_LONG:
                    968:                                                                                *va_arg(ap, signed long *) = o;
                    969:                                                                                break;
                    970:                                                                        case RNK_LONGLONG:
                    971:                                                                                *va_arg(ap, signed long long *) = o;
                    972:                                                                                break;
                    973:                                                                }
                    974:                                                                break;
                    975:                                                        }
                    976:                                                        default:
                    977:                                                        {
                    978:                                                                printf_hook_handler_t *handler;
                    979: 
                    980:                                                                handler = hooks->get(hooks, (void*)(uintptr_t)ch);
                    981:                                                                if (handler)
                    982:                                                                {
                    983:                                                                        const void *args[ARGS_MAX];
                    984:                                                                        int i, iargs[ARGS_MAX];
                    985:                                                                        void *pargs[ARGS_MAX];
                    986:                                                                        printf_hook_spec_t spec =  {
                    987:                                                                                .hash = flags & FL_HASH,
                    988:                                                                                .plus = flags & FL_PLUS,
                    989:                                                                                .minus = flags & FL_MINUS,
                    990:                                                                                .width = width,
                    991:                                                                        };
                    992:                                                                        printf_hook_data_t data = {
                    993:                                                                                .q = q,
                    994:                                                                                .n = (o < n) ? n - o : 0,
                    995:                                                                        };
                    996: 
                    997:                                                                        for (i = 0; i < handler->numargs; i++)
                    998:                                                                        {
                    999:                                                                                switch (handler->argtypes[i])
                   1000:                                                                                {
                   1001:                                                                                        case PRINTF_HOOK_ARGTYPE_INT:
                   1002:                                                                                                iargs[i] = va_arg(ap, int);
                   1003:                                                                                                args[i] = &iargs[i];
                   1004:                                                                                                break;
                   1005:                                                                                        case PRINTF_HOOK_ARGTYPE_POINTER:
                   1006:                                                                                                pargs[i] = va_arg(ap, void*);
                   1007:                                                                                                args[i] = &pargs[i];
                   1008:                                                                                                break;
                   1009:                                                                                }
                   1010:                                                                        }
                   1011:                                                                        sz = handler->hook(&data, &spec, args);
                   1012:                                                                        q += sz;
                   1013:                                                                        o += sz;
                   1014:                                                                }
                   1015:                                                                else
                   1016:                                                                {
                   1017:                                                                        /* Anything else, including % */
                   1018:                                                                        EMIT(ch);
                   1019:                                                                }
                   1020:                                                                break;
                   1021:                                                        }
                   1022:                                                }
                   1023:                                        }
                   1024:                                }
                   1025:                        }
                   1026:                }
                   1027:        }
                   1028: 
                   1029:        /* Null-terminate the string */
                   1030:        if (o < n)
                   1031:        {
                   1032:                /* No overflow */
                   1033:                *q = '\0';
                   1034:        }
                   1035:        else if (n > 0)
                   1036:        {
                   1037:                /* Overflow - terminate at end of buffer */
                   1038:                buffer[n - 1] = '\0';
                   1039:        }
                   1040:        return o;
                   1041: }
                   1042: 
                   1043: int builtin_printf(const char *format, ...)
                   1044: {
                   1045:        int written;
                   1046:        va_list args;
                   1047: 
                   1048:        va_start(args, format);
                   1049:        written = builtin_vprintf(format, args);
                   1050:        va_end(args);
                   1051: 
                   1052:        return written;
                   1053: }
                   1054: 
                   1055: int builtin_fprintf(FILE *stream, const char *format, ...)
                   1056: {
                   1057:        int written;
                   1058:        va_list args;
                   1059: 
                   1060:        va_start(args, format);
                   1061:        written = builtin_vfprintf(stream, format, args);
                   1062:        va_end(args);
                   1063: 
                   1064:        return written;
                   1065: }
                   1066: 
                   1067: int builtin_sprintf(char *str, const char *format, ...)
                   1068: {
                   1069:        int written;
                   1070:        va_list args;
                   1071: 
                   1072:        va_start(args, format);
                   1073:        written = builtin_vsnprintf(str, ~(size_t)0, format, args);
                   1074:        va_end(args);
                   1075: 
                   1076:        return written;
                   1077: }
                   1078: 
                   1079: int builtin_snprintf(char *str, size_t size, const char *format, ...)
                   1080: {
                   1081:        int written;
                   1082:        va_list args;
                   1083: 
                   1084:        va_start(args, format);
                   1085:        written = builtin_vsnprintf(str, size, format, args);
                   1086:        va_end(args);
                   1087: 
                   1088:        return written;
                   1089: }
                   1090: 
                   1091: int builtin_asprintf(char **str, const char *format, ...)
                   1092: {
                   1093:        int written;
                   1094:        va_list args;
                   1095: 
                   1096:        va_start(args, format);
                   1097:        written = builtin_vasprintf(str, format, args);
                   1098:        va_end(args);
                   1099: 
                   1100:        return written;
                   1101: }
                   1102: 
                   1103: int builtin_vprintf(const char *format, va_list ap)
                   1104: {
                   1105:        return builtin_vfprintf(stdout, format, ap);
                   1106: }
                   1107: 
                   1108: #ifdef WIN32
                   1109: /**
                   1110:  * Set TTY color on Windows consoles
                   1111:  */
                   1112: static void set_console_color(HANDLE handle, int color)
                   1113: {
                   1114:        CONSOLE_SCREEN_BUFFER_INFO info;
                   1115:        struct {
                   1116:                /* escape code */
                   1117:                int color;
                   1118:                /* windows console color combination */
                   1119:                WORD attributes;
                   1120:        } maps[] = {
                   1121:                { 30,   0                                                                                                                       },
                   1122:                { 31,   FOREGROUND_RED                                                                                          },
                   1123:                { 32,   FOREGROUND_GREEN                                                                                        },
                   1124:                { 33,   FOREGROUND_GREEN | FOREGROUND_RED                                                       },
                   1125:                { 34,   FOREGROUND_BLUE | FOREGROUND_INTENSITY                                          },
                   1126:                { 35,   FOREGROUND_RED | FOREGROUND_BLUE                                                        },
                   1127:                { 36,   FOREGROUND_GREEN | FOREGROUND_BLUE                                                      },
                   1128:                { 37,   FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED                     },
                   1129:                { 39,   FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED                     },
                   1130:                { 40,   0                                                                                                                       },
                   1131:                { 41,   BACKGROUND_RED                                                                                          },
                   1132:                { 42,   BACKGROUND_GREEN                                                                                        },
                   1133:                { 43,   BACKGROUND_GREEN | BACKGROUND_RED                                                       },
                   1134:                { 44,   BACKGROUND_BLUE                                                                                         },
                   1135:                { 45,   BACKGROUND_RED | BACKGROUND_BLUE                                                        },
                   1136:                { 46,   BACKGROUND_GREEN | BACKGROUND_BLUE                                                      },
                   1137:                { 47,   BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED                     },
                   1138:                { 49,   0                                                                                                                       },
                   1139:        };
                   1140:        int i;
                   1141: 
                   1142:        if (GetConsoleScreenBufferInfo(handle, &info))
                   1143:        {
                   1144:                if (color < 40)
                   1145:                {
                   1146:                        info.wAttributes &= ~(FOREGROUND_BLUE | FOREGROUND_GREEN |
                   1147:                                                                  FOREGROUND_RED | FOREGROUND_INTENSITY);
                   1148:                }
                   1149:                else
                   1150:                {
                   1151:                        info.wAttributes &= ~(BACKGROUND_BLUE | BACKGROUND_GREEN |
                   1152:                                                                  BACKGROUND_RED | BACKGROUND_INTENSITY);
                   1153:                }
                   1154:                for (i = 0; i < countof(maps); i++)
                   1155:                {
                   1156:                        if (maps[i].color == color)
                   1157:                        {
                   1158:                                info.wAttributes |= maps[i].attributes;
                   1159:                                SetConsoleTextAttribute(handle, info.wAttributes);
                   1160:                                break;
                   1161:                        }
                   1162:                }
                   1163:        }
                   1164: }
                   1165: 
                   1166: int builtin_vfprintf(FILE *stream, const char *format, va_list ap)
                   1167: {
                   1168:        char buf[PRINTF_BUF_LEN], *pos, *stop;
                   1169:        HANDLE handle;
                   1170:        int len, total;
                   1171:        DWORD clen, mode;
                   1172: 
                   1173:        total = len = builtin_vsnprintf(buf, sizeof(buf), format, ap);
                   1174:        switch (fileno(stream))
                   1175:        {
                   1176:                case 1:
                   1177:                        handle = GetStdHandle(STD_OUTPUT_HANDLE);
                   1178:                        break;
                   1179:                case 2:
                   1180:                        handle = GetStdHandle(STD_ERROR_HANDLE);
                   1181:                        break;
                   1182:                default:
                   1183:                        handle = INVALID_HANDLE_VALUE;
                   1184:                        break;
                   1185:        }
                   1186:        /* GetConsoleMode fails if output redirected */
                   1187:        if (handle == INVALID_HANDLE_VALUE || !GetConsoleMode(handle, &mode))
                   1188:        {
                   1189:                return fwrite(buf, 1, len, stream);
                   1190:        }
                   1191:        while (len)
                   1192:        {
                   1193:                pos = &buf[total - len];
                   1194:                if (len > 4)
                   1195:                {
                   1196:                        if (pos[0] == '\e' && pos[1] == '[' && pos[4] == 'm')
                   1197:                        {
                   1198:                                if (isdigit(pos[3]))
                   1199:                                {
                   1200:                                        if (pos[2] == '3' || pos[2] == '4')
                   1201:                                        {
                   1202:                                                set_console_color(handle,
                   1203:                                                                        (pos[2] - '0') * 10 + pos[3] - '0');
                   1204:                                                len -= 5;
                   1205:                                                continue;
                   1206:                                        }
                   1207:                                }
                   1208:                        }
                   1209:                }
                   1210:                stop = memchr(pos + 1, '\e', len);
                   1211:                if (stop)
                   1212:                {
                   1213:                        clen = stop - pos;
                   1214:                }
                   1215:                else
                   1216:                {
                   1217:                        clen = len;
                   1218:                }
                   1219:                if (clen && !WriteConsole(handle, pos, clen, &clen, NULL))
                   1220:                {
                   1221:                        break;
                   1222:                }
                   1223:                len -= clen;
                   1224:        }
                   1225:        return total - len;
                   1226: }
                   1227: 
                   1228: #else /* !WIN32 */
                   1229: 
                   1230: int builtin_vfprintf(FILE *stream, const char *format, va_list ap)
                   1231: {
                   1232:        char buf[PRINTF_BUF_LEN];
                   1233:        int len;
                   1234: 
                   1235:        len = builtin_vsnprintf(buf, sizeof(buf), format, ap);
                   1236:        return fwrite(buf, 1, len, stream);
                   1237: }
                   1238: 
                   1239: #endif /* !WIN32 */
                   1240: 
                   1241: int builtin_vsprintf(char *str, const char *format, va_list ap)
                   1242: {
                   1243:        return builtin_vsnprintf(str, ~(size_t)0, format, ap);
                   1244: }
                   1245: 
                   1246: int builtin_vasprintf(char **str, const char *format, va_list ap)
                   1247: {
                   1248:        char buf[PRINTF_BUF_LEN];
                   1249:        int len;
                   1250: 
                   1251:        len = builtin_vsnprintf(buf, sizeof(buf), format, ap);
                   1252:        *str = strdup(buf);
                   1253:        return len;
                   1254: }
                   1255: 
                   1256: METHOD(printf_hook_t, destroy, void,
                   1257:        private_printf_hook_t *this)
                   1258: {
                   1259:        enumerator_t *enumerator;
                   1260:        printf_hook_handler_t *handler;
                   1261: 
                   1262:        enumerator = hooks->create_enumerator(hooks);
                   1263:        while (enumerator->enumerate(enumerator, NULL, &handler))
                   1264:        {
                   1265:                free(handler);
                   1266:        }
                   1267:        enumerator->destroy(enumerator);
                   1268: 
                   1269:        hooks->destroy(hooks);
                   1270: 
                   1271:        free(this);
                   1272: }
                   1273: 
                   1274: /*
                   1275:  * see header file
                   1276:  */
                   1277: printf_hook_t *printf_hook_create()
                   1278: {
                   1279:        private_printf_hook_t *this;
                   1280: 
                   1281:        INIT(this,
                   1282:                .public = {
                   1283:                        .add_handler = _add_handler,
                   1284:                        .destroy = _destroy,
                   1285:                },
                   1286:        );
                   1287: 
                   1288:        hooks = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 8);
                   1289: 
                   1290:        return &this->public;
                   1291: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>