diff options
author | Steve Fink <sphink@gmail.com> | 2006-08-07 06:10:08 +0200 |
---|---|---|
committer | Ian Wienand <ianw@debian.org> | 2006-08-07 06:10:08 +0200 |
commit | e4b3263fb2b32eb5ee0f693fc223ed8c363fbd69 (patch) | |
tree | cc708044654624fd22fdfe7d0b9b09f1bef0c9e7 /read_config_file.c | |
parent | 1150bc4b812f0150e832607b8724b023d6d7d575 (diff) | |
download | ltrace-e4b3263fb2b32eb5ee0f693fc223ed8c363fbd69.tar.gz |
Add pointers to structs
* Allow parameters to be pointers to structs, which themselves
can contain (nearly) any other type, including other structs
or pointers to structs.
Diffstat (limited to 'read_config_file.c')
-rw-r--r-- | read_config_file.c | 114 |
1 files changed, 112 insertions, 2 deletions
diff --git a/read_config_file.c b/read_config_file.c index 51d4d85..ec1a4a8 100644 --- a/read_config_file.c +++ b/read_config_file.c @@ -19,6 +19,8 @@ static arg_type_info *parse_type(char **str); struct function *list_of_functions = NULL; +/* Map of strings to type names. These do not need to be in any + * particular order */ static struct list_of_pt_t { char *name; enum arg_type pt; @@ -39,11 +41,15 @@ static struct list_of_pt_t { "format", ARGTYPE_FORMAT}, { "string", ARGTYPE_STRING}, { "array", ARGTYPE_ARRAY}, { + "struct", ARGTYPE_STRUCT}, { "enum", ARGTYPE_ENUM}, { "ignore", ARGTYPE_IGNORE}, { NULL, ARGTYPE_UNKNOWN} /* Must finish with NULL */ }; +/* Array of singleton objects for each of the types. The order in this + * array must exactly match the list of enumerated values in + * ltrace.h */ static arg_type_info arg_type_singletons[] = { { ARGTYPE_VOID }, { ARGTYPE_INT }, @@ -62,6 +68,7 @@ static arg_type_info arg_type_singletons[] = { { ARGTYPE_STRING_N }, { ARGTYPE_ARRAY }, { ARGTYPE_ENUM }, + { ARGTYPE_STRUCT }, { ARGTYPE_IGNORE }, { ARGTYPE_POINTER }, { ARGTYPE_UNKNOWN } @@ -166,6 +173,7 @@ static int simple_type(enum arg_type at) case ARGTYPE_STRING_N: case ARGTYPE_ARRAY: case ARGTYPE_ENUM: + case ARGTYPE_STRUCT: return 0; default: @@ -178,8 +186,8 @@ static int parse_int(char **str) char *end; long n = strtol(*str, &end, 0); if (end == *str) { - output_line(0, "Syntax error in `%s', line %d: Bad number", - filename, line_no); + output_line(0, "Syntax error in `%s', line %d: Bad number (%s)", + filename, line_no, *str); error_count++; return 0; } @@ -209,6 +217,9 @@ static int parse_argnum(char **str) if (strncmp(*str, "arg", 3) == 0) { (*str) += 3; multiplier = -1; + } else if (strncmp(*str, "elt", 3) == 0) { + (*str) += 3; + multiplier = -1; } else if (strncmp(*str, "retval", 6) == 0) { (*str) += 6; return 0; @@ -289,6 +300,8 @@ static size_t arg_sizeof(arg_type_info * arg) return sizeof(float); } else if (arg->type == ARGTYPE_ENUM) { return sizeof(int); + } else if (arg->type == ARGTYPE_STRUCT) { + return arg->u.struct_info.size; } else if (arg->type == ARGTYPE_ARRAY) { if (arg->u.array_info.len_spec > 0) return arg->u.array_info.len_spec * arg->u.array_info.elt_size; @@ -299,6 +312,63 @@ static size_t arg_sizeof(arg_type_info * arg) } } +/* I'm sure this isn't completely correct, but just try to get most of + * them right for now. */ +#undef alignof +#define alignof(field,st) ((size_t) ((char*) &st.field - (char*) &st)) +static void align_struct(arg_type_info* info) +{ + struct { + char c; + int i; + } ci; + struct { + struct { + char c; + } s; + int i; + } cis; + + size_t int_alignment = alignof(i, ci); + size_t whole_struct_alignment = alignof(i, cis); + + size_t offset; + size_t gap; + int i; + + if (info->u.struct_info.size != 0) + return; // Already done + + // The gap array isn't actually needed anymore, because the + // offset can be used for everything. + + // 1. Add internal padding + offset = 0; + for (i = 0; info->u.struct_info.fields[i] != NULL; i++) { + arg_type_info *field = info->u.struct_info.fields[i]; + info->u.struct_info.offset[i] = offset; + offset += arg_sizeof(field); + + if (offset % int_alignment != 0) { + gap = int_alignment - offset % int_alignment; + info->u.struct_info.gap[i] = gap; + offset += gap; + } + } + + // 2. Add padding at end of entire struct + for (i = 0; info->u.struct_info.fields[i] != NULL; i++); + if (i == 0) + return; + if (offset % whole_struct_alignment != 0) { + gap = whole_struct_alignment - offset % whole_struct_alignment; + info->u.struct_info.gap[i - 1] = gap; + offset += gap; + } + + info->u.struct_info.size = offset; +} + static arg_type_info *parse_nonpointer_type(char **str) { arg_type_info *simple; @@ -432,6 +502,46 @@ static arg_type_info *parse_nonpointer_type(char **str) (*str)++; // Skip past closing ] return info; + // Syntax: struct ( type,type,type,... ) + case ARGTYPE_STRUCT:{ + int field_num = 0; + (*str)++; // Get past open paren + info->u.struct_info.fields = + malloc((MAX_ARGS + 1) * sizeof(void *)); + info->u.struct_info.gap = + malloc((MAX_ARGS + 1) * sizeof(size_t)); + info->u.struct_info.offset = + malloc((MAX_ARGS + 1) * sizeof(size_t)); + info->u.struct_info.size = 0; + eat_spaces(str); // Empty arg list with whitespace inside + while (**str && **str != ')') { + if (field_num == MAX_ARGS) { + output_line(0, + "Error in `%s', line %d: Too many structure elements", + filename, line_no); + error_count++; + return NULL; + } + eat_spaces(str); + if (field_num != 0) { + (*str)++; // Get past comma + eat_spaces(str); + } + info->u.struct_info.gap[field_num] = 0; + if ((info->u.struct_info.fields[field_num++] = + parse_type(str)) == NULL) + return NULL; + + // Must trim trailing spaces so the check for + // the closing paren is simple + eat_spaces(str); + } + (*str)++; // Get past closing paren + info->u.struct_info.fields[field_num] = NULL; + align_struct(info); + return info; + } + default: output_line(0, "Syntax error in `%s', line %d: Unknown type encountered", filename, line_no); |