+ /* create new item */
+ e1 = uci_alloc_generic(ctx, UCI_TYPE_ITEM, ptr->value, sizeof(struct uci_option));
+
+ if (!ptr->o) {
+ /* create new list */
+ UCI_TRAP_SAVE(ctx, error);
+ ptr->o = uci_alloc_list(ptr->s, ptr->option, NULL);
+ UCI_TRAP_RESTORE(ctx);
+ } else if (ptr->o->type == UCI_TYPE_STRING) {
+ /* create new list and add old string value as item to list */
+ struct uci_option *old = ptr->o;
+ UCI_TRAP_SAVE(ctx, error);
+ e2 = uci_alloc_generic(ctx, UCI_TYPE_ITEM, old->v.string, sizeof(struct uci_option));
+ ptr->o = uci_alloc_list(ptr->s, ptr->option, &old->e.list);
+ UCI_TRAP_RESTORE(ctx);
+ uci_list_add(&ptr->o->v.list, &e2->list);
+
+ /* remove old option */
+ if (ptr->option == old->e.name)
+ ptr->option = ptr->o->e.name;
+ uci_free_option(old);
+ }
+
+ /* add new item to list */
+ uci_list_add(&ptr->o->v.list, &e1->list);
+
+ if (!internal && ptr->p->has_delta)
+ uci_add_delta(ctx, &ptr->p->delta, UCI_CMD_LIST_ADD, ptr->section, ptr->option, ptr->value);
+
+ return 0;
+error:
+ if (e1 != NULL)
+ uci_free_element(e1);
+ if (e2 != NULL)
+ uci_free_element(e2);
+ UCI_THROW(ctx, ctx->err);
+}
+
+int uci_del_list(struct uci_context *ctx, struct uci_ptr *ptr)
+{
+ /* NB: pass on internal flag to uci_del_element */
+ bool internal = ctx && ctx->internal;
+ struct uci_element *e, *tmp;
+ struct uci_package *p;
+
+ UCI_HANDLE_ERR(ctx);
+
+ uci_expand_ptr(ctx, ptr, false);
+ UCI_ASSERT(ctx, ptr->s);
+ UCI_ASSERT(ctx, ptr->value);
+
+ if (!(ptr->o && ptr->option))
+ return 0;
+
+ if ((ptr->o->type != UCI_TYPE_LIST))
+ return 0;
+
+ p = ptr->p;
+ if (!internal && p->has_delta)
+ uci_add_delta(ctx, &p->delta, UCI_CMD_LIST_DEL, ptr->section, ptr->option, ptr->value);
+
+ uci_foreach_element_safe(&ptr->o->v.list, tmp, e) {
+ if (!strcmp(ptr->value, uci_to_option(e)->e.name)) {
+ uci_free_option(uci_to_option(e));
+ }