%{ /** * This file is part of the Detox package. * * Copyright (c) Doug Harple * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ #include "config.h" #include #include #include #include "detox.h" #include "clean_string.h" #include "config_file.h" /* * I must apologize in advance for the cryptic, global variable names. */ static struct detox_sequence_list *cf_sl_ret, *cf_sl_current; static struct detox_sequence_entry *cf_seq_ret, *cf_seq_current; static struct detox_ignore_entry *cf_ignore_ret, *cf_ignore_current; static struct clean_string_options *csopts; static char *current_name = NULL; static char *current_filename = NULL; static struct detox_options *current_options; void cf_append_sequence_list(void); void cf_append_sequence_entry(void *ptr, void *opts); void cf_append_ignore_entry(int token, void *str); void yyerror (char *s); int yylex (void); %} %union { char *string; /* string buffer */ int cmd; /* command value */ struct detox_sequence_entry *seq; /* sequence */ int nvalue; /* nvalue */ } %token QSTRING ID %token SEQUENCE IGNORE %token UNCGI ISO8859_1 UTF_8 SAFE WIPEUP %token MAX_LENGTH LOWER %token FILENAME REMOVE_TRAILING LENGTH %token OPEN CLOSE EOL %token NVALUE %type string %% configfile: | configfile rule ; rule: sequence | ignore ; sequence: sequence_open method_list sequence_close ; sequence_open: SEQUENCE string OPEN { current_name = $2; } ; sequence_close: CLOSE EOL { cf_append_sequence_list(); } ; method_list: method | method_list method ; method: UNCGI EOL { cf_append_sequence_entry(&clean_uncgi, NULL); } | LOWER EOL { cf_append_sequence_entry(&clean_lower, NULL); } | wipeup EOL | iso8859_1 EOL | utf_8 EOL | safe EOL | max_length EOL ; iso8859_1: ISO8859_1 { cf_append_sequence_entry(&clean_iso8859_1, NULL); } | ISO8859_1 OPEN CLOSE { cf_append_sequence_entry(&clean_iso8859_1, NULL); } | ISO8859_1 OPEN FILENAME string EOL CLOSE { csopts = malloc(sizeof(struct clean_string_options)); memset(csopts, 0, sizeof(struct clean_string_options)); csopts->filename = $4; cf_append_sequence_entry(&clean_iso8859_1, csopts); } ; utf_8: UTF_8 { cf_append_sequence_entry(&clean_utf_8, NULL); } | UTF_8 OPEN CLOSE { cf_append_sequence_entry(&clean_utf_8, NULL); } | UTF_8 OPEN FILENAME string EOL CLOSE { csopts = malloc(sizeof(struct clean_string_options)); memset(csopts, 0, sizeof(struct clean_string_options)); csopts->filename = $4; cf_append_sequence_entry(&clean_utf_8, csopts); } ; safe: SAFE { cf_append_sequence_entry(&clean_safe, NULL); } | SAFE OPEN CLOSE { cf_append_sequence_entry(&clean_safe, NULL); } | SAFE OPEN FILENAME string EOL CLOSE { csopts = malloc(sizeof(struct clean_string_options)); memset(csopts, 0, sizeof(struct clean_string_options)); csopts->filename = $4; cf_append_sequence_entry(&clean_safe, csopts); } ; wipeup: WIPEUP { if (current_options->remove_trailing) { csopts = malloc(sizeof(struct clean_string_options)); memset(csopts, 0, sizeof(struct clean_string_options)); csopts->remove_trailing = 1; } else { csopts = NULL; } cf_append_sequence_entry(&clean_wipeup, csopts); } | WIPEUP OPEN CLOSE { if (current_options->remove_trailing) { csopts = malloc(sizeof(struct clean_string_options)); memset(csopts, 0, sizeof(struct clean_string_options)); csopts->remove_trailing = 1; } else { csopts = NULL; } cf_append_sequence_entry(&clean_wipeup, csopts); } | WIPEUP OPEN REMOVE_TRAILING EOL CLOSE { csopts = malloc(sizeof(struct clean_string_options)); memset(csopts, 0, sizeof(struct clean_string_options)); csopts->remove_trailing = 1; cf_append_sequence_entry(&clean_wipeup, csopts); } ; max_length: MAX_LENGTH { cf_append_sequence_entry(&clean_max_length, NULL); } | MAX_LENGTH OPEN CLOSE { cf_append_sequence_entry(&clean_max_length, NULL); } | MAX_LENGTH OPEN LENGTH NVALUE EOL CLOSE { csopts = malloc(sizeof(struct clean_string_options)); memset(csopts, 0, sizeof(struct clean_string_options)); csopts->max_length = (size_t)$4; cf_append_sequence_entry(&clean_max_length, csopts); } ; ignore: ignore_open ignore_list ignore_close ; ignore_open: IGNORE OPEN ; ignore_close: CLOSE EOL ; ignore_list: ignore_filename | ignore_list ignore_filename ; ignore_filename: FILENAME string EOL { cf_append_ignore_entry(FILENAME, $2); } ; string: QSTRING { $$ = $1; } | ID { $$ = $1; } ; %% extern FILE *yyin; extern FILE *yyout; struct detox_parse_results *parse_config_file(char *filename, struct detox_parse_results *previous_results, struct detox_options *main_options) { struct detox_parse_results *ret = NULL; current_filename = filename; current_options = main_options; /* * XXX - Should we be closing the default yyin/yyout? If so, should we * be setting them to NULL at the end of this function? */ yyin = fopen(filename, "r"); if (yyin == NULL) { return previous_results; } yyout = fopen("/dev/null", "w"); /* * Initialize the return variable */ if (previous_results) { ret = previous_results; } else { ret = malloc(sizeof(struct detox_parse_results)); memset(ret, 0, sizeof(struct detox_parse_results)); } /* * Initialize the sequence list */ cf_sl_ret = NULL; cf_sl_current = NULL; if (previous_results && previous_results->sequences) { cf_sl_ret = previous_results->sequences; cf_sl_current = cf_sl_ret; while (cf_sl_current->next != NULL) { cf_sl_current = cf_sl_current->next; } } /* * Initialize the ignore list */ cf_ignore_ret = NULL; cf_ignore_current = NULL; if (previous_results && previous_results->files_to_ignore) { cf_ignore_ret = previous_results->files_to_ignore; cf_ignore_current = cf_ignore_ret; while (cf_ignore_current->next != NULL) { cf_ignore_current = cf_ignore_current->next; } } /* * Reset the sequence entry holding vars */ cf_seq_ret = NULL; cf_seq_current = NULL; do { yyparse(); } while (!feof(yyin)); fclose(yyin); fclose(yyout); /* * Populate returns */ ret->sequences = cf_sl_ret; ret->files_to_ignore = cf_ignore_ret; return ret; } void yyerror(char *s) { /* * XXX - Is extern valid here? Does it do what I'm expecting? */ extern char *yytext; fprintf(stderr, "detox: error parsing config file %s: %s\n", current_filename, s); fprintf(stderr, "\tline %d", config_file_lineno); if (yytext != NULL) { fprintf(stderr, ": %s", yytext); } fprintf(stderr, "\n"); exit(EXIT_FAILURE); } void cf_append_sequence_list(void) { struct detox_sequence_list *work; if (current_name == NULL) { current_name = strdup("default"); } work = NULL; if (cf_sl_ret != NULL) { work = cf_sl_ret; while (work != NULL) { if (strcmp(work->name, current_name) == 0) { break; } work = work->next; } } if (work != NULL) { /* * XXX - Free Old Tree */ } else { work = malloc(sizeof(struct detox_sequence_list)); memset(work, 0, sizeof(struct detox_sequence_list)); work->name = strdup(current_name); /* * Append to the tree first. If we don't, we could create a * circular reference. */ if (cf_sl_ret == NULL) { cf_sl_ret = cf_sl_current = work; } else { cf_sl_current->next = work; cf_sl_current = work; } } work->head = cf_seq_ret; work->source_filename = strdup(current_filename); cf_seq_ret = cf_seq_current = NULL; } void cf_append_sequence_entry(void *ptr, void *opts) { struct detox_sequence_entry *work; work = malloc(sizeof(struct detox_sequence_entry)); memset(work, 0, sizeof(struct detox_sequence_entry)); work->cleaner = ptr; work->options = opts; if (cf_seq_ret == NULL) { cf_seq_ret = cf_seq_current = work; } else { cf_seq_current->next = work; cf_seq_current = work; } } void cf_append_ignore_entry(int token, void *str) { struct detox_ignore_entry *work; work = malloc(sizeof(struct detox_ignore_entry)); memset(work, 0, sizeof(struct detox_ignore_entry)); switch(token) { case FILENAME: work->filename = str; break; default: break; } if (cf_ignore_ret == NULL) { cf_ignore_ret = cf_ignore_current = work; } else { cf_ignore_current->next = work; cf_ignore_current = work; } }