+int uci_add_list(struct uci_context *ctx, struct uci_package *p, const char *section, const char *option, const char *value, struct uci_option **result)
+{
+ /* NB: UCI_INTERNAL use means without history tracking */
+ bool internal = ctx->internal;
+ struct uci_element *e;
+ struct uci_section *s;
+ struct uci_option *o;
+ struct uci_option *prev = NULL;
+ const char *value2 = NULL;
+
+ UCI_HANDLE_ERR(ctx);
+ UCI_ASSERT(ctx, p && section && option && value && uci_validate_text(value));
+
+ /* look up the section first */
+ UCI_INTERNAL(uci_lookup, ctx, &e, p, section, NULL);
+ s = uci_to_section(e);
+
+ e = uci_lookup_list(&s->options, option);
+ if (e) {
+ o = uci_to_option(e);
+ switch (o->type) {
+ case UCI_TYPE_STRING:
+ /* we already have a string value, let's convert that to a list */
+ prev = o;
+ value2 = value;
+ value = o->v.string;
+ break;
+ case UCI_TYPE_LIST:
+ if (result)
+ *result = o;
+
+ ctx->internal = internal;
+ return uci_add_element_list(ctx, o, value);
+ default:
+ UCI_THROW(ctx, UCI_ERR_INVAL);
+ break;
+ }
+ }
+
+ o = uci_alloc_list(s, option);
+ if (result)
+ *result = o;
+ if (prev) {
+ UCI_INTERNAL(uci_add_element_list, ctx, o, value);
+ uci_free_option(prev);
+ value = value2;
+ }
+
+ ctx->internal = internal;
+ return uci_add_element_list(ctx, o, value);
+}
+