diff options
Diffstat (limited to 'src/args.c')
-rw-r--r-- | src/args.c | 1066 |
1 files changed, 1066 insertions, 0 deletions
diff --git a/src/args.c b/src/args.c new file mode 100644 index 0000000..4bb1252 --- /dev/null +++ b/src/args.c @@ -0,0 +1,1066 @@ +/* + Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com> + + This file is part of the latrace. + + The latrace is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + The latrace is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the latrace (file COPYING). If not, see + <http://www.gnu.org/licenses/>. +*/ + + +#include <stdlib.h> +#include <string.h> +#include <search.h> +#include <setjmp.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> + +#include "config.h" + + +#define YY_BUF_SIZE 16384 +#define MAX_INCLUDE_DEPTH 10 +#define LT_EQUAL " = " + + +extern int errno; + +typedef struct yy_buffer_state *YY_BUFFER_STATE; +YY_BUFFER_STATE yy_create_buffer(FILE *file, int size); +extern FILE *yyin; + +int yyparse(); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer); +void yy_delete_buffer(YY_BUFFER_STATE b); + +int lt_args_parse_init(struct lt_config_shared *cfg); +static struct lt_args_include include_stack[MAX_INCLUDE_DEPTH]; +static int include_stack_ptr = 0; +static int enum_init = 0; + + +/* hardcoded POD types */ +static struct lt_arg args_def_pod[] = { + { + .dtype = LT_ARGS_DTYPE_POD, + .type_id = LT_ARGS_TYPEID_VOID, + .type_len = sizeof(void), + .type_name = "void", + .pointer = 0, + .name = "", + .mmbcnt = 0, + .arch = NULL, + .en = NULL, + .args_head = NULL, + .args_list = { NULL, NULL } + }, + { + .dtype = LT_ARGS_DTYPE_POD, + .type_id = LT_ARGS_TYPEID_SHORT, + .type_len = sizeof(short), + .type_name = "short", + .pointer = 0, + .name = "", + .mmbcnt = 0, + .arch = NULL, + .en = NULL, + .args_head = NULL, + .args_list = { NULL, NULL } + }, + { + .dtype = LT_ARGS_DTYPE_POD, + .type_id = LT_ARGS_TYPEID_USHORT, + .type_len = sizeof(unsigned short), + .type_name = "u_short", + .pointer = 0, + .name = "", + .mmbcnt = 0, + .arch = NULL, + .en = NULL, + .args_head = NULL, + .args_list = { NULL, NULL } + }, + { + .dtype = LT_ARGS_DTYPE_POD, + .type_id = LT_ARGS_TYPEID_INT, + .type_len = sizeof(int), + .type_name = "int", + .pointer = 0, + .name = "", + .mmbcnt = 0, + .arch = NULL, + .en = NULL, + .args_head = NULL, + .args_list = { NULL, NULL } + }, + { + .dtype = LT_ARGS_DTYPE_POD, + .type_id = LT_ARGS_TYPEID_UINT, + .type_len = sizeof(unsigned int), + .type_name = "u_int", + .pointer = 0, + .name = "", + .mmbcnt = 0, + .arch = NULL, + .en = NULL, + .args_head = NULL, + .args_list = { NULL, NULL } + }, + { + .dtype = LT_ARGS_DTYPE_POD, + .type_id = LT_ARGS_TYPEID_LONG, + .type_len = sizeof(long), + .type_name = "long", + .pointer = 0, + .name = "", + .mmbcnt = 0, + .arch = NULL, + .en = NULL, + .args_head = NULL, + .args_list = { NULL, NULL } + }, + { + .dtype = LT_ARGS_DTYPE_POD, + .type_id = LT_ARGS_TYPEID_ULONG, + .type_len = sizeof(unsigned long), + .type_name = "u_long", + .pointer = 0, + .name = "", + .mmbcnt = 0, + .arch = NULL, + .en = NULL, + .args_head = NULL, + .args_list = { NULL, NULL } + }, + { + .dtype = LT_ARGS_DTYPE_POD, + .type_id = LT_ARGS_TYPEID_CHAR, + .type_len = sizeof(char), + .type_name = "char", + .pointer = 0, + .name = "", + .mmbcnt = 0, + .arch = NULL, + .en = NULL, + .args_head = NULL, + .args_list = { NULL, NULL } + }, + { + .dtype = LT_ARGS_DTYPE_POD, + .type_id = LT_ARGS_TYPEID_UCHAR, + .type_len = sizeof(unsigned char), + .type_name = "u_char", + .pointer = 0, + .name = "", + .mmbcnt = 0, + .arch = NULL, + .en = NULL, + .args_head = NULL, + .args_list = { NULL, NULL } + }, + { + .dtype = LT_ARGS_DTYPE_POD, + .type_id = LT_ARGS_TYPEID_LLONG, + .type_len = sizeof(long long), + .type_name = "llong", + .pointer = 0, + .name = "", + .mmbcnt = 0, + .arch = NULL, + .en = NULL, + .args_head = NULL, + .args_list = { NULL, NULL } + }, + { + .dtype = LT_ARGS_DTYPE_POD, + .type_id = LT_ARGS_TYPEID_ULLONG, + .type_len = sizeof(unsigned long long), + .type_name = "u_llong", + .pointer = 0, + .name = "", + .mmbcnt = 0, + .arch = NULL, + .en = NULL, + .args_head = NULL, + .args_list = { NULL, NULL } + }, + { + .dtype = LT_ARGS_DTYPE_POD, + .type_id = LT_ARGS_TYPEID_DOUBLE, + .type_len = sizeof(double), + .type_name = "double", + .pointer = 0, + .name = "", + .mmbcnt = 0, + .arch = NULL, + .en = NULL, + .args_head = NULL, + .args_list = { NULL, NULL } + }, + { + .dtype = LT_ARGS_DTYPE_POD, + .type_id = LT_ARGS_TYPEID_FLOAT, + .type_len = sizeof(float), + .type_name = "float", + .pointer = 0, + .name = "", + .mmbcnt = 0, + .arch = NULL, + .en = NULL, + .args_head = NULL, + .args_list = { NULL, NULL } + }, +}; + +#define LT_ARGS_DEF_POD_NUM (sizeof(args_def_pod)/sizeof(struct lt_arg)) + +/* struct, typedef, enum */ +static struct lt_arg args_def_struct[LT_ARGS_DEF_STRUCT_NUM]; +static struct lt_arg args_def_typedef[LT_ARGS_DEF_TYPEDEF_NUM]; +static int args_def_struct_cnt = 0; +static int args_def_typedef_cnt = 0; +static struct hsearch_data args_enum_tab; + +static struct lt_enum* getenum(struct lt_config_shared *cfg, char *name) +{ + struct lt_enum *en; + ENTRY e, *ep; + + PRINT_VERBOSE(cfg->verbose, 1, "request for <%s>\n", name); + + if (!enum_init) { + PRINT_VERBOSE(cfg->verbose, 1, "no enum added so far\n", name); + return NULL; + } + + e.key = name; + hsearch_r(e, FIND, &ep, &args_enum_tab); + + if (!ep) { + PRINT_VERBOSE(cfg->verbose, 1, "failed to find enum <%s>\n", name); + return NULL; + } + + en = (struct lt_enum*) ep->data; + + PRINT_VERBOSE(cfg->verbose, 1, "found %p <%s>\n", en, en->name); + return en; +} + +static int enum_comp(const void *ep1, const void *ep2) +{ + struct lt_enum_elem *e1 = (struct lt_enum_elem*) ep1; + struct lt_enum_elem *e2 = (struct lt_enum_elem*) ep2; + + return e1->val - e2->val; +} + +static struct lt_enum_elem* get_enumelem(struct lt_config_shared *cfg, + long val, struct lt_enum *en) +{ + struct lt_enum_elem key; + key.val = val; + + PRINT_VERBOSE(cfg->verbose, 1, "looking for %p <%s> value %ld\n", + en, en->name, val); + + return bsearch(&key, en->elems, en->cnt, + sizeof(struct lt_enum_elem), enum_comp); +} + +int lt_args_add_enum(struct lt_config_shared *cfg, char *name, + struct lt_list_head *h) +{ + ENTRY e, *ep; + struct lt_enum_elem *elem, *last = NULL; + struct lt_enum *en; + int i = 0; + + if (NULL == (en = malloc(sizeof(*en)))) + return -1; + + memset(en, 0x0, sizeof(*en)); + en->name = name; + + /* Initialize the hash table holding enum names */ + if (!enum_init) { + if (!hcreate_r(LT_ARGS_DEF_ENUM_NUM, &args_enum_tab)) { + perror("failed to create has table:"); + return -1; + } + enum_init = 1; + } + + e.key = en->name; + e.data = en; + + if (!hsearch_r(e, ENTER, &ep, &args_enum_tab)) { + perror("hsearch_r failed"); + free(en); + /* we dont want to exit just because + we ran out of our symbol limit */ + PRINT_VERBOSE(cfg->verbose, 3, + "reach the enum number limit %u\n", + LT_ARGS_DEF_ENUM_NUM); + } + + /* We've got enum inside the hash, let's prepare the enum itself. + The 'elems' field is going to be the qsorted list of + 'struct enum_elem's */ + lt_list_for_each_entry(elem, h, list) + en->cnt++; + + if (NULL == (en->elems = malloc(sizeof(struct lt_enum_elem) * en->cnt))) + return -1; + + PRINT_VERBOSE(cfg->verbose, 3, "enum %s (%d elems)\n", + en->name, en->cnt); + + lt_list_for_each_entry(elem, h, list) { + + if (elem->undef) { + if (!last) + elem->val = 0; + else + elem->val = last->val + 1; + elem->undef = 0; + } + + PRINT_VERBOSE(cfg->verbose, 3, "\t %s = %d\n", + elem->name, elem->val); + + en->elems[i++] = *elem; + last = elem; + } + + qsort(en->elems, en->cnt, sizeof(struct lt_enum_elem), enum_comp); + return 0; +} + +struct lt_enum_elem* lt_args_get_enum(struct lt_config_shared *cfg, + char *name, char *val) +{ + struct lt_enum_elem* elem; + + if (NULL == (elem = malloc(sizeof(*elem)))) + return NULL; + + memset(elem, 0x0, sizeof(*elem)); + elem->undef = 1; + + if (val) { + long num = strtol(val, (char **) NULL, 10); + if ((errno == ERANGE && (num == LONG_MAX || num == LONG_MIN)) || + (errno != 0 && num == 0)) + return NULL; + + elem->val = num; + elem->undef = 0; + } + + elem->name = strdup(name); + + PRINT_VERBOSE(cfg->verbose, 3, "enum elem %s = %d, undef = %d\n", + elem->name, elem->val, elem->undef); + return elem; +} + +int lt_args_add_struct(struct lt_config_shared *cfg, char *type_name, + struct lt_list_head *h) +{ + struct lt_arg *arg, sarg; + + if ((args_def_struct_cnt + 1) == LT_ARGS_DEF_STRUCT_NUM) + return 1; + + /* check if the struct name is already + defined as a type */ + if (lt_args_getarg(cfg, type_name, NULL, 0, 1, NULL)) + return -1; + + memset(&sarg, 0, sizeof(sarg)); + sarg.dtype = LT_ARGS_DTYPE_STRUCT; + sarg.type_id = LT_ARGS_TYPEID_CUSTOM + args_def_struct_cnt; + sarg.type_name = type_name; + sarg.args_head = h; + + PRINT_VERBOSE(cfg->verbose, 3, "struct [%s] type %d\n", + sarg.type_name, sarg.type_id); + + lt_list_for_each_entry(arg, sarg.args_head, args_list) { + + PRINT_VERBOSE(cfg->verbose, 3, "\t %s %s %u\n", + arg->type_name, arg->name, arg->type_len); + + /* This is not what sizeof would return on the structure. + The sizeof is arch dependent, this is pure sum. */ + sarg.type_len += arg->type_len; + sarg.mmbcnt++; + } + + args_def_struct[args_def_struct_cnt++] = sarg; + + PRINT_VERBOSE(cfg->verbose, 3, "%d.struct - final len = %u\n", + args_def_struct_cnt, sarg.type_len); + return 0; +} + +int lt_args_add_sym(struct lt_config_shared *cfg, struct lt_arg *ret, + struct lt_list_head *h) +{ + ENTRY e, *ep; + struct lt_args_sym *sym; + struct lt_arg *arg; + int i = 0; + + PRINT_VERBOSE(cfg->verbose, 3, "got symbol '%s %s'\n", + ret->type_name, ret->name); + + if (NULL == (sym = (struct lt_args_sym*) malloc(sizeof(*sym)))) + return -1; + + memset(sym, 0, sizeof(*sym)); + sym->name = ret->name; + + sym->argcnt = 1; + lt_list_for_each_entry(arg, h, args_list) + sym->argcnt++; + + sym->args = (struct lt_arg**) malloc(sym->argcnt * sizeof(struct lt_arg**)); + if (!sym->args) + /* no need to fre sym, since we are going + to exit the program anyway */ + return -1; + + PRINT_VERBOSE(cfg->verbose, 3, "got return %s, ptr %d\n", + ret->type_name, ret->pointer); + + sym->args[i++] = ret; + lt_list_for_each_entry(arg, h, args_list) { + PRINT_VERBOSE(cfg->verbose, 3, "\t '%s %s'\n", + arg->type_name, arg->name); + sym->args[i++] = arg; + } + + e.key = sym->name; + e.data = sym; + + if (!hsearch_r(e, ENTER, &ep, &cfg->args_tab)) { + perror("hsearch_r failed"); + free(sym); + /* we dont want to exit just because + we ran out of our symbol limit */ + PRINT_VERBOSE(cfg->verbose, 3, "reach the symbol number limit %u\n", + LT_ARGS_TAB); + } else + PRINT_VERBOSE(cfg->verbose, 3, "got symbol %s (%d args)\n", + sym->name, sym->argcnt); + + return 0; +} + +static struct lt_arg* argdup(struct lt_config_shared *cfg, struct lt_arg *asrc) +{ + struct lt_arg *arg, *a; + struct lt_list_head *h; + + PRINT_VERBOSE(cfg->verbose, 2, "got arg '%s %s', dtype %d\n", + asrc->type_name, asrc->name, asrc->dtype); + + if (NULL == (arg = malloc(sizeof(*arg)))) { + perror("malloc failed"); + return NULL; + } + + *arg = *asrc; + + if (arg->dtype != LT_ARGS_DTYPE_STRUCT) + return arg; + + /* For structures we need also to copy all its arguments. */ + + if (NULL == (h = (struct lt_list_head*) malloc(sizeof(*h)))) { + perror("malloc failed"); + return NULL; + } + + lt_init_list_head(h); + + lt_list_for_each_entry(a, asrc->args_head, args_list) { + struct lt_arg *aa; + + /* XXX Not sure how safe is this one... + might need some attention in future :) */ + if (NULL == (aa = argdup(cfg, a))) + return NULL; + + lt_list_add_tail(&aa->args_list, h); + } + + arg->args_head = h; + return arg; +} + +static struct lt_arg* find_arg(struct lt_config_shared *cfg, char *type, + struct lt_arg argsdef[], int size, int create) +{ + int i; + + for(i = 0; i < size; i++) { + struct lt_arg *arg; + struct lt_arg adef = argsdef[i]; + + PRINT_VERBOSE(cfg->verbose, 3, "%d. looking for [%s] - [%s]\n", + i, type, adef.type_name); + + if (strcmp(type, adef.type_name)) + continue; + + if (!create) + return &argsdef[i]; + + arg = argdup(cfg, &adef); + + PRINT_VERBOSE(cfg->verbose, 3, "found %d\n", arg->type_id); + return arg; + } + + return NULL; +} + +struct lt_arg* lt_args_getarg(struct lt_config_shared *cfg, char *type, + char *name, int pointer, int create, char *enum_name) +{ + struct lt_arg *arg; + + do { + if ((arg = find_arg(cfg, type, + args_def_pod, LT_ARGS_DEF_POD_NUM, create))) + break; + + if ((arg = find_arg(cfg, type, + args_def_struct, args_def_struct_cnt, create))) + break; + + if ((arg = find_arg(cfg, type, + args_def_typedef, args_def_typedef_cnt, create))) + break; + + return NULL; + + } while(0); + + if (!create) + return arg; + + /* Find out the enum definition if the enum + name is provided. */ + if (enum_name) + arg->en = getenum(cfg, enum_name); + + arg->name = strdup(name); + + /* If the type is already a pointer (could be for typedef), + give it a chance to show up. There's only one pointer for + the arg, since there's no reason to go dreper. */ + if (!arg->pointer) + arg->pointer = pointer; + + return arg; +} + +int lt_args_add_typedef(struct lt_config_shared *cfg, char *base, + char *new, int pointer) +{ + struct lt_arg *arg; + int i; + + if ((args_def_typedef_cnt + 1) == LT_ARGS_DEF_TYPEDEF_NUM) + return 2; + + /* check if the typedef name is already + defined as a type */ + if (lt_args_getarg(cfg, new, NULL, 0, 0, NULL)) + return 1; + + do { + if ((arg = find_arg(cfg, base, + args_def_pod, LT_ARGS_DEF_POD_NUM, 0))) + break; + + if ((arg = find_arg(cfg, base, + args_def_typedef, args_def_typedef_cnt, 0))) + break; + + PRINT_VERBOSE(cfg->verbose, 3, "%s not found\n", base); + return -1; + + } while(0); + + PRINT_VERBOSE(cfg->verbose, 3, "got [%s]\n", new); + + args_def_typedef[i = args_def_typedef_cnt++] = *arg; + + arg = &args_def_typedef[i]; + arg->type_name = strdup(new); + arg->pointer = pointer; + + lt_init_list_head(&arg->args_list); + + PRINT_VERBOSE(cfg->verbose, 3, "%d.typedef - got [%s] [%s]\n", + args_def_typedef_cnt, base, arg->type_name); + return 0; +} + +int lt_args_init(struct lt_config_shared *cfg) +{ + char *file = LT_ARGS_DEF_CONF; + int ret = 0; + + if (!hcreate_r(LT_ARGS_TAB, &cfg->args_tab)) { + perror("failed to create has table:"); + return -1; + } + + lt_args_parse_init(cfg); + + if (*cfg->args_def) + file = cfg->args_def; + + PRINT_VERBOSE(cfg->verbose, 1, "arguments definition file %s\n", file); + + if (lt_args_buf_open(cfg, file)) + return -1; + + if (yyparse()) { + printf("failed to parse config file %s\n", file); + ret = -1; + } + + if (fclose(yyin)) { + perror("failed to close " LT_ARGS_DEF_CONF); + return -1; + } + + return ret; +} + +static struct lt_args_sym* getsym(struct lt_config_shared *cfg, char *sym) +{ + struct lt_args_sym *a; + ENTRY e, *ep; + + PRINT_VERBOSE(cfg->verbose, 1, "request for <%s>\n", sym); + + e.key = sym; + hsearch_r(e, FIND, &ep, &cfg->args_tab); + + if (!ep) + return NULL; + + a = (struct lt_args_sym*) ep->data; + + PRINT_VERBOSE(cfg->verbose, 1, "found %p <%s>\n", a, a->name); + return a; +} + +static int getstr_addenum(struct lt_config_shared *cfg, struct lt_arg *arg, + char *argbuf, int alen, long val) +{ + char *enstr = NULL; + struct lt_enum_elem *elem; + + if (!arg->en) + return 0; + + if (NULL != (elem = get_enumelem(cfg, val, arg->en))) + enstr = elem->name; + + if (enstr) + return snprintf(argbuf, alen, "%s", enstr); + + return 0; +} + +static int getstr_pod(struct lt_config_shared *cfg, int dspname, struct lt_arg *arg, + void *pval, char *argbuf, int *arglen) +{ + int len = 0, alen = *arglen; + int namelen = strlen(arg->name); + + PRINT_VERBOSE(cfg->verbose, 1, "\t arg '%s %s', pval %p, len %d, pointer %d, dtype %d, type_id %d\n", + arg->type_name, arg->name, pval, alen, arg->pointer, arg->dtype, arg->type_id); + + if (alen < 5) + return 0; + + *arglen = 0; + + if ((dspname) && + (namelen < (alen - 5 - sizeof(LT_EQUAL)))) { + *arglen = sprintf(argbuf, "%s"LT_EQUAL, arg->name); + argbuf += *arglen; + alen -= *arglen; + } + + /* Get enum resolve for pointers now, the rest + POD is done in ARGS_SPRINTF macro. The char + pointers need special handling later. */ + if ((arg->pointer) && + (arg->type_id != LT_ARGS_TYPEID_CHAR)) { + + void *ptr = *((void**) pval); + + /* Try to get enumed value first. */ + len = getstr_addenum(cfg, arg, argbuf, alen, (long)ptr); + + /* If there's no enum resolved, + just display the ptr value */ + if (!len) { + if (ptr) + len = snprintf(argbuf, alen, "%p", ptr); + else + len = snprintf(argbuf, alen, "NULL"); + } + + goto out; + } + +#define ARGS_SPRINTF(FMT, TYPE) \ +do { \ + if (!(len = getstr_addenum(cfg, arg, argbuf, alen, \ + (long) *((TYPE*) pval)))) \ + len = snprintf(argbuf, alen, FMT, *((TYPE*) pval)); \ +} while(0) + + switch(arg->type_id) { + case LT_ARGS_TYPEID_SHORT: ARGS_SPRINTF("%hd", short); break; + case LT_ARGS_TYPEID_USHORT: ARGS_SPRINTF("%hu", unsigned short); break; + case LT_ARGS_TYPEID_INT: ARGS_SPRINTF("%d", int); break; + case LT_ARGS_TYPEID_UINT: ARGS_SPRINTF("%u", unsigned int); break; + case LT_ARGS_TYPEID_LONG: ARGS_SPRINTF("%ld", long); break; + case LT_ARGS_TYPEID_ULONG: ARGS_SPRINTF("%lu", unsigned long); break; + case LT_ARGS_TYPEID_LLONG: ARGS_SPRINTF("%lld", long long); break; + case LT_ARGS_TYPEID_ULLONG: ARGS_SPRINTF("%llu", unsigned long long); break; + case LT_ARGS_TYPEID_DOUBLE: ARGS_SPRINTF("%lf", double); break; + case LT_ARGS_TYPEID_FLOAT: ARGS_SPRINTF("%f", float); break; +#undef ARGS_SPRINTF + case LT_ARGS_TYPEID_CHAR: + if (arg->pointer) { + + void *val = *((void**) pval); + + if (val) { + char *s = val; + int slen = strlen(s); + int left = alen; + + if ((slen + 2) > left) { + snprintf(argbuf, left, "\"%s", s); + strncpy(argbuf + left - sizeof("...\"") + 1, "...\"", sizeof("...\"")); + } else { + strcpy(argbuf, "\""); + strcat(argbuf, s); + strcat(argbuf, "\""); + } + } else + len = snprintf(argbuf, alen, "NULL"); + } else { + + if (*((char*) pval) <= ' ') + len = snprintf(argbuf, alen, "0x%02x", + *((char*) pval)); + else + len = snprintf(argbuf, alen, "0x%02x \'%c\'", + *((char*) pval), *((char*) pval)); + } + break; + + case LT_ARGS_TYPEID_VOID: + len = snprintf(argbuf, alen, "void"); + break; + } + + if (LT_ARGS_DTYPE_STRUCT == arg->dtype) { + if (pval) + len = snprintf(argbuf, alen, "v(%p)", pval); + else + len = snprintf(argbuf, alen, "v(REG)"); + + } + +out: + *arglen += strlen(argbuf); + + PRINT_VERBOSE(cfg->verbose, 1, "\t arg out len %d - [%s]\n", + *arglen, argbuf); + return 0; +} + +int lt_args_cb_arg(struct lt_config_shared *cfg, struct lt_arg *arg, void *pval, + struct lt_args_data *data, int last, int dspname) +{ + int len = data->arglen; + + PRINT_VERBOSE(cfg->verbose, 1, "arg '%s %s', pval %p, last %d\n", + arg->type_name, arg->name, pval, last); + + getstr_pod(cfg, dspname, arg, pval, + data->args_buf + data->args_totlen, &len); + data->args_totlen += len; + + if (!last) { + strcat(data->args_buf, ", "); + data->args_totlen += 2; + } + + return 0; +} + +int lt_args_cb_struct(struct lt_config_shared *cfg, int type, struct lt_arg *arg, + void *pval, struct lt_args_data *data, int last) +{ + PRINT_VERBOSE(cfg->verbose, 1, + "type %d, arg '%s %s', pval %p, last %d, pointer %d\n", + type, arg->type_name, arg->name, pval, last, arg->pointer); + + /* initiall call for the structure argument */ + if (type == LT_ARGS_STRUCT_ITSELF) { + + data->argsd_totlen += sprintf(data->argsd_buf + data->argsd_totlen, + "struct %s %s = { ", + arg->type_name, arg->name); + return 0; + + /* subsequent calls for all structure arguments */ + } else if (type == LT_ARGS_STRUCT_ARG) { + + int len = cfg->args_detail_maxlen - data->argsd_totlen; + + getstr_pod(cfg, 1, arg, pval, data->argsd_buf + data->argsd_totlen, &len); + data->argsd_totlen += len; + + if (!last) { + strcat(data->argsd_buf, ", "); + data->argsd_totlen += 2; + } else + data->argsd_totlen += sprintf(data->argsd_buf + + data->argsd_totlen, " }\n"); + } + + return 0; +} + +static int getargs(struct lt_config_shared *cfg, struct lt_args_sym *asym, + La_regs *regs, char **abuf, char **adbuf) +{ + struct lt_args_data data; + int arglen; + char *buf, *bufd; + + if (NULL == (buf = malloc(cfg->args_maxlen))) + return -1; + + memset(&data, 0, sizeof(data)); + + *buf = 0; + *abuf = buf; + + if (cfg->args_detailed) { + if (NULL == (bufd = malloc(cfg->args_detail_maxlen))) + return -1; + + *bufd = 0; + *adbuf = bufd; + data.argsd_buf = bufd; + data.argsd_len = cfg->args_detail_maxlen; + } + + + /* makeup the final space for each + argument textual representation */ + arglen = (cfg->args_maxlen + - ((asym->argcnt - 1) * 2) /* args separating commas */ + )/ asym->argcnt; + + + data.arglen = arglen; + data.args_buf = buf; + data.args_len = cfg->args_maxlen; + + return lt_stack_process(cfg, asym, regs, &data); +} + +static FILE* open_include(struct lt_config_shared *cfg, char *file) +{ + FILE *f; + char fn[LT_MAXFILE]; + + /* we got an absolute path */ + if ((NULL != (f = fopen(file, "r")))) { + PRINT_VERBOSE(cfg->verbose, 1, "open ok [%s]\n", file); + return f; + } + + PRINT_VERBOSE(cfg->verbose, 1, "open failed [%s]: %s\n", + file, strerror(errno)); + + /* give up if there was already the absolute name */ + if (*file == '/') { + printf("open failed [%s]: %s\n", file, strerror(errno)); + return NULL; + } + + /* not an absolute name, give it a chance + inside of the /etc config directory */ + if (strlen(file) > (LT_MAXFILE - sizeof(LT_ARGS_DEF_DIR))) { + printf("file name length crossed the max %u: %s\n", + (u_int) (LT_MAXFILE - sizeof(LT_ARGS_DEF_DIR)), file); + return NULL; + } + + sprintf(fn, "%s/%s", LT_ARGS_DEF_DIR, file); + + if ((NULL == (f = fopen(fn, "r")))) { + PRINT_VERBOSE(cfg->verbose, 1, "open failed [%s]: %s\n", + fn, strerror(errno)); + printf("open failed [%s]: %s\n", file, strerror(errno)); + return NULL; + } + + PRINT_VERBOSE(cfg->verbose, 1, "open ok [%s]\n", fn); + return f; +} + +int lt_args_buf_open(struct lt_config_shared *cfg, char *file) +{ + struct lt_args_include *inc; + + PRINT_VERBOSE(cfg->verbose, 1, "opening buffer for [%s] depth %d\n", + file, include_stack_ptr); + + if ((include_stack_ptr + 1) == MAX_INCLUDE_DEPTH) { + printf("include depth overstep"); + return -1; + } + + if (NULL == (yyin = open_include(cfg, file))) + return -1; + + inc = &include_stack[include_stack_ptr++]; + memset(inc, 0, sizeof(*inc)); + + inc->yyin = yyin; + inc->file = strdup(file); + inc->lineno = 1; + inc->yybuf = yy_create_buffer(yyin, YY_BUF_SIZE); + + yy_switch_to_buffer(inc->yybuf); + + PRINT_VERBOSE(cfg->verbose, 1, "opened buffer for [%s] depth %d\n", + file, include_stack_ptr); + return 0; +} + +int lt_args_buf_close(struct lt_config_shared *cfg) +{ + struct lt_args_include *inc = &include_stack[--include_stack_ptr]; + + PRINT_VERBOSE(cfg->verbose, 1, "buffer closed [%s], depth [%d]\n", + inc->file, include_stack_ptr); + + free(inc->file); + + /* EOF with no other includes on stack */ + if (!include_stack_ptr) + return -1; + + /* looks like the base buffer is cleaned up by the + flex itself, so we do the actual cleaning + only for includes */ + yy_delete_buffer(inc->yybuf); + fclose(inc->yyin); + + inc = &include_stack[include_stack_ptr - 1]; + yy_switch_to_buffer(inc->yybuf); + return 0; +} + +struct lt_args_include* lt_args_buf_get(void) +{ + struct lt_args_include *inc = &include_stack[include_stack_ptr - 1]; + return inc; +} + +int lt_args_sym_entry(struct lt_config_shared *cfg, char *sym, La_regs *regs, + char **argbuf, char **argdbuf) +{ + struct lt_args_sym *asym; + + if (NULL == (asym = getsym(cfg, sym))) + return -1; + + return getargs(cfg, asym, regs, argbuf, argdbuf); +} + +static int getargs_ret(struct lt_config_shared *cfg, struct lt_args_sym *asym, + La_retval *regs, char **abuf, char **adbuf) +{ + struct lt_args_data data; + int arglen, totlen; + char *buf, *bufd; + + if (NULL == (buf = malloc(cfg->args_maxlen))) + return -1; + + memset(&data, 0, sizeof(data)); + + *buf = 0; + *abuf = buf; + + /* TODO get together with getargs function somehow... */ + if (cfg->args_detailed) { + + if (NULL == (bufd = malloc(cfg->args_detail_maxlen))) + return -1; + + *bufd = 0; + *adbuf = bufd; + data.argsd_buf = bufd; + data.argsd_len = cfg->args_detail_maxlen; + } + + arglen = cfg->args_maxlen - sizeof(LT_EQUAL); + totlen = sizeof(LT_EQUAL) - 1; + strcat(buf, LT_EQUAL); + + data.arglen = arglen; + data.args_buf = buf; + data.args_len = cfg->args_maxlen; + data.args_totlen = totlen; + + return lt_stack_process_ret(cfg, asym, regs, &data); +} + +int lt_args_sym_exit(struct lt_config_shared *cfg, char *sym, La_regs *inregs, La_retval *outregs, + char **argbuf, char **argdbuf) +{ + struct lt_args_sym *asym; + + if (NULL == (asym = getsym(cfg, sym))) + return -1; + + return getargs_ret(cfg, asym, outregs, argbuf, argdbuf); +} |