static int trie_node_add_value(struct trie *trie, struct trie_node *node, const char *key, const char *value, const char *filename, uint16_t file_priority, uint32_t line_number) { ssize_t k, v, fn; struct trie_value_entry *val; k = strbuf_add_string(trie->strings, key, strlen(key)); if (k < 0) return k; v = strbuf_add_string(trie->strings, value, strlen(value)); if (v < 0) return v; fn = strbuf_add_string(trie->strings, filename, strlen(filename)); if (fn < 0) return fn; if (node->values_count) { struct trie_value_entry search = { .key_off = k, .value_off = v, }; val = xbsearch_r(&search, node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie); if (val) { /* At this point we have 2 identical properties on the same match-string. * Since we process files in order, we just replace the previous value. */ val->value_off = v; val->filename_off = fn; val->file_priority = file_priority; val->line_number = line_number; return 0; } } /* extend array, add new entry, sort for bisection */ val = reallocarray(node->values, node->values_count + 1, sizeof(struct trie_value_entry)); if (!val) return -ENOMEM; trie->values_count++; node->values = val; node->values[node->values_count].key_off = k; node->values[node->values_count].value_off = v; node->values[node->values_count].filename_off = fn; node->values[node->values_count].file_priority = file_priority; node->values[node->values_count].line_number = line_number; node->values_count++; qsort_r(node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie); return 0; }
static int trie_node_add_value(struct trie *trie, struct trie_node *node, const char *key, const char *value) { ssize_t k, v; struct trie_value_entry *val; k = strbuf_add_string(trie->strings, key, strlen(key)); if (k < 0) return k; v = strbuf_add_string(trie->strings, value, strlen(value)); if (v < 0) return v; if (node->values_count) { struct trie_value_entry search = { .key_off = k, .value_off = v, }; val = xbsearch_r(&search, node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp_r, trie); if (val) { /* replace existing earlier key with new value */ val->value_off = v; return 0; } } /* extend array, add new entry, sort for bisection */ val = realloc(node->values, (node->values_count + 1) * sizeof(struct trie_value_entry)); if (!val) return -ENOMEM; trie->values_count++; node->values = val; node->values[node->values_count].key_off = k; node->values[node->values_count].value_off = v; node->values_count++; trie_values_cmp_param = trie; qsort(node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp); return 0; }
static int finish_item( Hashmap *h, struct strbuf *sb, sd_id128_t id, const char *language, const char *payload) { ssize_t offset; _cleanup_free_ CatalogItem *i = NULL; int r; assert(h); assert(sb); assert(payload); offset = strbuf_add_string(sb, payload, strlen(payload)); if (offset < 0) return log_oom(); i = new0(CatalogItem, 1); if (!i) return log_oom(); i->id = id; if (language) { assert(strlen(language) > 1 && strlen(language) < 32); strcpy(i->language, language); } i->offset = htole64((uint64_t) offset); r = hashmap_put(h, i, i); if (r == -EEXIST) { log_warning("Duplicate entry for " SD_ID128_FORMAT_STR ".%s, ignoring.", SD_ID128_FORMAT_VAL(id), language ? language : "C"); return 0; } else if (r < 0) return r; i = NULL; return 0; }
static int trie_insert(struct trie *trie, struct trie_node *node, const char *search, const char *key, const char *value) { size_t i = 0; int err = 0; for (;;) { size_t p; uint8_t c; struct trie_node *child; for (p = 0; (c = trie->strings->buf[node->prefix_off + p]); p++) { _cleanup_free_ char *s = NULL; ssize_t off; _cleanup_free_ struct trie_node *new_child = NULL; if (c == search[i + p]) continue; /* split node */ new_child = calloc(sizeof(struct trie_node), 1); if (!new_child) return -ENOMEM; /* move values from parent to child */ new_child->prefix_off = node->prefix_off + p+1; new_child->children = node->children; new_child->children_count = node->children_count; new_child->values = node->values; new_child->values_count = node->values_count; /* update parent; use strdup() because the source gets realloc()d */ s = strndup(trie->strings->buf + node->prefix_off, p); if (!s) return -ENOMEM; off = strbuf_add_string(trie->strings, s, p); if (off < 0) return off; node->prefix_off = off; node->children = NULL; node->children_count = 0; node->values = NULL; node->values_count = 0; err = node_add_child(trie, node, new_child, c); if (err) return err; new_child = NULL; /* avoid cleanup */ break; } i += p; c = search[i]; if (c == '\0') return trie_node_add_value(trie, node, key, value); child = node_lookup(node, c); if (!child) { ssize_t off; /* new child */ child = calloc(sizeof(struct trie_node), 1); if (!child) return -ENOMEM; off = strbuf_add_string(trie->strings, search + i+1, strlen(search + i+1)); if (off < 0) { free(child); return off; } child->prefix_off = off; err = node_add_child(trie, node, child, c); if (err) { free(child); return err; } return trie_node_add_value(trie, child, key, value); } node = child; i++; } }
static ssize_t add_string(struct strbuf *sb, const char *s) { return strbuf_add_string(sb, s, strlen(s)); }