read_config_file.c revision 7bafff09cc66e23519512a54e2d1ebd3664a1a70
1#if HAVE_CONFIG_H 2#include "config.h" 3#endif 4 5#include <string.h> 6#include <stdlib.h> 7#include <ctype.h> 8 9#include "ltrace.h" 10#include "read_config_file.h" 11#include "output.h" 12#include "debug.h" 13 14struct function *list_of_functions = NULL; 15 16static struct list_of_pt_t { 17 char *name; 18 enum arg_type pt; 19} list_of_pt[] = { 20 { 21 "void", ARGTYPE_VOID}, { 22 "int", ARGTYPE_INT}, { 23 "uint", ARGTYPE_UINT}, { 24 "long", ARGTYPE_LONG}, { 25 "ulong", ARGTYPE_ULONG}, { 26 "octal", ARGTYPE_OCTAL}, { 27 "char", ARGTYPE_CHAR}, { 28 "addr", ARGTYPE_ADDR}, { 29 "file", ARGTYPE_FILE}, { 30 "format", ARGTYPE_FORMAT}, { 31 "string", ARGTYPE_STRING}, { 32 "ignore", ARGTYPE_IGNORE}, { 33 NULL, ARGTYPE_UNKNOWN} /* Must finish with NULL */ 34}; 35 36static arg_type_info arg_type_singletons[] = { 37 { ARGTYPE_VOID }, 38 { ARGTYPE_INT }, 39 { ARGTYPE_UINT }, 40 { ARGTYPE_LONG }, 41 { ARGTYPE_ULONG }, 42 { ARGTYPE_OCTAL }, 43 { ARGTYPE_CHAR }, 44 { ARGTYPE_ADDR }, 45 { ARGTYPE_FILE }, 46 { ARGTYPE_FORMAT }, 47 { ARGTYPE_STRING }, 48 { ARGTYPE_STRING_N }, 49 { ARGTYPE_IGNORE }, 50 { ARGTYPE_POINTER }, 51 { ARGTYPE_UNKNOWN } 52}; 53 54arg_type_info *lookup_singleton(enum arg_type at) 55{ 56 if (at >= 0 && at <= ARGTYPE_COUNT) 57 return &arg_type_singletons[at]; 58 else 59 return &arg_type_singletons[ARGTYPE_COUNT]; /* UNKNOWN */ 60} 61 62static arg_type_info *str2type(char **str) 63{ 64 struct list_of_pt_t *tmp = &list_of_pt[0]; 65 66 while (tmp->name) { 67 if (!strncmp(*str, tmp->name, strlen(tmp->name)) 68 && index(" ,()#*;012345[", *(*str + strlen(tmp->name)))) { 69 *str += strlen(tmp->name); 70 return lookup_singleton(tmp->pt); 71 } 72 tmp++; 73 } 74 return lookup_singleton(ARGTYPE_UNKNOWN); 75} 76 77static void eat_spaces(char **str) 78{ 79 while (**str == ' ') { 80 (*str)++; 81 } 82} 83 84/* 85 Returns position in string at the left parenthesis which starts the 86 function's argument signature. Returns NULL on error. 87*/ 88static char *start_of_arg_sig(char *str) 89{ 90 char *pos; 91 int stacked = 0; 92 93 if (!strlen(str)) 94 return NULL; 95 96 pos = &str[strlen(str)]; 97 do { 98 pos--; 99 if (pos < str) 100 return NULL; 101 while ((pos > str) && (*pos != ')') && (*pos != '(')) 102 pos--; 103 104 if (*pos == ')') 105 stacked++; 106 else if (*pos == '(') 107 stacked--; 108 else 109 return NULL; 110 111 } while (stacked > 0); 112 113 return (stacked == 0) ? pos : NULL; 114} 115 116/* 117 Decide whether a type needs any additional parameters. 118 For now, we do not parse any nontrivial argument types. 119*/ 120static int simple_type(enum arg_type at) 121{ 122 return 1; 123} 124 125static int line_no; 126static char *filename; 127 128static int parse_int(char **str) 129{ 130 char *end; 131 long n = strtol(*str, &end, 0); 132 if (end == *str) { 133 output_line(0, "Syntax error in `%s', line %d: Bad number", 134 filename, line_no); 135 return 0; 136 } 137 138 *str = end; 139 return n; 140} 141 142/* 143 * Input: 144 * argN : The value of argument #N, counting from 1 (arg0 = retval) 145 * eltN : The value of element #N of the containing structure 146 * retval : The return value 147 * 0 : Error 148 * N : The numeric value N, if N > 0 149 * 150 * Output: 151 * > 0 actual numeric value 152 * = 0 return value 153 * < 0 (arg -n), counting from one 154 */ 155static int parse_argnum(char **str) 156{ 157 int multiplier = 1; 158 int n = 0; 159 160 if (strncmp(*str, "arg", 3) == 0) { 161 (*str) += 3; 162 multiplier = -1; 163 } else if (strncmp(*str, "retval", 6) == 0) { 164 (*str) += 6; 165 return 0; 166 } 167 168 n = parse_int(str); 169 170 return n * multiplier; 171} 172 173static arg_type_info *parse_nonpointer_type(char **str) 174{ 175 arg_type_info *simple; 176 arg_type_info *info; 177 178 simple = str2type(str); 179 if (simple->type == ARGTYPE_UNKNOWN) { 180 return simple; // UNKNOWN 181 } 182 183 if (simple_type(simple->type) && simple->type != ARGTYPE_STRING) 184 return simple; 185 186 info = malloc(sizeof(*info)); 187 info->type = simple->type; 188 189 /* Code to parse parameterized types will go into the following 190 switch statement. */ 191 192 switch (info->type) { 193 194 case ARGTYPE_STRING: 195 if (!isdigit(**str) && **str != '[') { 196 /* Oops, was just a simple string after all */ 197 free(info); 198 return simple; 199 } 200 201 info->type = ARGTYPE_STRING_N; 202 203 /* Backwards compatibility for string0, string1, ... */ 204 if (isdigit(**str)) { 205 info->u.string_n_info.size_spec = -parse_int(str); 206 return info; 207 } 208 209 (*str)++; // Skip past opening [ 210 eat_spaces(str); 211 info->u.string_n_info.size_spec = parse_argnum(str); 212 eat_spaces(str); 213 (*str)++; // Skip past closing ] 214 return info; 215 216 default: 217 output_line(0, "Syntax error in `%s', line %d: Unknown type encountered", 218 filename, line_no); 219 free(info); 220 return NULL; 221 } 222} 223 224static arg_type_info *parse_type(char **str) 225{ 226 arg_type_info *info = parse_nonpointer_type(str); 227 while (**str == '*') { 228 arg_type_info *outer = malloc(sizeof(*info)); 229 outer->type = ARGTYPE_POINTER; 230 outer->u.ptr_info.info = info; 231 (*str)++; 232 info = outer; 233 } 234 return info; 235} 236 237static struct function *process_line(char *buf) 238{ 239 struct function fun; 240 struct function *fun_p; 241 char *str = buf; 242 char *tmp; 243 int i; 244 245 line_no++; 246 debug(3, "Reading line %d of `%s'", line_no, filename); 247 eat_spaces(&str); 248 fun.return_info = parse_type(&str); 249 if (fun.return_info == NULL) 250 return NULL; 251 if (fun.return_info->type == ARGTYPE_UNKNOWN) { 252 debug(3, " Skipping line %d", line_no); 253 return NULL; 254 } 255 debug(4, " return_type = %d", fun.return_info->type); 256 eat_spaces(&str); 257 tmp = start_of_arg_sig(str); 258 if (!tmp) { 259 output_line(0, "Syntax error in `%s', line %d", filename, 260 line_no); 261 return NULL; 262 } 263 *tmp = '\0'; 264 fun.name = strdup(str); 265 str = tmp + 1; 266 debug(3, " name = %s", fun.name); 267 fun.params_right = 0; 268 for (i = 0; i < MAX_ARGS; i++) { 269 eat_spaces(&str); 270 if (*str == ')') { 271 break; 272 } 273 if (str[0] == '+') { 274 fun.params_right++; 275 str++; 276 } else if (fun.params_right) { 277 fun.params_right++; 278 } 279 fun.arg_info[i] = parse_type(&str); 280 if (fun.arg_info[i] == NULL) { 281 output_line(0, "Syntax error in `%s', line %d" 282 ": unknown argument type", 283 filename, line_no); 284 return NULL; 285 } 286 eat_spaces(&str); 287 if (*str == ',') { 288 str++; 289 continue; 290 } else if (*str == ')') { 291 continue; 292 } else { 293 if (str[strlen(str) - 1] == '\n') 294 str[strlen(str) - 1] = '\0'; 295 output_line(0, "Syntax error in `%s', line %d at ...\"%s\"", 296 filename, line_no, str); 297 return NULL; 298 } 299 } 300 fun.num_params = i; 301 fun_p = malloc(sizeof(struct function)); 302 memcpy(fun_p, &fun, sizeof(struct function)); 303 return fun_p; 304} 305 306void read_config_file(char *file) 307{ 308 FILE *stream; 309 char buf[1024]; 310 311 filename = file; 312 313 debug(1, "Reading config file `%s'...", filename); 314 315 stream = fopen(filename, "r"); 316 if (!stream) { 317 return; 318 } 319 line_no = 0; 320 while (fgets(buf, 1024, stream)) { 321 struct function *tmp = process_line(buf); 322 323 if (tmp) { 324 debug(2, "New function: `%s'", tmp->name); 325 tmp->next = list_of_functions; 326 list_of_functions = tmp; 327 } 328 } 329 fclose(stream); 330} 331