I know there are probably thousands of INI parser implementations in C.
Nevertheless I want to implement one to learn the art of parsing grammar.
I just wrote a small piece of the INI parser and wanted to ask if I am on the right track:
void parse_line(const char *str, char **name) {
size_t length = strlen(str);
bool found_section = false;
for (size_t pos = 0; pos < length; ++pos) {
char current = str[pos];
bool is_last_ch = (pos + 1) >= length;
//dbg("Processing %c", current);
if (current == '[') {
size_t updated_pos = pos + 1;
ssize_t match_pos = -1;
if (is_last_ch) {
dbg("Reached end of line without closing ] (1)!");
return;
}
if (found_section) {
dbg("Already found a section!");
return;
}
//dbg("Found a [ at position %zu, looking for ] now", pos);
for (size_t x = updated_pos; x < length; ++x) {
if (str[x] == ';') {
break;
} else if (str[x] == ']') {
match_pos = x;
break;
}
}
if (match_pos == -1) {
dbg("Reached end of line without closing ] (2)!");
return;
}
//dbg("Found matching ] at position %zd", match_pos);
assert(match_pos >= updated_pos);
size_t length_of_section = match_pos - updated_pos;
//dbg("Length of name is %zu", length_of_section);
char *section_name = malloc(length_of_section + 1);
assert(section_name);
for (size_t x = 0; x < length_of_section; ++x) {
size_t i = x + updated_pos;
section_name[x] = str[i];
}
section_name[length_of_section] = 0;
// utilize `section_name` in some way...
//dbg("Section name is: %s", section_name);
*name = section_name;
// and then free() it somewhere
pos += length_of_section + 1;
assert(pos < length);
found_section = true;
} else if (current == ']') {
dbg("Found unmatched ] at position %zu", pos);
return;
} else if (current == ';') {
//dbg("End of line, bye!");
return;
} else {
dbg("Unexpected character %c", current);
return;
}
}
}
At the moment it only parses name of sections (like [name]
).
I want to focus on detecting malformed grammar:
[section] comment
-> invalid
comment [section]
-> invalid
etc.
Example:
parse_line("[name]", ...); // gives "name"
parse_line("[name];Comment", ...); // gives "name"
parse_line(";[name];Comment", ...); // gives (null)
parse_line("[name[]", ...); // works... but should not (i already have a fix for this in mind -> check for "[" in section name fetching ; but is this good?)
Is the approach to ''wait'' for a character and then process from there on a robust way to parse things like INI files?