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 ''. Replacement not possible. \"%s\"", line);
+ continue;
+ }
+ char x = *t;
+ if( !( x == '>' || ( x >= '0' && x <= '9' ) ) ) {
+ dbg->warning("tabfile_t::replace", "Found ']. Replacement not possible. \"%s\"", line);
+ continue;
+ }
+ //allow > to act as 0>
+ 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;
};