initial import (incomplete)
[project/uci.git] / libuci.c
1 /*
2  * libuci - Library for the Unified Configuration Interface
3  * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License version 2.1
7  * as published by the Free Software Foundation
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14
15 /*
16  * This file contains some common code for the uci library
17  */
18
19 #include <sys/types.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include "libuci.h"
24
25 #define DEBUG
26
27 #ifdef DEBUG
28 #define DPRINTF(...) fprintf(stderr, __VA_ARGS__)
29 #else
30 #define DPRINTF(...)
31 #endif
32 /* 
33  * throw an uci exception and store the error number
34  * in the context.
35  */
36 #define UCI_THROW(ctx, err) do {        \
37         longjmp(ctx->trap, err);        \
38 } while (0)
39
40 /*
41  * store the return address for handling exceptions
42  * needs to be called in every externally visible library function
43  *
44  * NB: this does not handle recursion at all. Calling externally visible
45  * functions from other uci functions is only allowed at the end of the
46  * calling function.
47  */
48 #define UCI_HANDLE_ERR(ctx) do {                \
49         int __val;                      \
50         if (!ctx)                       \
51                 return UCI_ERR_INVAL;   \
52         __val = setjmp(ctx->trap);      \
53         if (__val) {                    \
54                 ctx->errno = __val;     \
55                 return __val;           \
56         }                               \
57 } while (0)
58
59 /*
60  * check the specified condition.
61  * throw an invalid argument exception if it's false
62  */
63 #define UCI_ASSERT(ctx, expr) do {      \
64         if (!(expr)) {                  \
65                 DPRINTF("[%s:%d] Assertion failed\n", __FILE__, __LINE__); \
66                 UCI_THROW(ctx, UCI_ERR_INVAL);  \
67         }                               \
68 } while (0)
69
70
71 static char *uci_errstr[] = {
72         [UCI_OK] =           "Success",
73         [UCI_ERR_MEM] =      "Out of memory",
74         [UCI_ERR_INVAL] =    "Invalid argument",
75         [UCI_ERR_NOTFOUND] = "Entry not found",
76         [UCI_ERR_PARSE] =    "Parse error",
77         [UCI_ERR_UNKNOWN] =  "Unknown error",
78 };
79
80
81 /*
82  * UCI wrapper for malloc, which uses exception handling
83  */
84 static void *uci_malloc(struct uci_context *ctx, size_t size)
85 {
86         void *ptr;
87         
88         ptr = malloc(size);
89         if (!ptr)
90                 UCI_THROW(ctx, UCI_ERR_MEM);
91         memset(ptr, 0, size);
92
93         return ptr;
94 }
95
96 /*
97  * UCI wrapper for realloc, which uses exception handling
98  */
99 static void *uci_realloc(struct uci_context *ctx, void *ptr, size_t size)
100 {
101         ptr = realloc(ptr, size);
102         if (!ptr)
103                 UCI_THROW(ctx, UCI_ERR_MEM);
104
105         return ptr;
106 }
107
108 #include "hash.c"
109 #include "parse.c"
110
111 /* externally visible functions */
112
113 struct uci_context *uci_alloc(void)
114 {
115         struct uci_context *ctx;
116         
117         ctx = (struct uci_context *) malloc(sizeof(struct uci_context));
118         memset(ctx, 0, sizeof(struct uci_context));
119         
120         return ctx;
121 }
122
123 int uci_cleanup(struct uci_context *ctx)
124 {
125         UCI_HANDLE_ERR(ctx);
126         uci_parse_cleanup(ctx);
127         return 0;
128 }
129
130 void uci_perror(struct uci_context *ctx, const char *str)
131 {
132         int err;
133
134         if (!ctx)
135                 err = UCI_ERR_INVAL;
136         else
137                 err = ctx->errno;
138         
139         if ((err < 0) || (err >= UCI_ERR_LAST))
140                 err = UCI_ERR_UNKNOWN;
141
142         switch (err) {
143         case UCI_ERR_PARSE:
144                 if (ctx->pctx) {
145                         fprintf(stderr, "%s: %s at line %d, byte %d\n", str, uci_errstr[err], ctx->pctx->line, ctx->pctx->byte);
146                         break;
147                 }
148                 /* fall through */
149         default:
150                 fprintf(stderr, "%s: %s\n", str, uci_errstr[err]);
151                 break;
152         }
153 }
154
155