summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ini/ini_configobj.h25
-rw-r--r--ini/ini_parse.c215
-rw-r--r--ini/ini_parse_ut.c6
-rw-r--r--ini/ini_print.c6
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 */