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

1.1       misho       1: /*
                      2:  * Copyright (C) 2009-2013 Tobias Brunner
                      3:  * Copyright (C) 2006-2008 Martin Willi
                      4:  * HSR Hochschule fuer Technik Rapperswil
                      5:  *
                      6:  * This program is free software; you can redistribute it and/or modify it
                      7:  * under the terms of the GNU General Public License as published by the
                      8:  * Free Software Foundation; either version 2 of the License, or (at your
                      9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     10:  *
                     11:  * This program is distributed in the hope that it will be useful, but
                     12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     14:  * for more details.
                     15:  */
                     16: 
                     17: #include "printf_hook.h"
                     18: 
                     19: #include <utils/utils.h>
                     20: #include <utils/debug.h>
                     21: #include <threading/thread_value.h>
                     22: 
                     23: #include <vstr.h>
                     24: #include <string.h>
                     25: #include <unistd.h>
                     26: #include <errno.h>
                     27: 
                     28: typedef struct private_printf_hook_t private_printf_hook_t;
                     29: typedef struct printf_hook_handler_t printf_hook_handler_t;
                     30: 
                     31: #define PRINTF_BUF_LEN 8192
                     32: #define ARGS_MAX 3
                     33: 
                     34: /**
                     35:  * private data of printf_hook
                     36:  */
                     37: struct private_printf_hook_t {
                     38: 
                     39:        /**
                     40:         * public functions
                     41:         */
                     42:        printf_hook_t public;
                     43: };
                     44: 
                     45: /**
                     46:  * struct with information about a registered handler
                     47:  */
                     48: struct printf_hook_handler_t {
                     49: 
                     50:        /**
                     51:         * callback function
                     52:         */
                     53:        printf_hook_function_t hook;
                     54: 
                     55:        /**
                     56:         * number of arguments
                     57:         */
                     58:        int numargs;
                     59: 
                     60:        /**
                     61:         * types of the arguments, VSTR_TYPE_FMT_*
                     62:         */
                     63:        int argtypes[ARGS_MAX];
                     64: 
                     65:        /**
                     66:         * name required for Vstr
                     67:         */
                     68:        char *name;
                     69: };
                     70: 
                     71: /**
                     72:  * Data to pass to a printf hook.
                     73:  */
                     74: struct printf_hook_data_t {
                     75: 
                     76:        /**
                     77:         * Base to append printf to
                     78:         */
                     79:        Vstr_base *base;
                     80: 
                     81:        /**
                     82:         * Position in base to write to
                     83:         */
                     84:        size_t pos;
                     85: };
                     86: 
                     87: /* A-Z | 6 other chars | a-z */
                     88: static printf_hook_handler_t *printf_hooks[58];
                     89: 
                     90: #define SPEC_TO_INDEX(spec) ((int)(spec) - (int)'A')
                     91: 
                     92: /**
                     93:  * These are used below, whenever the public wrapper functions are called before
                     94:  * initialization or after destruction.
                     95:  */
                     96: #undef vprintf
                     97: #undef vfprintf
                     98: #undef vsnprintf
                     99: 
                    100: /**
                    101:  * Vstr variant of print_in_hook()
                    102:  */
                    103: size_t print_in_hook(printf_hook_data_t *data, char *fmt, ...)
                    104: {
                    105:        size_t written;
                    106:        va_list args;
                    107: 
                    108:        va_start(args, fmt);
                    109:        written = vstr_add_vfmt(data->base, data->pos, fmt, args);
                    110:        va_end(args);
                    111: 
                    112:        data->pos += written;
                    113:        return written;
                    114: }
                    115: 
                    116: /**
                    117:  * Vstr custom format specifier callback function.
                    118:  */
                    119: static int custom_fmt_cb(Vstr_base *base, size_t pos, Vstr_fmt_spec *fmt_spec)
                    120: {
                    121:        int i;
                    122:        const void *args[ARGS_MAX];
                    123:        printf_hook_spec_t spec;
                    124:        printf_hook_handler_t *handler;
                    125:        printf_hook_data_t data = {
                    126:                .base = base,
                    127:                .pos = pos,
                    128:        };
                    129: 
                    130:        handler = printf_hooks[SPEC_TO_INDEX(fmt_spec->name[0])];
                    131:        for (i = 0; i < handler->numargs; i++)
                    132:        {
                    133:                switch (handler->argtypes[i])
                    134:                {
                    135:                        case VSTR_TYPE_FMT_INT:
                    136:                                args[i] = VSTR_FMT_CB_ARG_PTR(fmt_spec, i);
                    137:                                break;
                    138:                        case VSTR_TYPE_FMT_PTR_VOID:
                    139:                                args[i] = &VSTR_FMT_CB_ARG_PTR(fmt_spec, i);
                    140:                                break;
                    141:                }
                    142:        }
                    143: 
                    144:        spec.hash = fmt_spec->fmt_hash;
                    145:        spec.plus = fmt_spec->fmt_plus;
                    146:        spec.minus = fmt_spec->fmt_minus;
                    147:        spec.width = fmt_spec->obj_field_width;
                    148: 
                    149:        handler->hook(&data, &spec, args);
                    150: 
                    151:        return 1;
                    152: }
                    153: 
                    154: /**
                    155:  * Add a custom format handler to the given Vstr_conf object
                    156:  */
                    157: static void vstr_fmt_add_handler(Vstr_conf *conf, printf_hook_handler_t *handler)
                    158: {
                    159:        int *at;
                    160: 
                    161:        at = handler->argtypes;
                    162:        switch (handler->numargs)
                    163:        {
                    164:                case 1:
                    165:                        vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
                    166:                                                 VSTR_TYPE_FMT_END);
                    167:                        break;
                    168:                case 2:
                    169:                        vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
                    170:                                                 at[1], VSTR_TYPE_FMT_END);
                    171:                        break;
                    172:                case 3:
                    173:                        vstr_fmt_add(conf, handler->name, custom_fmt_cb, at[0],
                    174:                                                 at[1], at[2], VSTR_TYPE_FMT_END);
                    175:                        break;
                    176:        }
                    177: }
                    178: 
                    179: /**
                    180:  * Thread specific vstr config
                    181:  */
                    182: static thread_value_t *vstr_conf = NULL;
                    183: 
                    184: /**
                    185:  * Create vstr config for current thread
                    186:  */
                    187: static Vstr_conf *create_vstr_conf()
                    188: {
                    189:        Vstr_conf *conf;
                    190:        int i;
                    191: 
                    192:        conf = vstr_make_conf();
                    193:        vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_FMT_CHAR_ESC, '%');
                    194:        vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_TYPE_GRPALLOC_CACHE,
                    195:                                                 VSTR_TYPE_CNTL_CONF_GRPALLOC_CSTR);
                    196:        vstr_cntl_conf(conf, VSTR_CNTL_CONF_SET_NUM_BUF_SZ, PRINTF_BUF_LEN);
                    197: 
                    198:        for (i = 0; i < countof(printf_hooks); i++)
                    199:        {
                    200:                if (printf_hooks[i])
                    201:                {
                    202:                        vstr_fmt_add_handler(conf, printf_hooks[i]);
                    203:                }
                    204:        }
                    205:        return conf;
                    206: }
                    207: 
                    208: /**
                    209:  * Get vstr config of current thread
                    210:  */
                    211: static inline Vstr_conf *get_vstr_conf()
                    212: {
                    213:        Vstr_conf *conf = NULL;
                    214: 
                    215:        if (vstr_conf)
                    216:        {
                    217:                conf = (Vstr_conf*)vstr_conf->get(vstr_conf);
                    218:                if (!conf)
                    219:                {
                    220:                        conf = create_vstr_conf();
                    221:                        vstr_conf->set(vstr_conf, conf);
                    222:                }
                    223:        }
                    224:        return conf;
                    225: }
                    226: 
                    227: /**
                    228:  * Wrapper functions for printf and alike
                    229:  */
                    230: int vstr_wrapper_printf(const char *format, ...)
                    231: {
                    232:        int written;
                    233:        va_list args;
                    234:        va_start(args, format);
                    235:        written = vstr_wrapper_vprintf(format, args);
                    236:        va_end(args);
                    237:        return written;
                    238: }
                    239: 
                    240: int vstr_wrapper_fprintf(FILE *stream, const char *format, ...)
                    241: {
                    242:        int written;
                    243:        va_list args;
                    244:        va_start(args, format);
                    245:        written = vstr_wrapper_vfprintf(stream, format, args);
                    246:        va_end(args);
                    247:        return written;
                    248: }
                    249: 
                    250: int vstr_wrapper_sprintf(char *str, const char *format, ...)
                    251: {
                    252:        int written;
                    253:        va_list args;
                    254:        va_start(args, format);
                    255:        written = vstr_wrapper_vsprintf(str, format, args);
                    256:        va_end(args);
                    257:        return written;
                    258: }
                    259: 
                    260: int vstr_wrapper_snprintf(char *str, size_t size, const char *format, ...)
                    261: {
                    262:        int written;
                    263:        va_list args;
                    264:        va_start(args, format);
                    265:        written = vstr_wrapper_vsnprintf(str, size, format, args);
                    266:        va_end(args);
                    267:        return written;
                    268: }
                    269: 
                    270: int vstr_wrapper_asprintf(char **str, const char *format, ...)
                    271: {
                    272:        int written;
                    273:        va_list args;
                    274:        va_start(args, format);
                    275:        written = vstr_wrapper_vasprintf(str, format, args);
                    276:        va_end(args);
                    277:        return written;
                    278: }
                    279: 
                    280: static inline int vstr_wrapper_vprintf_internal(Vstr_conf *conf, FILE *stream,
                    281:                                                                                                const char *format,
                    282:                                                                                                va_list args)
                    283: {
                    284:        struct iovec *iov;
                    285:        int iovcnt, written = 0;
                    286:        Vstr_base *s;
                    287: 
                    288:        s = vstr_make_base(conf);
                    289:        vstr_add_vfmt(s, 0, format, args);
                    290:        if (vstr_export_iovec_ptr_all(s, &iov, &iovcnt))
                    291:        {
                    292:                while (iovcnt--)
                    293:                {
                    294:                        if (iov->iov_base)
                    295:                        {
                    296:                                written += fwrite(iov->iov_base, 1, iov->iov_len, stream);
                    297:                        }
                    298:                        iov++;
                    299:                }
                    300:        }
                    301:        vstr_free_base(s);
                    302:        return written;
                    303: }
                    304: 
                    305: int vstr_wrapper_vprintf(const char *format, va_list args)
                    306: {
                    307:        Vstr_conf *conf;
                    308: 
                    309:        conf = get_vstr_conf();
                    310:        if (conf)
                    311:        {
                    312:                return vstr_wrapper_vprintf_internal(conf, stdout, format, args);
                    313:        }
                    314:        return vprintf(format, args);
                    315: }
                    316: 
                    317: int vstr_wrapper_vfprintf(FILE *stream, const char *format, va_list args)
                    318: {
                    319:        Vstr_conf *conf;
                    320: 
                    321:        conf = get_vstr_conf();
                    322:        if (conf)
                    323:        {
                    324:                return vstr_wrapper_vprintf_internal(conf, stream, format, args);
                    325:        }
                    326:        return vfprintf(stream, format, args);
                    327: }
                    328: 
                    329: static inline int vstr_wrapper_vsnprintf_internal(char *str, size_t size,
                    330:                                                                                                  const char *format,
                    331:                                                                                                  va_list args)
                    332: {
                    333:        Vstr_conf *conf;
                    334:        Vstr_base *s;
                    335:        int written;
                    336: 
                    337:        conf = get_vstr_conf();
                    338:        if (conf)
                    339:        {
                    340:                s = vstr_make_base(conf);
                    341:                vstr_add_vfmt(s, 0, format, args);
                    342:                written = s->len;
                    343:                vstr_export_cstr_buf(s, 1, s->len, str, (size > 0) ? size : s->len + 1);
                    344:                vstr_free_base(s);
                    345:                return written;
                    346:        }
                    347:        return vsnprintf(str, size, format, args);
                    348: }
                    349: 
                    350: int vstr_wrapper_vsprintf(char *str, const char *format, va_list args)
                    351: {
                    352:        return vstr_wrapper_vsnprintf_internal(str, 0, format, args);
                    353: }
                    354: 
                    355: int vstr_wrapper_vsnprintf(char *str, size_t size, const char *format,
                    356:                                                   va_list args)
                    357: {
                    358:        if (size > 0)
                    359:        {
                    360:                return vstr_wrapper_vsnprintf_internal(str, size, format, args);
                    361:        }
                    362:        return 0;
                    363: }
                    364: 
                    365: int vstr_wrapper_vasprintf(char **str, const char *format, va_list args)
                    366: {
                    367:        size_t len = 100;
                    368:        int written;
                    369: 
                    370:        *str = malloc(len);
                    371:        while (TRUE)
                    372:        {
                    373:                va_list ac;
                    374:                va_copy(ac, args);
                    375:                written = vstr_wrapper_vsnprintf_internal(*str, len, format, ac);
                    376:                va_end(ac);
                    377:                if (written < len)
                    378:                {
                    379:                        break;
                    380:                }
                    381:                len = written + 1;
                    382:                *str = realloc(*str, len);
                    383:        }
                    384:        return written;
                    385: }
                    386: 
                    387: METHOD(printf_hook_t, add_handler, void,
                    388:        private_printf_hook_t *this, char spec, printf_hook_function_t hook, ...)
                    389: {
                    390:        int i = -1;
                    391:        bool failed = FALSE;
                    392:        printf_hook_handler_t *handler;
                    393:        printf_hook_argtype_t argtype;
                    394:        va_list args;
                    395: 
                    396:        if (SPEC_TO_INDEX(spec) <= -1 ||
                    397:                SPEC_TO_INDEX(spec) >= countof(printf_hooks))
                    398:        {
                    399:                DBG1(DBG_LIB, "'%c' is not a valid printf hook specifier, "
                    400:                         "not registered!", spec);
                    401:                return;
                    402:        }
                    403: 
                    404:        INIT(handler,
                    405:                .hook = hook,
                    406:        );
                    407: 
                    408:        va_start(args, hook);
                    409:        while (!failed)
                    410:        {
                    411:                argtype = va_arg(args, printf_hook_argtype_t);
                    412:                if (argtype == PRINTF_HOOK_ARGTYPE_END)
                    413:                {
                    414:                        break;
                    415:                }
                    416:                if (++i >= ARGS_MAX)
                    417:                {
                    418:                        DBG1(DBG_LIB, "Too many arguments for printf hook with "
                    419:                                 "specifier '%c', not registered!", spec);
                    420:                        failed = TRUE;
                    421:                        break;
                    422:                }
                    423:                switch (argtype)
                    424:                {
                    425:                        case PRINTF_HOOK_ARGTYPE_INT:
                    426:                                handler->argtypes[i] = VSTR_TYPE_FMT_INT;
                    427:                                break;
                    428:                        case PRINTF_HOOK_ARGTYPE_POINTER:
                    429:                                handler->argtypes[i] = VSTR_TYPE_FMT_PTR_VOID;
                    430:                                break;
                    431:                        default:
                    432:                                DBG1(DBG_LIB, "Invalid printf hook arg type for '%c'", spec);
                    433:                                failed = TRUE;
                    434:                                break;
                    435:                }
                    436:        }
                    437:        va_end(args);
                    438: 
                    439:        handler->numargs = i + 1;
                    440: 
                    441:        if (!failed && handler->numargs > 0)
                    442:        {
                    443:                Vstr_conf *conf = get_vstr_conf();
                    444:                handler->name = malloc(2);
                    445:                handler->name[0] = spec;
                    446:                handler->name[1] = '\0';
                    447:                vstr_fmt_add_handler(conf, handler);
                    448:                printf_hooks[SPEC_TO_INDEX(spec)] = handler;
                    449:        }
                    450:        else
                    451:        {
                    452:                free(handler);
                    453:        }
                    454: }
                    455: 
                    456: METHOD(printf_hook_t, destroy, void,
                    457:        private_printf_hook_t *this)
                    458: {
                    459:        int i;
                    460:        Vstr_conf *conf;
                    461:        printf_hook_handler_t *handler;
                    462: 
                    463:        conf = get_vstr_conf();
                    464:        for (i = 0; i < countof(printf_hooks); ++i)
                    465:        {
                    466:                handler = printf_hooks[i];
                    467:                if (handler)
                    468:                {
                    469:                        vstr_fmt_del(conf, handler->name);
                    470:                        free(handler->name);
                    471:                        free(handler);
                    472:                }
                    473:        }
                    474: 
                    475:        /* freeing the Vstr_conf of the main thread */
                    476:        vstr_conf->destroy(vstr_conf);
                    477:        vstr_conf = NULL;
                    478:        vstr_exit();
                    479:        free(this);
                    480: }
                    481: 
                    482: /*
                    483:  * see header file
                    484:  */
                    485: printf_hook_t *printf_hook_create()
                    486: {
                    487:        private_printf_hook_t *this;
                    488: 
                    489:        INIT(this,
                    490:                .public = {
                    491:                        .add_handler = _add_handler,
                    492:                        .destroy = _destroy,
                    493:                },
                    494:        );
                    495: 
                    496:        memset(printf_hooks, 0, sizeof(printf_hooks));
                    497: 
                    498:        if (!vstr_init())
                    499:        {
                    500:                DBG1(DBG_LIB, "failed to initialize Vstr library!");
                    501:                free(this);
                    502:                return NULL;
                    503:        }
                    504:        vstr_conf = thread_value_create((thread_cleanup_t)vstr_free_conf);
                    505: 
                    506:        return &this->public;
                    507: }

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