diff --git a/dataobj/tabfile.cc b/dataobj/tabfile.cc index 828955297..12e0b444f 100644 --- a/dataobj/tabfile.cc +++ b/dataobj/tabfile.cc @@ -36,6 +36,7 @@ void tabfile_t::close() fclose(file); file = NULL; } + sublines.clear(); } @@ -291,181 +292,313 @@ void tabfileobj_t::unused( const char *exclude_start_chars ) } +int tabfile_t::directive(char *dir) +{ + const char *STARTSUB = ""; + const char *ENDSUB = ""; + const char *MARKER = ""; + const char *DELSUB = ""; + if(!strcmp(dir, STARTSUB)){ + return 1; + } + if(!strcmp(dir, ENDSUB)){ + return 2; + } + if(!strcmp(dir, MARKER)){ + return 3; + } + if(!strcmp(dir, DELSUB)){ + return 4; + } + return -1; +} + + bool tabfile_t::read(tabfileobj_t &objinfo, FILE *fp) { bool lines = false; char line[LINEBUFFER_SIZE]; - char line_expand[LINEBUFFER_SIZE]; char delim_expand[LINEBUFFER_SIZE]; char buffer[LINEBUFFER_SIZE]; char *param[10]; char *expansion[10]; - + + bool in_sub_block = false; //copy lines to table + bool line_to_obj = false; //put line into object + char subname[LINEBUFFER_SIZE]; //holds name of substitution block; empty means no substitution + char replacement[LINEBUFFER_SIZE]; //holds string for inline replacement; empty means no replacement + current_line_number = 0; - objinfo.clear(); - + do { while(read_line(line, sizeof(line)) && *line != '-') { - char *delim = strchr(line, '='); - - if(delim) { - *delim++ = '\0'; - format_key(line); - if (line[0] == 0) { - return false; + replacement[0]='\0'; + + // Handle substitution blocks. Lines get stored in the hashtable, unless it's the end of the block. + // directives are not allowed (except for ending the block), ignored + warning. + if(in_sub_block) { + if(line[0] == '<') { + if(directive(line)==2){ //End of a substitution block + in_sub_block=false; + } + else { + dbg->warning( "tabfile_t::read", "Line %d in substitution block ignored. \"%s\"", current_line_number, line); + } } - - int parameters = 0; - int expansions = 0; - /* - @line, the whole parameter text (everything before =) - @delim, the whole value text (everything after =) - @parameters, number of fields enclosed by square brackets [] - @expansions, number of expansions included in the value (text inside angle brackets <>) - @param, array containing the text inside each [] field - @expansion, array containing the text inside each <> field - */ - if(find_parameter_expansion(line, delim, ¶meters, &expansions, param, expansion) > 0) { - int parameter_value[10][256]; - int parameter_length[10]; - int parameter_values[10]; // number of possible 'values' inside each [] field | e.g. [0-4]=5 / [n,s,w]=3 - char parameter_name[256][6]; // non-numeric ribis strings for all parameter fields consecutively - bool parameter_ribi[10]; // true if parameters are ribi strings - - int combinations=1; - int names = 0; // total number of ribi parameters - - // analyse and obtain all parameter expansions - for(int i=0; ipush_back(helper); + } + } + + // Handle directives. Since directives can be key-value-pairs, they may need to be seperated. + // Directive strings are turned into integers via directive() to be used in a switch. + else if(line[0] == '<') { + char *delim = strchr(line, '='); + if(delim) { + *delim++ = '\0'; + format_key(line); + } + switch (directive(line)){ + case 1: //Beginning of a substitution block + if(delim) { + strcpy(subname, delim); + sublines.put(subname, std::vector(0)); + in_sub_block = true; + } + else{ + dbg->warning( "tabfile_t::read", "Line %d ignored. Start of substitution block without name.", current_line_number); + } + break; + case 2: //End of a substitution block + dbg->warning( "tabfile_t::read", "End of substitution block outside of substitution block in line %d ignored.", current_line_number); + break; + case 3: //Insertion marker + if(delim) { + // check for replacement-string + char *repl = strchr(delim, ';'); + if(repl){ + *repl++ = '\0'; + strcpy(replacement, repl); } - parameter_value[i][parameter_values[i]++] = value; - - token_ptr = strtok(buffer,"-,"); - while (token_ptr != NULL && parameter_values[i]<256) { - switch(param[i][token_ptr-buffer-1]) { - case ',': - value = atoi(token_ptr); - if (parameter_ribi[i]) { - value = parameter_values[i]; - sprintf(parameter_name[ names++ ], "%.*s", (int)strcspn(buffer+name_length+1,","), buffer+name_length+1); - name_length += strcspn(buffer+name_length+1,",") + 1; - } - parameter_value[i][parameter_values[i]++] = value; - break; - case '-': - if (parameter_ribi[i]) { - value = parameter_values[i]; - sprintf(parameter_name[value], "%.*s", (int)strcspn(buffer+name_length+1,","), buffer+name_length+1); - name_length += strcspn(buffer+name_length+1,",") + 1; - parameter_value[i][parameter_values[i]++] = value; - } - else { - const int start_range = parameter_value[i][parameter_values[i]-1]; - const int end_range = atoi(token_ptr); - - if (parameter_values[i] + (end_range - start_range) >= 256) { - dbg->fatal("tabfile_t::read", "Invalid number range %d-%d (Max range %d values) in line %d", start_range, end_range, 256 - parameter_values[i], current_line_number); - } - - for(int range=start_range; rangewarning( "tabfile_t::read", "Line %d ignored. Insertion of substitution without name.", current_line_number); + } + break; + case 4: //forget substitution block + if(delim) { + sublines.remove(delim); + } + else{ + sublines.clear(); + } + break; + default: //Unknown command + dbg->warning( "tabfile_t::read", "Unknown command in line %d ignored. \"%s\"", current_line_number, line); + } + } + + // Handle regular lines. + else { + subname[0]='\0'; + line_to_obj = true; + } + + // Turn lines into key-value-pairs and store them in objinfo + if(line_to_obj) { + + // For regular lines, go through the loop once. + // For a substitution block, loop through each stored line. + // For a substitution block without lines stored, skip the loop. + for(size_t i=0; i < (subname[0] ? (sublines.access(subname) ? sublines.access(subname)->size() : 0) : 1); i++) { + + // Get lines from stored substitution block + if(subname[0]) { + strcpy(line, sublines.access(subname)->at(i)); + + // inline-replacement (replace in lines within a substitution block) + if(replacement[0]) { + char *c = line; + do { + c = strchr(c, '<'); + if(c && c[1] == '?' && c[2] == '>') { + *c++ = '\0'; + *c+=2; + strcat(line, replacement); + strcat(line, c); + } + } while(c++); } - combinations*=parameter_values[i]; } + + // Finally, the line can be seperated in key and value, expanded if shorthand is used, and put into objinfo + char *delim = strchr(line, '='); + + if(delim) { + *delim++ = '\0'; + format_key(line); + if (line[0] == 0) { + return false; + } - // start expansion of the parameter - for(int c=0; c0) { - // warp values around the number of parameters the expansion has - for(int j=0; j) + @param, array containing the text inside each [] field + @expansion, array containing the text inside each <> field + */ + if(find_parameter_expansion(line, delim, ¶meters, &expansions, param, expansion) > 0) { + int parameter_value[10][256]; + int parameter_length[10]; + int parameter_values[10]; // number of possible 'values' inside each [] field | e.g. [0-4]=5 / [n,s,w]=3 + char parameter_name[256][6]; // non-numeric ribis strings for all parameter fields consecutively + bool parameter_ribi[10]; // true if parameters are ribi strings + + int combinations=1; + int names = 0; // total number of ribi parameters + + // analyse and obtain all parameter expansions + for(int i=0; i= 256) { + dbg->fatal("tabfile_t::read", "Invalid number range %d-%d (Max range %d values) in line %d", start_range, end_range, 256 - parameter_values[i], current_line_number); + } + + for(int range=start_range; range0) { + // warp values around the number of parameters the expansion has + for(int j=0; j0) { - int expansion_length[10]; - int expansion_value[10]; + // expand the value + if(expansions>0) { + int expansion_length[10]; + int expansion_value[10]; - for(int i=0; i")-1; - sprintf(buffer, "%.*s", expansion_length[i]+1, expansion[i]); + for(int i=0; i")-1; + sprintf(buffer, "%.*s", expansion_length[i]+1, expansion[i]); - expansion_value[i] = calculate(buffer, parameter_value, parameters, combination); - } + expansion_value[i] = calculate(buffer, parameter_value, parameters, combination); + } - sprintf(delim_expand, "%.*s%d", (int)(expansion[0]-delim), delim, expansion_value[0]); - for(int i=1; iwarning( "tabfile_t::read", "No data in \"%s\"", line ); } } - lines = true; - } - else if( *line ) { - dbg->warning( "tabfile_t::read", "No data in \"%s\"", line ); + line_to_obj=false; } } } while(!lines && !feof(file)); // skip empty objects diff --git a/dataobj/tabfile.h b/dataobj/tabfile.h index 83239a566..c1a81a26c 100644 --- a/dataobj/tabfile.h +++ b/dataobj/tabfile.h @@ -8,6 +8,7 @@ #include +#include #include "../simcolor.h" #include "../tpl/stringhashtable_tpl.h" @@ -47,7 +48,7 @@ class tabfile_t public: tabfile_t() : file(NULL) {} ~tabfile_t() { close(); } - + stringhashtable_tpl> sublines; public: bool open(const char *filename); @@ -98,6 +99,11 @@ private: * Format the key string (trimright and lowercase) */ void format_key(char *key); + + /** + * Turns directives into integer values. + */ + int directive(char *dir); private: FILE *file;