diff --git a/shared/configfile.c b/shared/configfile.c index 2b71706..5dc31c2 100644 --- a/shared/configfile.c +++ b/shared/configfile.c @@ -594,20 +594,22 @@ static char get_next_char_f(FILE *f) /* Parser states */ #define ST_INITIAL 0 -#define ST_IGNORE 257 -#define ST_SECTIONNAME 258 +#define ST_COMMENT 257 +#define ST_SECTIONLABEL 258 #define ST_KEYNAME 259 -#define ST_VALUE 260 -#define ST_QUOTEDVALUE 261 -#define ST_QUOTEDVALUE_ESCCHAR 262 -#define ST_INVALID_SECTIONNAME 263 -#define ST_INVALID_KEYNAME 264 -#define ST_INVALID_VALUE 265 -#define ST_INVALID_QUOTEDVALUE 266 +#define ST_ASSIGNMENT 260 +#define ST_VALUE 261 +#define ST_QUOTEDVALUE 262 +#define ST_SECTIONLABEL_DONE 263 +#define ST_VALUE_DONE 264 +#define ST_INVALID_SECTIONLABEL 265 +#define ST_INVALID_KEYNAME 266 +#define ST_INVALID_ASSIGNMENT 267 +#define ST_INVALID_VALUE 268 #define ST_END 999 /* Limits */ -#define MAXSECTIONNAMELENGTH 40 +#define MAXSECTIONLABELLENGTH 40 #define MAXKEYNAMELENGTH 40 #define MAXVALUELENGTH 200 @@ -616,7 +618,7 @@ static int process_config(section **current_section, char(*get_next_char)(), con { int state = ST_INITIAL; char ch; - char sectionname[MAXSECTIONNAMELENGTH+1]; + char sectionname[MAXSECTIONLABELLENGTH+1]; int sectionname_pos = 0; char keyname[MAXKEYNAMELENGTH+1]; int keyname_pos = 0; @@ -625,6 +627,7 @@ static int process_config(section **current_section, char(*get_next_char)(), con int escape = 0; key *k; int line_nr = 1; + int error = 0; while (state != ST_END) { @@ -639,180 +642,206 @@ static int process_config(section **current_section, char(*get_next_char)(), con switch (state) { case ST_INITIAL: switch (ch) { - case '\n': - case '\r': - case '\t': - case ' ': - break; case '#': case ';': - case '=': - case ']': - /* It's a comment or an error */ - state = ST_IGNORE; - break; - case '[': - /* It's a section name */ - state = ST_SECTIONNAME; - sectionname[0] = '\0'; - sectionname_pos = 0; - break; - case '\0': - break; - default: - /* It's a keyname */ - state = ST_KEYNAME; - keyname[0] = ch; - keyname[1] = '\0'; - keyname_pos = 1; - } - break; - case ST_IGNORE: - switch (ch) { - case '\n': - state = ST_INITIAL; - break; - } - break; - case ST_SECTIONNAME: - switch (ch) { + /* comment start */ + state = ST_COMMENT; + /* fall through */ case '\0': case '\n': - report(RPT_WARNING, "Section name incorrectly closed on line %d of %s: %s", - line_nr, source_descr, sectionname); - state = ST_INITIAL; - break; case '\r': case '\t': case ' ': - case '"': + /* ignore spaces */ + break; case '[': - report(RPT_WARNING, "Invalid characters in section name on line %d of %s: %s", - line_nr, source_descr, sectionname); - state = ST_INVALID_SECTIONNAME; - break; - case ']': - if (!(*current_section=find_section(sectionname))) { - *current_section=add_section(sectionname); - } - state = ST_INITIAL; + /* section name */ + state = ST_SECTIONLABEL; + sectionname_pos = 0; + sectionname[sectionname_pos] = '\0'; break; default: - if (sectionname_pos < MAXSECTIONNAMELENGTH) { - sectionname[sectionname_pos++] = ch; - sectionname[sectionname_pos] = '\0'; - } else { - report(RPT_WARNING, "Section name too long on line %d of %s: %s", - line_nr, source_descr, sectionname); - state = ST_INVALID_SECTIONNAME; - } + /* key word */ + state = ST_KEYNAME; + keyname_pos = 0; + keyname[keyname_pos++] = ch; + keyname[keyname_pos] = '\0'; } break; - case ST_INVALID_SECTIONNAME: + case ST_SECTIONLABEL: + /* section label: "["{non-space chars}+"]" */ switch (ch) { + case '\0': case '\n': - case ']': - state = ST_INITIAL; + /* premature end of label */ + report(RPT_WARNING, "Unterminated section label on line %d of %s: %s", + line_nr, source_descr, sectionname); + error = 1; + state = ST_INITIAL; /* alrady at the end, no resync required */ break; + case ']': + /* label terminated: find/create section */ + if (!(*current_section = find_section(sectionname))) { + *current_section = add_section(sectionname); + } + state = ST_SECTIONLABEL_DONE; + break; + // case '\r': + // case '\t': + // case ' ': + // /* no spaces allowed in section labels WHY? */ + // report(RPT_WARNING, "Invalid character in section label on line %d of %s: %s", + // line_nr, source_descr, sectionname); + // error = 1; + // state = ST_INVALID_SECTIONLABEL; /* resync required */ + // break; + default: + /* append char to section label */ + if (sectionname_pos < MAXSECTIONLABELLENGTH) { + sectionname[sectionname_pos++] = ch; + sectionname[sectionname_pos] = '\0'; + break; + } + report(RPT_WARNING, "Section name too long on line %d of %s: %s", + line_nr, source_descr, sectionname); + error = 1; + state = ST_INVALID_SECTIONLABEL; /* resync required */ } break; case ST_KEYNAME: + /* key name: {non-space chars}+ */ switch (ch) { - case '\0': - case '\n': case '\r': case '\t': case ' ': + /* ignore trailing spaces */ + if (keyname_pos != 0) + state = ST_ASSIGNMENT; + break; + case '\0': + case '\n': + /* premature end of line */ report(RPT_WARNING, "Loose word found on line %d of %s: %s", line_nr, source_descr, keyname); - state = ST_INITIAL; - break; - case '"': - case '[': - case ']': - report(RPT_WARNING, "Invalid characters in key name on line %d of %s: %s", - line_nr, source_descr, keyname); - state = ST_INVALID_KEYNAME; + error = 1; + state = ST_INITIAL; /* already at the end; no resync required */ break; case '=': + /* end of key reached, "=" found, now we need a value */ + state = ST_VALUE; + value[0] = '\0'; + value_pos = 0; + break; + // case '"': + // case '[': + // case ']': + // /* character invalid in key names WHY ? */ + // report(RPT_WARNING, "Invalid character in key name on line %d of %s: %s", + // line_nr, source_descr, keyname); + // error = 1; + // state = ST_INVALID_KEYNAME; /* resync required */ + // break; + default: + /* append char to key name */ + if (keyname_pos < MAXKEYNAMELENGTH) { + keyname[keyname_pos++] = ch; + keyname[keyname_pos] = '\0'; + break; + } + report(RPT_WARNING, "Key name too long on line %d of %s: %s", + line_nr, source_descr, keyname); + error = 1; + state = ST_INVALID_KEYNAME; /* resync required */ + } + break; + case ST_ASSIGNMENT: + /* assignement: "=" */ + switch (ch) { + case '\t': + case ' ': + /* ignore leading spaces */ + break; + case '=': + /* "=" found, now we need a value */ state = ST_VALUE; value[0] = '\0'; value_pos = 0; break; default: - if (keyname_pos>=MAXKEYNAMELENGTH) { - report(RPT_WARNING, "Key name too long on line %d of %s: %s", - line_nr, source_descr, keyname); - state = ST_INVALID_KEYNAME; - } else { - keyname[keyname_pos++] = ch; - keyname[keyname_pos] = '\0'; - } - } - break; - case ST_INVALID_KEYNAME: - switch (ch) { - case '\n': - state = ST_INITIAL; + report(RPT_WARNING, "Assigment expected on line %d of %s: %s", + line_nr, source_descr, keyname); + error = 1; + state = ST_INVALID_ASSIGNMENT; } break; case ST_VALUE: + /* value: {non-space char}+ | "\""{any potentially-quoted char}+"\"" */ switch (ch) { - case '[': - case ']': case '#': case ';': + /* allow comment if we already had a value */ + /* WHY ONLY THEN ? 'xx=' can be seen as equivalent to 'xx=""' */ + if (value_pos > 0) { + state = ST_COMMENT; + break; + } + /* fall through */ + case '[': + case ']': case '=': - report(RPT_WARNING, "Invalid characters in value on line %d of %s, at key: %s", - line_nr, source_descr, keyname); + /* illegal characters WHY? */ + report(RPT_WARNING, "Invalid character '%c' in value on line %d of %s, at key: %s", + ch, line_nr, source_descr, keyname); + error = 1; state = ST_INVALID_VALUE; break; - case '"': - state = ST_QUOTEDVALUE; - break; + case '\t': + case ' ': + /* ignore leading spaces */ + if (value_pos == 0) + break; + /* fall through */ case '\0': case '\n': case '\r': - case '\t': - case ' ': - /* Value complete ! */ - if (! *current_section) { + /* value complete */ + if (!*current_section) { report(RPT_WARNING, "Data outside sections on line %d of %s with key: %s", line_nr, source_descr, keyname); + error = 1; } else { - /* Store the value */ + /* Store the value*/ k = add_key(*current_section, keyname, value); } - /* And be ready for next thing... */ - state = ST_INITIAL; - break; - default: - if (value_pos