+ return NULL;
+}
+
+static struct uci_element *
+uci_lookup_ext_section(struct uci_context *ctx, struct uci_ptr *ptr)
+{
+ char *idxstr, *t, *section, *name;
+ struct uci_element *e = NULL;
+ struct uci_section *s;
+ int idx, c;
+
+ section = uci_strdup(ctx, ptr->section);
+ name = idxstr = section + 1;
+
+ if (section[0] != '@')
+ goto error;
+
+ /* parse the section index part */
+ idxstr = strchr(idxstr, '[');
+ if (!idxstr)
+ goto error;
+ *idxstr = 0;
+ idxstr++;
+
+ t = strchr(idxstr, ']');
+ if (!t)
+ goto error;
+ if (t[1] != 0)
+ goto error;
+ *t = 0;
+
+ t = NULL;
+ idx = strtol(idxstr, &t, 10);
+ if (t && *t)
+ goto error;
+
+ if (!*name)
+ name = NULL;
+ else if (!uci_validate_type(name))
+ goto error;
+
+ /* if the given index is negative, it specifies the section number from
+ * the end of the list */
+ if (idx < 0) {
+ c = 0;
+ uci_foreach_element(&ptr->p->sections, e) {
+ s = uci_to_section(e);
+ if (name && (strcmp(s->type, name) != 0))
+ continue;
+
+ c++;
+ }
+ idx += c;
+ }
+
+ c = 0;
+ uci_foreach_element(&ptr->p->sections, e) {
+ s = uci_to_section(e);
+ if (name && (strcmp(s->type, name) != 0))
+ continue;
+
+ if (idx == c)
+ goto done;
+ c++;
+ }
+ e = NULL;
+ goto done;
+
+error:
+ e = NULL;
+ memset(ptr, 0, sizeof(struct uci_ptr));
+ UCI_THROW(ctx, UCI_ERR_INVAL);
+done:
+ free(section);
+ if (e)
+ ptr->section = e->name;
+ return e;
+}
+
+int
+uci_lookup_next(struct uci_context *ctx, struct uci_element **e, struct uci_list *list, const char *name)
+{
+ UCI_HANDLE_ERR(ctx);
+
+ *e = uci_lookup_list(list, name);
+ if (!*e)
+ UCI_THROW(ctx, UCI_ERR_NOTFOUND);
+
+ return 0;
+}
+
+int
+uci_lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str, bool extended)
+{
+ struct uci_element *e;
+
+ UCI_HANDLE_ERR(ctx);
+ UCI_ASSERT(ctx, ptr != NULL);
+
+ if (str)
+ UCI_INTERNAL(uci_parse_ptr, ctx, ptr, str);
+
+ ptr->flags |= UCI_LOOKUP_DONE;
+
+ /* look up the package first */
+ if (ptr->p)
+ e = &ptr->p->e;
+ else
+ e = uci_lookup_list(&ctx->root, ptr->package);
+
+ if (!e) {
+ UCI_INTERNAL(uci_load, ctx, ptr->package, &ptr->p);
+ if (!ptr->p)
+ goto notfound;
+ ptr->last = &ptr->p->e;
+ } else {
+ ptr->p = uci_to_package(e);
+ ptr->last = e;
+ }
+
+ if (!ptr->section && !ptr->s)
+ goto complete;
+
+ /* if the section name validates as a regular name, pass through
+ * to the regular uci_lookup function call */
+ if (ptr->s) {
+ e = &ptr->s->e;
+ } else if (ptr->flags & UCI_LOOKUP_EXTENDED) {
+ if (extended)
+ e = uci_lookup_ext_section(ctx, ptr);
+ else
+ UCI_THROW(ctx, UCI_ERR_INVAL);
+ } else {
+ e = uci_lookup_list(&ptr->p->sections, ptr->section);
+ }
+
+ if (!e)
+ goto abort;
+
+ ptr->last = e;
+ ptr->s = uci_to_section(e);
+
+ if (ptr->option) {
+ e = uci_lookup_list(&ptr->s->options, ptr->option);
+ if (!e)
+ goto abort;
+
+ ptr->o = uci_to_option(e);
+ ptr->last = e;
+ }
+
+complete:
+ ptr->flags |= UCI_LOOKUP_COMPLETE;
+abort:
+ return 0;
+
+notfound: