diff --git a/dataobj/tabfile.cc b/dataobj/tabfile.cc index 828955297..77479c9d6 100644 --- a/dataobj/tabfile.cc +++ b/dataobj/tabfile.cc @@ -26,6 +26,7 @@ bool tabfile_t::open(const char *filename) close(); file = dr_fopen(filename, "r"); current_line_number = 0; + replacements.assign(10,""); return file != NULL; } @@ -36,6 +37,8 @@ void tabfile_t::close() fclose(file); file = NULL; } + sublines.clear(); + replacements.clear(); } @@ -291,181 +294,371 @@ void tabfileobj_t::unused( const char *exclude_start_chars ) } +void tabfile_t::replace( char *line ) +{ + // looks at each char in the line. + for(char *s = line; *s; s++) { + if( !(*s == '<') ) { + continue; + } + char *t = s; // s stays at '<' while t looks ahead + t++; + if( !(*t == '?') ) { + continue; + } + t++; + if(!*t) { + dbg->warning("tabfile_t::replace", "Line ends in incomplete '' || ( x >= '0' && x <= '9' ) ) ) { + dbg->warning("tabfile_t::replace", "Found ']. Replacement not possible. \"%s\"", line); + continue; + } + //allow to act as + if (x == '>') { + x = '0'; + } + else { + t++; + if( !(*t == '>') ){ + dbg->warning("tabfile_t::replace", "Found ''. Replacement not possible. \"%s\"", line); + continue; + } + } + + // temporary store part of line AFTER , copy replacement in line, copy temp in line, end with '\0' + char temp[strlen(t)]; + t++; + strcpy(temp, t); + t = s; + for( char *u = replacements[x-'0']; *u; u++){ + *t = *u; + t++; + } + for( char *u = temp; *u; u++){ + *t = *u; + t++; + } + *t = '\0'; + s--; // ensures the same position is read again, since replacement might have been empty. + } +} + + +int tabfile_t::directive( char *dir ) +{ + const char *STARTSUB = ""; + const char *ENDSUB = ""; + const char *MARKER = ""; + const char *DELSUB = ""; + const char *REPLACE = ""; + if(!strcmp(dir, STARTSUB)){ + return 1; + } + if(!strcmp(dir, ENDSUB)){ + return 2; + } + if(!strcmp(dir, MARKER)){ + return 3; + } + if(!strcmp(dir, DELSUB)){ + return 4; + } + if(!strcmp(dir, REPLACE)){ + return '0'; + } + char temp[10]; + for(int i = '0'; i <= '9'; i++){ + strcpy(temp, REPLACE); + temp[strlen(REPLACE)-1] = i; + temp[strlen(REPLACE)] = '>'; + if(!strcmp(dir, temp)){ + return i; + } + } + 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 + 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; + + // 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) { + strcpy(subname, delim); + line_to_obj = true; + } + else{ + dbg->warning( "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; + //replacements (48-58) + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': + if(delim) { + char *helper = new char[strlen(delim)+1]; + strcpy(helper, delim); + replacements[directive(line)-'0'] = helper; + } + else{ + replacements[directive(line)-'0'] = ""; + } + 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)); + } + + // replacements + replace(line); + + // 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; } - 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; + + 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; 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; 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); + // start expansion of the parameter + for(int c=0; c0) { + // warp values around the number of parameters the expansion has + for(int j=0; j0) { - // 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..a0f7cd393 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,6 @@ class tabfile_t public: tabfile_t() : file(NULL) {} ~tabfile_t() { close(); } - public: bool open(const char *filename); @@ -98,11 +98,25 @@ private: * Format the key string (trimright and lowercase) */ void format_key(char *key); + + /** + * Turns directives into integer values. + */ + int directive(char *dir); + + /** + * replace instances of in a line with the content of replacements[n] + */ + void replace(char *line); private: FILE *file; int current_line_number; + + stringhashtable_tpl> sublines; + + std::vector replacements; };