#ifndef __LIBUCI_H
#define __LIBUCI_H
#ifdef __cplusplus
extern "C" {
#endif
#include "uci_config.h"
#include <stdbool.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#define UCI_CONFDIR "/etc/config"
#define UCI_SAVEDIR "/tmp/.uci"
#define UCI_DIRMODE 0700
#define UCI_FILEMODE 0600
enum
{
UCI_OK = 0,
UCI_ERR_MEM,
UCI_ERR_INVAL,
UCI_ERR_NOTFOUND,
UCI_ERR_IO,
UCI_ERR_PARSE,
UCI_ERR_DUPLICATE,
UCI_ERR_UNKNOWN,
UCI_ERR_LAST
};
struct uci_list;
struct uci_list
{
struct uci_list *next;
struct uci_list *prev;
};
struct uci_ptr;
struct uci_element;
struct uci_package;
struct uci_section;
struct uci_option;
struct uci_delta;
struct uci_context;
struct uci_backend;
struct uci_parse_option;
struct uci_parse_context;
extern struct uci_context *uci_alloc_context(void);
extern void uci_free_context(struct uci_context *ctx);
extern void uci_perror(struct uci_context *ctx, const char *str);
extern void uci_get_errorstr(struct uci_context *ctx, char **dest, const char *str);
extern int uci_import(struct uci_context *ctx, FILE *stream, const char *name, struct uci_package **package, bool single);
extern int uci_export(struct uci_context *ctx, FILE *stream, struct uci_package *package, bool header);
extern int uci_load(struct uci_context *ctx, const char *name, struct uci_package **package);
extern int uci_unload(struct uci_context *ctx, struct uci_package *p);
extern int uci_lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str, bool extended);
extern int uci_add_section(struct uci_context *ctx, struct uci_package *p, const char *type, struct uci_section **res);
extern int uci_set(struct uci_context *ctx, struct uci_ptr *ptr);
extern int uci_add_list(struct uci_context *ctx, struct uci_ptr *ptr);
extern int uci_del_list(struct uci_context *ctx, struct uci_ptr *ptr);
extern int uci_reorder_section(struct uci_context *ctx, struct uci_section *s, int pos);
extern int uci_rename(struct uci_context *ctx, struct uci_ptr *ptr);
extern int uci_delete(struct uci_context *ctx, struct uci_ptr *ptr);
extern int uci_save(struct uci_context *ctx, struct uci_package *p);
extern int uci_commit(struct uci_context *ctx, struct uci_package **p, bool overwrite);
extern int uci_list_configs(struct uci_context *ctx, char ***list);
extern int uci_set_savedir(struct uci_context *ctx, const char *dir);
extern int uci_set_confdir(struct uci_context *ctx, const char *dir);
extern int uci_add_delta_path(struct uci_context *ctx, const char *dir);
extern int uci_revert(struct uci_context *ctx, struct uci_ptr *ptr);
extern int uci_parse_argument(struct uci_context *ctx, FILE *stream, char **str, char **result);
extern int uci_set_backend(struct uci_context *ctx, const char *name);
extern bool uci_validate_text(const char *str);
int uci_parse_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str);
int uci_lookup_next(struct uci_context *ctx, struct uci_element **e, struct uci_list *list, const char *name);
void uci_parse_section(struct uci_section *s, const struct uci_parse_option *opts,
int n_opts, struct uci_option **tb);
uint32_t uci_hash_options(struct uci_option **tb, int n_opts);
enum uci_type {
UCI_TYPE_UNSPEC = 0,
UCI_TYPE_DELTA = 1,
UCI_TYPE_PACKAGE = 2,
UCI_TYPE_SECTION = 3,
UCI_TYPE_OPTION = 4,
UCI_TYPE_PATH = 5,
UCI_TYPE_BACKEND = 6,
UCI_TYPE_ITEM = 7,
UCI_TYPE_HOOK = 8,
};
enum uci_option_type {
UCI_TYPE_STRING = 0,
UCI_TYPE_LIST = 1,
};
enum uci_flags {
UCI_FLAG_STRICT = (1 << 0),
UCI_FLAG_PERROR = (1 << 1),
UCI_FLAG_EXPORT_NAME = (1 << 2),
UCI_FLAG_SAVED_DELTA = (1 << 3),
};
struct uci_element
{
struct uci_list list;
enum uci_type type;
char *name;
};
struct uci_backend
{
struct uci_element e;
char **(*list_configs)(struct uci_context *ctx);
struct uci_package *(*load)(struct uci_context *ctx, const char *name);
void (*commit)(struct uci_context *ctx, struct uci_package **p, bool overwrite);
const void *ptr;
void *priv;
};
struct uci_context
{
struct uci_list root;
struct uci_parse_context *pctx;
struct uci_backend *backend;
struct uci_list backends;
enum uci_flags flags;
char *confdir;
char *savedir;
struct uci_list delta_path;
int err;
const char *func;
jmp_buf trap;
bool internal, nested;
char *buf;
int bufsz;
};
struct uci_package
{
struct uci_element e;
struct uci_list sections;
struct uci_context *ctx;
bool has_delta;
char *path;
struct uci_backend *backend;
void *priv;
int n_section;
struct uci_list delta;
struct uci_list saved_delta;
};
struct uci_section
{
struct uci_element e;
struct uci_list options;
struct uci_package *package;
bool anonymous;
char *type;
};
struct uci_option
{
struct uci_element e;
struct uci_section *section;
enum uci_option_type type;
union {
struct uci_list list;
char *string;
} v;
};
enum uci_command {
UCI_CMD_ADD,
UCI_CMD_REMOVE,
UCI_CMD_CHANGE,
UCI_CMD_RENAME,
UCI_CMD_REORDER,
UCI_CMD_LIST_ADD,
UCI_CMD_LIST_DEL,
__UCI_CMD_MAX,
__UCI_CMD_LAST = __UCI_CMD_MAX - 1
};
extern char const uci_command_char[];
struct uci_delta
{
struct uci_element e;
enum uci_command cmd;
char *section;
char *value;
};
struct uci_ptr
{
enum uci_type target;
enum {
UCI_LOOKUP_DONE = (1 << 0),
UCI_LOOKUP_COMPLETE = (1 << 1),
UCI_LOOKUP_EXTENDED = (1 << 2),
} flags;
struct uci_package *p;
struct uci_section *s;
struct uci_option *o;
struct uci_element *last;
const char *package;
const char *section;
const char *option;
const char *value;
};
struct uci_parse_option {
const char *name;
enum uci_option_type type;
};
#ifndef container_of
#define container_of(ptr, type, member) \
((type *) ((char *)ptr - offsetof(type,member)))
#endif
#define list_to_element(ptr) \
container_of(ptr, struct uci_element, list)
#define uci_foreach_element(_list, _ptr) \
for(_ptr = list_to_element((_list)->next); \
&_ptr->list != (_list); \
_ptr = list_to_element(_ptr->list.next))
#define uci_foreach_element_safe(_list, _tmp, _ptr) \
for(_ptr = list_to_element((_list)->next), \
_tmp = list_to_element(_ptr->list.next); \
&_ptr->list != (_list); \
_ptr = _tmp, _tmp = list_to_element(_ptr->list.next))
#define uci_list_empty(list) ((list)->next == (list))
#define uci_type_backend UCI_TYPE_BACKEND
#define uci_type_delta UCI_TYPE_DELTA
#define uci_type_package UCI_TYPE_PACKAGE
#define uci_type_section UCI_TYPE_SECTION
#define uci_type_option UCI_TYPE_OPTION
#ifdef UCI_DEBUG_TYPECAST
static const char *uci_typestr[] = {
[uci_type_backend] = "backend",
[uci_type_delta] = "delta",
[uci_type_package] = "package",
[uci_type_section] = "section",
[uci_type_option] = "option",
};
static void uci_typecast_error(int from, int to)
{
fprintf(stderr, "Invalid typecast from '%s' to '%s'\n", uci_typestr[from], uci_typestr[to]);
}
#define BUILD_CAST(_type) \
static inline struct uci_ ## _type *uci_to_ ## _type (struct uci_element *e) \
{ \
if (e->type != uci_type_ ## _type) { \
uci_typecast_error(e->type, uci_type_ ## _type); \
} \
return (struct uci_ ## _type *) e; \
}
BUILD_CAST(backend)
BUILD_CAST(delta)
BUILD_CAST(package)
BUILD_CAST(section)
BUILD_CAST(option)
#else
#define uci_to_backend(ptr) container_of(ptr, struct uci_backend, e)
#define uci_to_delta(ptr) container_of(ptr, struct uci_delta, e)
#define uci_to_package(ptr) container_of(ptr, struct uci_package, e)
#define uci_to_section(ptr) container_of(ptr, struct uci_section, e)
#define uci_to_option(ptr) container_of(ptr, struct uci_option, e)
#endif
#define uci_alloc_element(ctx, type, name, datasize) \
uci_to_ ## type (uci_alloc_generic(ctx, uci_type_ ## type, name, sizeof(struct uci_ ## type) + datasize))
#define uci_dataptr(ptr) \
(((char *) ptr) + sizeof(*ptr))
static inline struct uci_package *
uci_lookup_package(struct uci_context *ctx, const char *name)
{
struct uci_element *e = NULL;
if (uci_lookup_next(ctx, &e, &ctx->root, name) == 0)
return uci_to_package(e);
else
return NULL;
}
static inline struct uci_section *
uci_lookup_section(struct uci_context *ctx, struct uci_package *p, const char *name)
{
struct uci_element *e = NULL;
if (uci_lookup_next(ctx, &e, &p->sections, name) == 0)
return uci_to_section(e);
else
return NULL;
}
static inline struct uci_option *
uci_lookup_option(struct uci_context *ctx, struct uci_section *s, const char *name)
{
struct uci_element *e = NULL;
if (uci_lookup_next(ctx, &e, &s->options, name) == 0)
return uci_to_option(e);
else
return NULL;
}
static inline const char *
uci_lookup_option_string(struct uci_context *ctx, struct uci_section *s, const char *name)
{
struct uci_option *o;
o = uci_lookup_option(ctx, s, name);
if (!o || o->type != UCI_TYPE_STRING)
return NULL;
return o->v.string;
}
#ifndef BITS_PER_LONG
#define BITS_PER_LONG (8 * sizeof(unsigned long))
#endif
static inline void uci_bitfield_set(unsigned long *bits, int bit)
{
bits[bit / BITS_PER_LONG] |= (1UL << (bit % BITS_PER_LONG));
}
#ifdef __cplusplus
}
#endif
#endif