]> git.seodisparate.com - c_simple_http/commitdiff
Refactor config.c to change c-macros to functions
authorStephen Seo <seo.disparate@gmail.com>
Fri, 8 Nov 2024 05:00:36 +0000 (14:00 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Fri, 8 Nov 2024 05:00:36 +0000 (14:00 +0900)
Resolves https://git.seodisparate.com/stephenseo/c_simple_http/issues/9

src/config.c

index 5af1ffe644450d9daba9fbf807b5d627e8327e3d..1f76371f34a989b75c30a692948ab82c9b8a7dc5 100644 (file)
 // Local includes
 #include "constants.h"
 
-#define SINGLE_QUOTE_DECREMENT() \
-  for(; single_quote_count > 0; --single_quote_count) { \
-    if ((state & 1) == 0) { \
-      key_buf[key_idx++] = '\''; \
-      if (key_idx >= C_SIMPLE_HTTP_CONFIG_BUF_SIZE) { \
-        fprintf(stderr, \
-                "ERROR: config file \"key\" is larger than %u bytes!\n", \
-                C_SIMPLE_HTTP_CONFIG_BUF_SIZE - 1); \
-        c_simple_http_clean_up_parsed_config(&config); \
-        config.hash_map = NULL; \
-        return config; \
-      } \
-    } else { \
-      value_buf[value_idx++] = '\''; \
-      if (value_idx >= C_SIMPLE_HTTP_CONFIG_BUF_SIZE) { \
-        fprintf(stderr, \
-                "ERROR: config file \"value\" is larger than %u bytes!\n", \
-                C_SIMPLE_HTTP_CONFIG_BUF_SIZE - 1); \
-        c_simple_http_clean_up_parsed_config(&config); \
-        config.hash_map = NULL; \
-        return config; \
-      } \
-    } \
-  }
-
-#define DOUBLE_QUOTE_DECREMENT() \
-  for(; double_quote_count > 0; --double_quote_count) { \
-    if ((state & 1) == 0) { \
-      key_buf[key_idx++] = '"'; \
-      if (key_idx >= C_SIMPLE_HTTP_CONFIG_BUF_SIZE) { \
-        fprintf(stderr, \
-                "ERROR: config file \"key\" is larger than %u bytes!\n", \
-                C_SIMPLE_HTTP_CONFIG_BUF_SIZE - 1); \
-        c_simple_http_clean_up_parsed_config(&config); \
-        config.hash_map = NULL; \
-        return config; \
-      } \
-    } else { \
-      value_buf[value_idx++] = '"'; \
-      if (value_idx >= C_SIMPLE_HTTP_CONFIG_BUF_SIZE) { \
-        fprintf(stderr, \
-                "ERROR: config file \"value\" is larger than %u bytes!\n", \
-                C_SIMPLE_HTTP_CONFIG_BUF_SIZE - 1); \
-        c_simple_http_clean_up_parsed_config(&config); \
-        config.hash_map = NULL; \
-        return config; \
-      } \
-    } \
-  }
-
-#define CHECK_ADD_VALUE() \
-  if (value_idx < C_SIMPLE_HTTP_CONFIG_BUF_SIZE) { \
-    value_buf[value_idx++] = 0; \
-  } else { \
-    fprintf(stderr, \
-            "ERROR: config file \"value\" is larger than %u bytes!\n", \
-            C_SIMPLE_HTTP_CONFIG_BUF_SIZE - 1); \
-    c_simple_http_clean_up_parsed_config(&config); \
-    config.hash_map = NULL; \
-    return config; \
-  } \
-  state &= 0xFFFFFFFE; \
- \
-  /* Check if key is separating_key. */ \
-  if (strcmp((char*)key_buf, separating_key) == 0) { \
-    if (current_separating_key_value) { \
-      if (required_names) { \
-        C_SIMPLE_HTTP_HashMapWrapper *hash_map_wrapper = \
-          simple_archiver_hash_map_get( \
-            config.hash_map, \
-            current_separating_key_value, \
-            current_separating_key_value_size); \
-        C_SIMPLE_HTTP_INTERNAL_RequiredIter req_iter_struct; \
-        req_iter_struct.hash_map = hash_map_wrapper->hash_map; \
-        if (paths->count != 0) { \
-          req_iter_struct.path = paths->tail->prev->data; \
-        } else { \
-          req_iter_struct.path = NULL; \
-        } \
-        const char *missing_key = simple_archiver_list_get( \
-          required_names, \
-          c_simple_http_required_iter_fn, \
-          &req_iter_struct); \
-        if (missing_key) { \
-          fprintf(stderr, \
-                  "WARNING: config file did not have required key \"%s\"!" \
-                  " Returning NULL map!\n", \
-                  missing_key); \
-          c_simple_http_clean_up_parsed_config(&config); \
-          config.hash_map = NULL; \
-          return config; \
-        } \
-      } \
- \
-      state &= 0xFFFFFFFD; \
-      free(current_separating_key_value); \
-    } \
-    current_separating_key_value = malloc(value_idx); \
-    memcpy(current_separating_key_value, value_buf, value_idx); \
-    current_separating_key_value_size = value_idx; \
-    /* At this point, key is separating_key. */ \
-    SDArchiverHashMap *hash_map = simple_archiver_hash_map_init(); \
-    unsigned char *key = malloc(separating_key_size); \
-    strncpy((char*)key, separating_key, separating_key_size); \
-    unsigned char *value = malloc(value_idx); \
-    memcpy(value, value_buf, value_idx); \
-    if (simple_archiver_hash_map_insert(hash_map, \
-                                        value, \
-                                        key, \
-                                        separating_key_size, \
-                                        NULL, \
-                                        NULL) != 0) { \
-      fprintf(stderr, \
-        "ERROR: Failed to create hash map for new separating_key " \
-        "block!\n"); \
-      c_simple_http_clean_up_parsed_config(&config); \
-      config.hash_map = NULL; \
-      free(key); \
-      free(value); \
-      return config; \
-    } \
- \
-    C_SIMPLE_HTTP_HashMapWrapper *wrapper = malloc(sizeof(C_SIMPLE_HTTP_HashMapWrapper)); \
-    wrapper->paths = hash_map; \
- \
-    if (simple_archiver_hash_map_insert( \
-        config.hash_map, \
-        wrapper, \
-        value, \
-        value_idx, \
-        c_simple_http_hash_map_wrapper_cleanup_hashmap_fn, \
-        simple_archiver_helper_datastructure_cleanup_nop) != 0) { \
-      fprintf(stderr, \
-          "ERROR: Failed to insert new hash map for new PATH block!\n"); \
-      c_simple_http_clean_up_parsed_config(&config); \
-      config.hash_map = NULL; \
-      c_simple_http_hash_map_wrapper_cleanup(wrapper); \
-      return config; \
-    } \
-    simple_archiver_list_add(paths, value, \
-        simple_archiver_helper_datastructure_cleanup_nop); \
-  } else if (!current_separating_key_value) { \
-    fprintf( \
-        stderr, \
-        "ERROR: config file has invalid key: No preceding \"%s\" " \
-        "key!\n", separating_key); \
-    c_simple_http_clean_up_parsed_config(&config); \
-    config.hash_map = NULL; \
-    return config; \
-  } else { \
-    /* Non-separating_key key. */ \
-    C_SIMPLE_HTTP_HashMapWrapper *hash_map_wrapper = \
-      simple_archiver_hash_map_get( \
-        config.hash_map, \
-        current_separating_key_value, \
-        current_separating_key_value_size); \
-    if (!hash_map_wrapper) { \
-      fprintf(stderr, \
-        "ERROR: Internal error failed to get existing hash map with path " \
-        "\"%s\"!", current_separating_key_value); \
-      c_simple_http_clean_up_parsed_config(&config); \
-      config.hash_map = NULL; \
-      return config; \
-    } \
- \
-    unsigned char *key = malloc(key_idx); \
-    memcpy(key, key_buf, key_idx); \
-    unsigned char *value = malloc(value_idx); \
-    memcpy(value, value_buf, value_idx); \
- \
-    if (simple_archiver_hash_map_insert(hash_map_wrapper->paths, \
-                                        value, \
-                                        key, \
-                                        key_idx, \
-                                        NULL, \
-                                        NULL) != 0) { \
-      fprintf(stderr, \
-        "ERROR: Internal error failed to insert into hash map with path " \
-        "\"%s\"!", current_separating_key_value); \
-      c_simple_http_clean_up_parsed_config(&config); \
-      config.hash_map = NULL; \
-      free(key); \
-      free(value); \
-      return config; \
-    } \
-  } \
-  key_idx = 0; \
-  value_idx = 0;
-
-void c_simple_http_hash_map_wrapper_cleanup_hashmap_fn(void *data) {
-  C_SIMPLE_HTTP_HashMapWrapper *wrapper = data;
-  simple_archiver_hash_map_free(&wrapper->paths);
-  free(wrapper);
-}
-
-void c_simple_http_hash_map_wrapper_cleanup(C_SIMPLE_HTTP_HashMapWrapper *wrapper) {
-  simple_archiver_hash_map_free(&wrapper->paths);
-  free(wrapper);
-}
-
-void c_simple_http_hash_map_cleanup_helper(SDArchiverHashMap *hash_map) {
-  simple_archiver_hash_map_free(&hash_map);
-}
-
 typedef struct C_SIMPLE_HTTP_INTERNAL_RequiredIter {
   SDArchiverHashMap *hash_map;
   const char *path;
 } C_SIMPLE_HTTP_INTERNAL_RequiredIter;
 
+typedef struct C_SIMPLE_HTTP_INTERNAL_RequiredCheck {
+  const SDArchiverHashMap *map_of_paths_and_their_vars;
+  const SDArchiverLinkedList *required;
+} C_SIMPLE_HTTP_INTERNAL_RequiredCheck;
+
 int c_simple_http_required_iter_fn(void *data, void *ud) {
   C_SIMPLE_HTTP_INTERNAL_RequiredIter *req_iter_struct = ud;
   uint32_t data_str_length = (uint32_t)strlen(data) + 1;
@@ -260,10 +61,243 @@ int c_simple_http_required_iter_fn(void *data, void *ud) {
   return 0;
 }
 
-typedef struct C_SIMPLE_HTTP_INTERNAL_RequiredCheck {
-  const SDArchiverHashMap *map_of_paths_and_their_vars;
-  const SDArchiverLinkedList *required;
-} C_SIMPLE_HTTP_INTERNAL_RequiredCheck;
+void c_simple_http_hash_map_wrapper_cleanup_hashmap_fn(void *data) {
+  C_SIMPLE_HTTP_HashMapWrapper *wrapper = data;
+  simple_archiver_hash_map_free(&wrapper->paths);
+  free(wrapper);
+}
+
+void c_simple_http_hash_map_wrapper_cleanup(
+    C_SIMPLE_HTTP_HashMapWrapper *wrapper) {
+  simple_archiver_hash_map_free(&wrapper->paths);
+  free(wrapper);
+}
+
+/// Returns non-zero if config should be returned.
+int internal_single_quote_decrement(uint_fast8_t *single_quote_count,
+                                    uint32_t *state,
+                                    unsigned char *key_buf,
+                                    uint32_t *key_idx,
+                                    unsigned char *value_buf,
+                                    uint32_t *value_idx,
+                                    C_SIMPLE_HTTP_ParsedConfig *config) {
+  for(; (*single_quote_count) > 0; --(*single_quote_count)) {
+    if (((*state) & 1) == 0) {
+      key_buf[(*key_idx)++] = '\'';
+      if ((*key_idx) >= C_SIMPLE_HTTP_CONFIG_BUF_SIZE) {
+        fprintf(stderr,
+                "ERROR: config file \"key\" is larger than %u bytes!\n",
+                C_SIMPLE_HTTP_CONFIG_BUF_SIZE - 1);
+        c_simple_http_clean_up_parsed_config(config);
+        config->hash_map = NULL;
+        return 1;
+      }
+    } else {
+      value_buf[(*value_idx)++] = '\'';
+      if ((*value_idx) >= C_SIMPLE_HTTP_CONFIG_BUF_SIZE) {
+        fprintf(stderr,
+                "ERROR: config file \"value\" is larger than %u bytes!\n",
+                C_SIMPLE_HTTP_CONFIG_BUF_SIZE - 1);
+        c_simple_http_clean_up_parsed_config(config);
+        config->hash_map = NULL;
+        return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+/// Returns non-zero if config should be returned.
+int internal_double_quote_decrement(uint_fast8_t *double_quote_count,
+                                    uint32_t *state,
+                                    unsigned char *key_buf,
+                                    uint32_t *key_idx,
+                                    unsigned char *value_buf,
+                                    uint32_t *value_idx,
+                                    C_SIMPLE_HTTP_ParsedConfig *config) {
+  for(; (*double_quote_count) > 0; --(*double_quote_count)) {
+    if (((*state) & 1) == 0) {
+      key_buf[(*key_idx)++] = '"';
+      if ((*key_idx) >= C_SIMPLE_HTTP_CONFIG_BUF_SIZE) {
+        fprintf(stderr,
+                "ERROR: config file \"key\" is larger than %u bytes!\n",
+                C_SIMPLE_HTTP_CONFIG_BUF_SIZE - 1);
+        c_simple_http_clean_up_parsed_config(config);
+        config->hash_map = NULL;
+        return 1;
+      }
+    } else {
+      value_buf[(*value_idx)++] = '"';
+      if ((*value_idx) >= C_SIMPLE_HTTP_CONFIG_BUF_SIZE) {
+        fprintf(stderr,
+                "ERROR: config file \"value\" is larger than %u bytes!\n",
+                C_SIMPLE_HTTP_CONFIG_BUF_SIZE - 1);
+        c_simple_http_clean_up_parsed_config(config);
+        config->hash_map = NULL;
+        return 1;
+      }
+    }
+  }
+  return 0;
+}
+
+/// Returns non-zero if config should be returned.
+int internal_check_add_value(uint32_t *state,
+                             unsigned char *key_buf,
+                             uint32_t *key_idx,
+                             unsigned char *value_buf,
+                             uint32_t *value_idx,
+                             C_SIMPLE_HTTP_ParsedConfig *config,
+                             const char *separating_key,
+                             const SDArchiverLinkedList *required_names,
+                             const uint32_t separating_key_size,
+                             SDArchiverLinkedList *paths,
+                             char **current_separating_key_value,
+                             uint32_t *current_separating_key_value_size) {
+  if ((*value_idx) < C_SIMPLE_HTTP_CONFIG_BUF_SIZE) {
+    value_buf[(*value_idx)++] = 0;
+  } else {
+    fprintf(stderr,
+            "ERROR: config file \"value\" is larger than %u bytes!\n",
+            C_SIMPLE_HTTP_CONFIG_BUF_SIZE - 1);
+    c_simple_http_clean_up_parsed_config(config);
+    config->hash_map = NULL;
+    return 1;
+  }
+  (*state) &= 0xFFFFFFFE;
+
+  /* Check if key is separating_key. */
+  if (strcmp((char*)key_buf, separating_key) == 0) {
+    if (*current_separating_key_value) {
+      if (required_names) {
+        C_SIMPLE_HTTP_HashMapWrapper *hash_map_wrapper =
+          simple_archiver_hash_map_get(
+            config->hash_map,
+            (*current_separating_key_value),
+            (*current_separating_key_value_size));
+        C_SIMPLE_HTTP_INTERNAL_RequiredIter req_iter_struct;
+        req_iter_struct.hash_map = hash_map_wrapper->hash_map;
+        if (paths->count != 0) {
+          req_iter_struct.path = paths->tail->prev->data;
+        } else {
+          req_iter_struct.path = NULL;
+        }
+        const char *missing_key = simple_archiver_list_get(
+          required_names,
+          c_simple_http_required_iter_fn,
+          &req_iter_struct);
+        if (missing_key) {
+          fprintf(stderr,
+                  "WARNING: config file did not have required key \"%s\"!"
+                  " Returning NULL map!\n",
+                  missing_key);
+          c_simple_http_clean_up_parsed_config(config);
+          config->hash_map = NULL;
+          return 1;
+        }
+      }
+
+      (*state) &= 0xFFFFFFFD;
+      free((*current_separating_key_value));
+    }
+    (*current_separating_key_value) = malloc((*value_idx));
+    memcpy((*current_separating_key_value), value_buf, (*value_idx));
+    (*current_separating_key_value_size) = (*value_idx);
+    /* At this point, key is separating_key. */
+    SDArchiverHashMap *hash_map = simple_archiver_hash_map_init();
+    unsigned char *key = malloc(separating_key_size);
+    strncpy((char*)key, separating_key, separating_key_size);
+    unsigned char *value = malloc(*value_idx);
+    memcpy(value, value_buf, (*value_idx));
+    if (simple_archiver_hash_map_insert(hash_map,
+                                        value,
+                                        key,
+                                        separating_key_size,
+                                        NULL,
+                                        NULL) != 0) {
+      fprintf(stderr,
+        "ERROR: Failed to create hash map for new separating_key "
+        "block!\n");
+      c_simple_http_clean_up_parsed_config(config);
+      config->hash_map = NULL;
+      free(key);
+      free(value);
+      return 1;
+    }
+
+    C_SIMPLE_HTTP_HashMapWrapper *wrapper =
+      malloc(sizeof(C_SIMPLE_HTTP_HashMapWrapper));
+    wrapper->paths = hash_map;
+
+    if (simple_archiver_hash_map_insert(
+        config->hash_map,
+        wrapper,
+        value,
+        (*value_idx),
+        c_simple_http_hash_map_wrapper_cleanup_hashmap_fn,
+        simple_archiver_helper_datastructure_cleanup_nop) != 0) {
+      fprintf(stderr,
+          "ERROR: Failed to insert new hash map for new PATH block!\n");
+      c_simple_http_clean_up_parsed_config(config);
+      config->hash_map = NULL;
+      c_simple_http_hash_map_wrapper_cleanup(wrapper);
+      return 1;
+    }
+    simple_archiver_list_add(paths, value,
+        simple_archiver_helper_datastructure_cleanup_nop);
+  } else if (!(*current_separating_key_value)) {
+    fprintf(
+        stderr,
+        "ERROR: config file has invalid key: No preceding \"%s\" "
+        "key!\n", separating_key);
+    c_simple_http_clean_up_parsed_config(config);
+    config->hash_map = NULL;
+    return 1;
+  } else {
+    /* Non-separating_key key. */
+    C_SIMPLE_HTTP_HashMapWrapper *hash_map_wrapper =
+      simple_archiver_hash_map_get(
+        config->hash_map,
+        (*current_separating_key_value),
+        (*current_separating_key_value_size));
+    if (!hash_map_wrapper) {
+      fprintf(stderr,
+        "ERROR: Internal error failed to get existing hash map with path "
+        "\"%s\"!", (*current_separating_key_value));
+      c_simple_http_clean_up_parsed_config(config);
+      config->hash_map = NULL;
+      return 1;
+    }
+
+    unsigned char *key = malloc(*key_idx);
+    memcpy(key, key_buf, *key_idx);
+    unsigned char *value = malloc(*value_idx);
+    memcpy(value, value_buf, (*value_idx));
+
+    if (simple_archiver_hash_map_insert(hash_map_wrapper->paths,
+                                        value,
+                                        key,
+                                        *key_idx,
+                                        NULL,
+                                        NULL) != 0) {
+      fprintf(stderr,
+        "ERROR: Internal error failed to insert into hash map with path "
+        "\"%s\"!", (*current_separating_key_value));
+      c_simple_http_clean_up_parsed_config(config);
+      config->hash_map = NULL;
+      free(key);
+      free(value);
+      return 1;
+    }
+  }
+  (*key_idx) = 0;
+  (*value_idx) = 0;
+  return 0;
+}
+
+void c_simple_http_hash_map_cleanup_helper(SDArchiverHashMap *hash_map) {
+  simple_archiver_hash_map_free(&hash_map);
+}
 
 int c_simple_http_check_required_iter_fn(void *path_void_str, void *ud) {
   C_SIMPLE_HTTP_INTERNAL_RequiredCheck *req = ud;
@@ -332,8 +366,8 @@ C_SIMPLE_HTTP_ParsedConfig c_simple_http_parse_config(
   // 01xx - reading value is single quoted
   // 10xx - reading value is double quoted
   uint32_t state = 0;
-  unsigned char single_quote_count = 0;
-  unsigned char double_quote_count = 0;
+  uint_fast8_t single_quote_count = 0;
+  uint_fast8_t double_quote_count = 0;
   int32_t c;
 
   while (feof(f) == 0) {
@@ -342,20 +376,60 @@ C_SIMPLE_HTTP_ParsedConfig c_simple_http_parse_config(
       break;
     } else if ((state & 0xC) == 0 && (c == ' ' || c == '\t')) {
       // Ignore whitespace when not quoted.
-      SINGLE_QUOTE_DECREMENT();
-      DOUBLE_QUOTE_DECREMENT();
+      if (internal_single_quote_decrement(&single_quote_count,
+                                          &state,
+                                          key_buf,
+                                          &key_idx,
+                                          value_buf,
+                                          &value_idx,
+                                          &config)) {
+        return config;
+      }
+      if (internal_double_quote_decrement(&double_quote_count,
+                                          &state,
+                                          key_buf,
+                                          &key_idx,
+                                          value_buf,
+                                          &value_idx,
+                                          &config)) {
+        return config;
+      }
       continue;
     } else if ((state & 1) == 0
         && (state & 0xC) == 0
         && (c == '\r' || c == '\n')) {
       // Ignore newlines when parsing for key and when not quoted.
-      SINGLE_QUOTE_DECREMENT();
-      DOUBLE_QUOTE_DECREMENT();
+      if (internal_single_quote_decrement(&single_quote_count,
+                                          &state,
+                                          key_buf,
+                                          &key_idx,
+                                          value_buf,
+                                          &value_idx,
+                                          &config)) {
+        return config;
+      }
+      if (internal_double_quote_decrement(&double_quote_count,
+                                          &state,
+                                          key_buf,
+                                          &key_idx,
+                                          value_buf,
+                                          &value_idx,
+                                          &config)) {
+        return config;
+      }
       continue;
     } else if ((state & 1) == 1) {
       if (c == '\'') {
         ++single_quote_count;
-        DOUBLE_QUOTE_DECREMENT();
+        if (internal_double_quote_decrement(&double_quote_count,
+                                            &state,
+                                            key_buf,
+                                            &key_idx,
+                                            value_buf,
+                                            &value_idx,
+                                            &config)) {
+          return config;
+        }
 
         if (((state & 0xC) == 0x4 || (state & 0xC) == 0)
             && single_quote_count >= C_SIMPLE_HTTP_QUOTE_COUNT_MAX) {
@@ -371,7 +445,15 @@ C_SIMPLE_HTTP_ParsedConfig c_simple_http_parse_config(
         continue;
       } else if (c == '"') {
         ++double_quote_count;
-        SINGLE_QUOTE_DECREMENT();
+        if (internal_single_quote_decrement(&single_quote_count,
+                                            &state,
+                                            key_buf,
+                                            &key_idx,
+                                            value_buf,
+                                            &value_idx,
+                                            &config)) {
+          return config;
+        }
 
         if (((state & 0xC) == 0x8 || (state & 0xC) == 0)
             && double_quote_count >= C_SIMPLE_HTTP_QUOTE_COUNT_MAX) {
@@ -386,8 +468,24 @@ C_SIMPLE_HTTP_ParsedConfig c_simple_http_parse_config(
         }
         continue;
       } else {
-        SINGLE_QUOTE_DECREMENT();
-        DOUBLE_QUOTE_DECREMENT();
+        if (internal_single_quote_decrement(&single_quote_count,
+                                            &state,
+                                            key_buf,
+                                            &key_idx,
+                                            value_buf,
+                                            &value_idx,
+                                            &config)) {
+          return config;
+        }
+        if (internal_double_quote_decrement(&double_quote_count,
+                                            &state,
+                                            key_buf,
+                                            &key_idx,
+                                            value_buf,
+                                            &value_idx,
+                                            &config)) {
+          return config;
+        }
       }
     }
     if ((state & 1) == 0) {
@@ -426,7 +524,20 @@ C_SIMPLE_HTTP_ParsedConfig c_simple_http_parse_config(
           return config;
         }
       } else {
-        CHECK_ADD_VALUE()
+        if (internal_check_add_value(&state,
+                                     key_buf,
+                                     &key_idx,
+                                     value_buf,
+                                     &value_idx,
+                                     &config,
+                                     separating_key,
+                                     required_names,
+                                     separating_key_size,
+                                     paths,
+                                     &current_separating_key_value,
+                                     &current_separating_key_value_size)) {
+          return config;
+        }
       }
     }
   }
@@ -435,7 +546,20 @@ C_SIMPLE_HTTP_ParsedConfig c_simple_http_parse_config(
   if ((state & 0x1) == 1 && (state & 0xC) == 0 && value_idx != 0) {
     // Leftover "value" not added yet.
 
-    CHECK_ADD_VALUE()
+    if (internal_check_add_value(&state,
+                                 key_buf,
+                                 &key_idx,
+                                 value_buf,
+                                 &value_idx,
+                                 &config,
+                                 separating_key,
+                                 required_names,
+                                 separating_key_size,
+                                 paths,
+                                 &current_separating_key_value,
+                                 &current_separating_key_value_size)) {
+      return config;
+    }
   }
 
   if (!current_separating_key_value) {