diff options
Diffstat (limited to 'ini')
-rw-r--r-- | ini/ini_configobj.h | 25 | ||||
-rw-r--r-- | ini/ini_parse.c | 215 | ||||
-rw-r--r-- | ini/ini_parse_ut.c | 6 | ||||
-rw-r--r-- | ini/ini_print.c | 6 |
4 files changed, 187 insertions, 65 deletions
diff --git a/ini/ini_configobj.h b/ini/ini_configobj.h index 824df17..5e8d95b 100644 --- a/ini/ini_configobj.h +++ b/ini/ini_configobj.h @@ -172,7 +172,10 @@ enum ERR_PARSE { ERR_DUPKEYSEC, /**< Duplicate key is detected while merging sections (Error). */ ERR_DUPSECTION, /**< Duplicate section is not allowed (Error). */ - ERR_MAXPARSE = ERR_DUPSECTION /**< Special value. Size of the error array. */ + ERR_SPECIAL, /**< Line contains invalid characters (Error). */ + ERR_TAB, /**< Line starts with tab when it + should not (Error). */ + ERR_MAXPARSE = ERR_TAB /**< Special value. Size of the error array. */ }; /** @@ -321,6 +324,25 @@ enum ERR_PARSE { */ /** + * @defgroup parseflags Flags that define parsing rules + * + * Flags that define how the file should be parsed. + * + * @{ + */ + +/** @brief Do not wrap */ +#define INI_PARSE_NOWRAP 0x0001 +/** @brief No spaces are allowed to the left of the key */ +#define INI_PARSE_NOSPACE 0x0002 +/** @brief No tabs are allowed to the left of the key */ +#define INI_PARSE_NOTAB 0x0004 + +/** + * @} + */ + +/** * @defgroup searchmode Constants that define how to look for a value * * Configuration file can allow several keys with the same name @@ -664,6 +686,7 @@ int ini_config_changed(struct ini_cfgfile *file_ctx1, int ini_config_parse(struct ini_cfgfile *file_ctx, int error_level, uint32_t collision_flags, + uint32_t parse_flags, struct ini_cfgobj *ini_config); /** diff --git a/ini/ini_parse.c b/ini/ini_parse.c index 2f65dfa..d009914 100644 --- a/ini/ini_parse.c +++ b/ini/ini_parse.c @@ -59,6 +59,8 @@ struct parser_obj { int error_level; /* Collistion flags */ uint32_t collision_flags; + /* Parseing flags */ + uint32_t parse_flags; /* Wrapping boundary */ uint32_t boundary; /* Action queue */ @@ -121,6 +123,53 @@ int is_just_spaces(const char *str, uint32_t len) return 1; } +/* Functions checks whether the line + * starts with the sequence of allowed blank characters. + * If spaces are allowed - function will say that line + * is OK. If tabls are allowed the function also would + * say that line is OK. If the mixture of both is allowed + * the line is OK too. + * Any other character will cause an error. + */ +int is_allowed_spaces(const char *str, + uint32_t len, + uint32_t parse_flags, + int *error) +{ + uint32_t i; + int line_ok = 1; + + TRACE_FLOW_ENTRY(); + + for (i = 0; i < len; i++) { + if ((str[i] == ' ') && + (parse_flags & INI_PARSE_NOSPACE)) { + /* Leading spaces are not allowed */ + *error = ERR_SPACE; + line_ok = 0; + break; + } + else if ((str[i] == '\t') && + (parse_flags & INI_PARSE_NOTAB)) { + /* Leading tabs are not allowed */ + *error = ERR_TAB; + line_ok = 0; + break; + } + else if ((str[i] == '\f') || + (str[i] == '\n') || + (str[i] == '\r') || + (str[i] == '\v')) { + *error = ERR_SPECIAL; + line_ok = 0; + break; + } + if (!isblank(str[i])) break; + } + + TRACE_FLOW_EXIT(); + return line_ok; +} /* Destroy parser object */ static void parser_destroy(struct parser_obj *po) @@ -152,6 +201,7 @@ static int parser_create(struct ini_cfgobj *co, const char *config_filename, int error_level, uint32_t collision_flags, + uint32_t parse_flags, struct collection_item *error_list, struct parser_obj **po) { @@ -202,6 +252,7 @@ static int parser_create(struct ini_cfgobj *co, new_po->filename = config_filename; new_po->error_level = error_level; new_po->collision_flags = collision_flags; + new_po->parse_flags = parse_flags; new_po->boundary = co->boundary; new_po->co = co; @@ -903,55 +954,6 @@ static int handle_comment(struct parser_obj *po, uint32_t *action) return EOK; } - -/* Process line starts with space */ -static int handle_space(struct parser_obj *po, uint32_t *action) -{ - int error = EOK; - - TRACE_FLOW_ENTRY(); - - /* Do we have current value object? */ - if (po->key) { - /* This is a new line in a folded value */ - error = value_add_to_arrays(po->last_read, - po->last_read_len, - po->raw_lines, - po->raw_lengths); - if (error) { - TRACE_ERROR_NUMBER("Failed to add line to value", error); - return error; - } - /* Do not free the line, it is now an element of the array */ - po->last_read = NULL; - po->last_read_len = 0; - *action = PARSE_READ; - } - else { - /* Check if this is a completely empty line */ - if (is_just_spaces(po->last_read, po->last_read_len)) { - error = handle_comment(po, action); - if (error) { - TRACE_ERROR_NUMBER("Failed to process comment", error); - return error; - } - } - else { - /* We do not have an active value - * but have a line is starting with a space. - * For now it is error. - * We can change it in future if - * people find it being too restrictive - */ - *action = PARSE_ERROR; - po->last_error = ERR_SPACE; - } - } - - TRACE_FLOW_EXIT(); - return EOK; -} - /* Handle key-value pair */ static int handle_kvp(struct parser_obj *po, uint32_t *action) { @@ -959,35 +961,46 @@ static int handle_kvp(struct parser_obj *po, uint32_t *action) char *eq = NULL; uint32_t len = 0; char *dupval = NULL; + char *str; + uint32_t full_len; TRACE_FLOW_ENTRY(); - TRACE_INFO_STRING("Last read:", po->last_read); + str = po->last_read; + full_len = po->last_read_len; + + TRACE_INFO_STRING("Last read:", str); + + /* Trim spaces at the beginning */ + while ((full_len > 0) && (isspace(*(str)))) { + str++; + full_len--; + } - /* We got a line with KVP */ - if (*(po->last_read) == '=') { + /* Check if we have the key */ + if (*(str) == '=') { po->last_error = ERR_NOKEY; *action = PARSE_ERROR; return EOK; } /* Find "=" */ - eq = strchr(po->last_read, '='); + eq = strchr(str, '='); if (eq == NULL) { - TRACE_ERROR_STRING("No equal sign", po->last_read); + TRACE_ERROR_STRING("No equal sign", str); po->last_error = ERR_NOEQUAL; *action = PARSE_ERROR; return EOK; } /* Strip spaces around "=" */ - /* Since eq > po->last_read we can substract 1 */ - len = eq - po->last_read - 1; - while ((len > 0) && (isspace(*(po->last_read + len)))) len--; + /* Since eq > str we can substract 1 */ + len = eq - str - 1; + while ((len > 0) && (isspace(*(str + len)))) len--; /* Adjust length properly */ len++; if (!len) { - TRACE_ERROR_STRING("No key", po->last_read); + TRACE_ERROR_STRING("No key", str); po->last_error = ERR_NOKEY; *action = PARSE_ERROR; return EOK; @@ -995,7 +1008,7 @@ static int handle_kvp(struct parser_obj *po, uint32_t *action) /* Check the key length */ if(len >= MAX_KEY) { - TRACE_ERROR_STRING("Key name is too long", po->last_read); + TRACE_ERROR_STRING("Key name is too long", str); po->last_error = ERR_LONGKEY; *action = PARSE_ERROR; return EOK; @@ -1017,14 +1030,14 @@ static int handle_kvp(struct parser_obj *po, uint32_t *action) return ENOMEM; } - memcpy(po->key, po->last_read, len); + memcpy(po->key, str, len); *(po->key + len) = '\0'; po->key_len = len; TRACE_INFO_STRING("Key:", po->key); TRACE_INFO_NUMBER("Keylen:", po->key_len); - len = po->last_read_len - (eq - po->last_read) - 1; + len = full_len - (eq - str) - 1; /* Trim spaces after equal sign */ eq++; @@ -1081,6 +1094,81 @@ static int handle_kvp(struct parser_obj *po, uint32_t *action) return EOK; } +/* Process line starts with space */ +static int handle_space(struct parser_obj *po, uint32_t *action) +{ + int error = EOK; + int space_err = 0; + + TRACE_FLOW_ENTRY(); + + if (po->parse_flags & INI_PARSE_NOWRAP) { + /* In this case an empty line is a comment. */ + if (is_just_spaces(po->last_read, po->last_read_len)) { + error = handle_comment(po, action); + TRACE_FLOW_EXIT(); + return error; + } + + /* Wrapping is not allowed */ + if (!is_allowed_spaces(po->last_read, + po->last_read_len, + po->parse_flags, + &space_err)) { + *action = PARSE_ERROR; + po->last_error = space_err; + error = EOK; + } + else { + /* Allowed spaces will be trimmed + * inside KVP processing. + */ + error = handle_kvp(po, action); + } + TRACE_FLOW_EXIT(); + return error; + } + + /* Do we have current value object? */ + if (po->key) { + /* This is a new line in a folded value */ + error = value_add_to_arrays(po->last_read, + po->last_read_len, + po->raw_lines, + po->raw_lengths); + if (error) { + TRACE_ERROR_NUMBER("Failed to add line to value", error); + return error; + } + /* Do not free the line, it is now an element of the array */ + po->last_read = NULL; + po->last_read_len = 0; + *action = PARSE_READ; + } + else { + /* Check if this is a completely empty line */ + if (is_just_spaces(po->last_read, po->last_read_len)) { + error = handle_comment(po, action); + if (error) { + TRACE_ERROR_NUMBER("Failed to process comment", error); + return error; + } + } + else { + /* We do not have an active value + * but have a line is starting with a space. + * For now it is error. + * We can change it in future if + * people find it being too restrictive + */ + *action = PARSE_ERROR; + po->last_error = ERR_SPACE; + } + } + + TRACE_FLOW_EXIT(); + return EOK; +} /* Parse and process section */ static int handle_section(struct parser_obj *po, uint32_t *action) @@ -1231,8 +1319,7 @@ static int parser_inspect(struct parser_obj *po) return error; } } - else if ((*(po->last_read) == ' ') || - (*(po->last_read) == '\t')) { + else if (isspace(*(po->last_read))) { error = handle_space(po, &action); if (error) { @@ -1507,6 +1594,7 @@ int parser_run(struct parser_obj *po) int ini_config_parse(struct ini_cfgfile *file_ctx, int error_level, uint32_t collision_flags, + uint32_t parse_flags, struct ini_cfgobj *ini_config) { int error = EOK; @@ -1541,6 +1629,7 @@ int ini_config_parse(struct ini_cfgfile *file_ctx, file_ctx->filename, error_level, collision_flags, + parse_flags, file_ctx->error_list, &po); if (error) { diff --git a/ini/ini_parse_ut.c b/ini/ini_parse_ut.c index 2c77947..3526d48 100644 --- a/ini/ini_parse_ut.c +++ b/ini/ini_parse_ut.c @@ -81,6 +81,7 @@ int test_one_file(const char *in_filename, error = ini_config_parse(file_ctx, INI_STOP_ON_NONE, 0, /* TBD */ + 0, ini_config); if (error) { INIOUT(printf("Failed to parse configuration. Error %d.\n", error)); @@ -382,6 +383,7 @@ int merge_values_test(void) error = ini_config_parse(file_ctx, INI_STOP_ON_ANY, mflags[i], + 0, ini_config); if (error) { INIOUT(printf("Failed to parse configuration. Error %d.\n", @@ -577,6 +579,7 @@ int merge_section_test(void) error = ini_config_parse(file_ctx, INI_STOP_ON_ANY, msecflags[i] | mflags[j], + 0, ini_config); if (error) { INIOUT(printf("Failed to parse configuration. " @@ -698,6 +701,7 @@ int read_one_file(char *name, error = ini_config_parse(file_ctx, INI_STOP_ON_ANY, collision_flags, + 0, ini_config); if (error) { INIOUT(printf("Failed to parse configuration. " @@ -1137,6 +1141,7 @@ int startup_test(void) error = ini_config_parse(file_ctx, INI_STOP_ON_NONE, 0, + 0, ini_config); if (error) { INIOUT(printf("Failed to parse configuration. Error %d.\n", error)); @@ -1420,6 +1425,7 @@ int get_test(void) INI_MS_MERGE | INI_MV1S_ALLOW | INI_MV2S_ALLOW, + 0, ini_config); if (error) { INIOUT(printf("Failed to parse configuration. Error %d.\n", error)); diff --git a/ini/ini_print.c b/ini/ini_print.c index d2d01c1..1812cd6 100644 --- a/ini/ini_print.c +++ b/ini/ini_print.c @@ -122,7 +122,11 @@ static const char *parsing_error_str(int parsing_error) _("Duplicate key is not allowed."), _("Duplicate key is detected while " "merging sections."), - _("Duplicate section is not allowed.") + _("Duplicate section is not allowed."), + _("Invalid character at the " + "beginning of the line."), + _("Invalid tab character at the " + "beginning of the line.") }; /* Check the range */ |