<libroxml  version="3.0.2" />
contact: tristan.lelong@libroxml.net
roxml_commit.c
Go to the documentation of this file.
1
12#include <stdlib.h>
13#include <string.h>
14#include <stdarg.h>
15#include <unistd.h>
16#include "roxml_core.h"
17
18ROXML_STATIC ROXML_INT void roxml_realloc_buf(char **buf, int *len, int min_len)
19{
20 int append = (min_len | (ROXML_BASE_LEN - 1)) + 1;
21 *buf = realloc(*buf, *len + append);
22 memset(*buf + *len, 0, append);
23 *len += append;
24}
25
37ROXML_STATIC ROXML_INT void roxml_print_spaces(FILE *f, char **buf, int *offset, int *len, int lvl)
38{
39 int i;
40
41 if (f) {
42 if ((*offset)++ > 0)
43 fwrite("\n", 1, 1, f);
44 for (i = 0; i < lvl; i++)
45 fwrite(" ", 1, 1, f);
46 } else if (buf && *buf) {
47 if (*offset + lvl + 1 >= *len)
48 roxml_realloc_buf(buf, len, lvl);
49 if (*offset > 0)
50 *(*buf + (*offset)++) = '\n';
51 for (i = 0; i < lvl; i++)
52 *(*buf + (*offset)++) = ' ';
53 }
54}
55
67ROXML_STATIC ROXML_INT void roxml_write_string(FILE *f, char **buf, int *offset, int *len, char *str, ...)
68{
69 va_list args;
70 int min_len;
71
72 va_start(args, str);
73 min_len = vsnprintf(NULL, 0, str, args);
74 va_end(args);
75
76 va_start(args, str);
77
78 if (f) {
79 vfprintf(f, str, args);
80 } else if (buf && *buf) {
81 if (*offset + min_len >= *len)
82 roxml_realloc_buf(buf, len, min_len);
83 *offset += vsprintf(*buf + *offset, str, args);
84 }
85
86 va_end(args);
87}
88
89ROXML_STATIC ROXML_INT void roxml_write_other_node(node_t *n, FILE *f, char **buf, int *offset, int *len, char *name)
90{
91 char *value;
92 int status;
93 char head[8] = "\0";
94 char tail[8] = "\0";
95 char cdata_head[16] = "\0";
96 char cdata_tail[8] = "\0";
97
98 ROXML_GET_BASE_BUFFER(val);
99
100 if ((n->type & ROXML_NODE_TYPES) == ROXML_CMT_NODE) {
101 strcpy(head, "<!--");
102 strcpy(tail, "-->");
103 } else if ((n->type & ROXML_NODE_TYPES) == ROXML_DOCTYPE_NODE) {
104 strcpy(head, "<");
105 strcpy(tail, ">");
106 } else if ((n->type & ROXML_NODE_TYPES) == ROXML_PI_NODE) {
107 strcpy(head, "<?");
108 strcpy(tail, "?>");
109 }
110
111 value = roxml_get_content(n, val, ROXML_BASE_LEN, &status);
112 if (status >= ROXML_BASE_LEN)
113 value = roxml_get_content(n, NULL, 0, &status);
114
115 if ((n->type & ROXML_CDATA_NODE) == ROXML_CDATA_NODE) {
116 strcpy(cdata_head, "<![CDATA[");
117 strcpy(cdata_tail, "]]>");
118 }
119
120 roxml_write_string(f, buf, offset, len, "%s%s%s%s%s%s%s", head,
121 name[0] ? name : "", name[0] ? " " : "", cdata_head, value, cdata_tail, tail);
122 roxml_release(value);
123
124 ROXML_PUT_BASE_BUFFER(val);
125}
126
127ROXML_STATIC ROXML_INT void roxml_write_elm_name_open(node_t *n, FILE *f, char **buf, int *offset, int *len,
128 char *name, char *ns)
129{
130 if (!n->prnt)
131 return;
132
133 if (n->ns)
135 else
136 ns[0] = '\0';
137
138 roxml_write_string(f, buf, offset, len, "<%s%s%s", ns[0] ? ns : "", ns[0] ? ":" : "", name);
139}
140
141ROXML_STATIC ROXML_INT void roxml_write_elm_name_close(node_t *n, FILE *f, char **buf, int *offset, int *len,
142 char *name, char *ns)
143{
144 char head[8] = "\0";
145 char tail[8] = "/>";
146
147 if (n->chld) {
148 strcpy(head, "</");
149 strcpy(tail, ">");
150 }
151
152 roxml_write_string(f, buf, offset, len, "%s%s%s%s%s", head,
153 n->chld && ns[0] ? ns : "", n->chld && ns[0] ? ":" : "", n->chld ? name : "", tail);
154}
155
156ROXML_STATIC ROXML_INT void roxml_write_elm_attr(node_t *n, FILE *f, char **buf, int *offset, int *len)
157{
158 node_t *attr = n->attr;
159
160 while (attr) {
161 int ns_node_attr = attr->type & ROXML_NS_NODE;
162 int status = 0;
163 char arg[ROXML_BASE_LEN];
164 char val[ROXML_BASE_LEN];
165 char *value;
166
167 ROXML_GET_BASE_BUFFER(ns);
168
169 roxml_get_name(attr, arg, ROXML_BASE_LEN);
170
171 value = roxml_get_content(attr, val, ROXML_BASE_LEN, &status);
172 if (status >= ROXML_BASE_LEN)
173 value = roxml_get_content(attr, NULL, 0, &status);
174
175 if (attr->ns)
176 roxml_get_name(attr->ns, ns, ROXML_BASE_LEN);
177
178 roxml_write_string(f, buf, offset, len, " %s%s%s%s%s=\"%s\"",
179 ns_node_attr ? "xmlns" : "",
180 ns_node_attr && arg[0] ? ":" : "",
181 attr->ns ? ns : "", attr->ns ? ":" : "", arg, value);
182
183 attr = attr->sibl;
184 roxml_release(value);
185
186 ROXML_PUT_BASE_BUFFER(ns);
187 }
188}
189
203ROXML_STATIC ROXML_INT void roxml_write_node(node_t *n, FILE *f, char **buf, int human, int lvl, int *offset, int *len)
204{
205 ROXML_GET_BASE_BUFFER(name);
207
208 if (n->type & ROXML_ELM_NODE) {
209 ROXML_GET_BASE_BUFFER(ns);
210 node_t *chld = n->chld;
211
212 if (human)
213 roxml_print_spaces(f, buf, offset, len, lvl);
214 roxml_write_elm_name_open(n, f, buf, offset, len, name, ns);
215 roxml_write_elm_attr(n, f, buf, offset, len);
216
217 if (chld) {
218 node_t *prev = chld;
219
220 roxml_write_string(f, buf, offset, len, ">");
221
222 while (chld) {
223 int keep_human = human;
224
225 if ((chld->type | prev->type) & ROXML_TXT_NODE)
226 keep_human = 0;
227
228 roxml_write_node(chld, f, buf, keep_human, lvl + 1, offset, len);
229
230 prev = chld;
231 chld = chld->sibl;
232
233 }
234 if (human && !(prev->type & ROXML_TXT_NODE))
235 roxml_print_spaces(f, buf, offset, len, lvl);
236 }
237
238 roxml_write_elm_name_close(n, f, buf, offset, len, name, ns);
239 ROXML_PUT_BASE_BUFFER(ns);
240 } else {
241 if (human)
242 roxml_print_spaces(f, buf, offset, len, lvl);
243 roxml_write_other_node(n, f, buf, offset, len, name);
244 }
245
246 ROXML_PUT_BASE_BUFFER(name);
247}
248
249ROXML_STATIC ROXML_INT void roxml_commit_nodes(node_t *n, FILE *f, char **buf, int human, int *size, int *len)
250{
251 node_t fakeroot;
252
253 if (n->prnt == NULL) {
254 /* Get the first child since we do not write the docroot */
255 n = n->chld;
256 } else if (n->prnt->prnt == NULL) {
257 /* Get the first sibling since it might be a PI */
258 n = n->prnt->chld;
259 } else {
260 /* The root is a subtree: simulate a real root */
261 memcpy(&fakeroot, n, sizeof(node_t));
262 fakeroot.sibl = NULL;
263 n = &fakeroot;
264 }
265
266 while (n) {
267 roxml_write_node(n, f, buf, human, 0, size, len);
268 n = n->sibl;
269 }
270}
271
272ROXML_API int roxml_commit_file(node_t *n, char *dest, int human)
273{
274 FILE *fout;
275 int size = 0;
276 int len = ROXML_BASE_LEN;
277
278 if (n == ROXML_INVALID_DOC)
279 return 0;
280
281 if (!dest)
282 return 0;
283
284 fout = fopen(dest, "w");
285 if (!fout)
286 return 0;
287
288 roxml_commit_nodes(n, fout, NULL, human, &size, &len);
289
290 size = ftell(fout);
291 fclose(fout);
292
293 return size;
294}
295
296ROXML_API int roxml_commit_buffer(node_t *n, char **buffer, int human)
297{
298 int size = 0;
299 int len = ROXML_BASE_LEN;
300
301 if (n == ROXML_INVALID_DOC)
302 return 0;
303
304 if (!buffer)
305 return 0;
306
307 *buffer = malloc(ROXML_BASE_LEN);
308 if (!*buffer)
309 return 0;
310 memset(*buffer, 0, ROXML_BASE_LEN);
311
312 roxml_commit_nodes(n, NULL, buffer, human, &size, &len);
313
314 return size;
315}
316
317ROXML_API int roxml_commit_fd(node_t *n, int fd, int human)
318{
319 int fd2;
320 FILE *fout;
321 int size = 0;
322 int len = ROXML_BASE_LEN;
323
324 if (n == ROXML_INVALID_DOC)
325 return 0;
326
327 if (fd <= 0)
328 return 0;
329
330 /* in order to avoid accidental close of fd, we need dup() it */
331 fd2 = dup(fd);
332 if (fd2 < 0)
333 return 0;
334
335 /*
336 * fdopen(fd, "w") does not truncate the file - so the user
337 * must have called ftruncate() before calling this function
338 * if needed ; otherwise, data will be appended to the file.
339 */
340
341 fout = fdopen(fd2, "w");
342 if (!fout)
343 return 0;
344
345 roxml_commit_nodes(n, fout, NULL, human, &size, &len);
346
347 /* since we pass a fd to this function, we expect it to not be
348 * buffered, so flush everything before doing anything else */
349 fflush(fout);
350
351 size = ftell(fout);
352 fclose(fout);
353
354 return size;
355}
356
357ROXML_API int roxml_commit_changes(node_t *n, char *dest, char **buffer, int human)
358{
359 if (dest)
360 return roxml_commit_file(n, dest, human);
361 else if (buffer)
362 return roxml_commit_buffer(n, buffer, human);
363 return 0;
364}
#define ROXML_CMT_NODE
Definition roxml.h:86
#define ROXML_PI_NODE
Definition roxml.h:94
#define ROXML_INVALID_DOC
Definition roxml.h:235
ROXML_API void roxml_release(void *data)
memory cleanning function
Definition roxml_mem.c:109
#define ROXML_NS_NODE
Definition roxml.h:102
#define ROXML_TXT_NODE
Definition roxml.h:78
#define ROXML_ELM_NODE
Definition roxml.h:70
#define ROXML_API
Definition roxml.h:24
#define ROXML_CDATA_NODE
Definition roxml.h:126
#define ROXML_NODE_TYPES
Definition roxml.h:158
#define ROXML_DOCTYPE_NODE
Definition roxml.h:134
ROXML_STATIC ROXML_INT void roxml_write_string(FILE *f, char **buf, int *offset, int *len, char *str,...)
string writter function
ROXML_API int roxml_commit_buffer(node_t *n, char **buffer, int human)
sync to a memory buffer function
ROXML_STATIC ROXML_INT void roxml_print_spaces(FILE *f, char **buf, int *offset, int *len, int lvl)
space printing function
ROXML_API int roxml_commit_changes(node_t *n, char *dest, char **buffer, int human)
sync function
ROXML_API int roxml_commit_fd(node_t *n, int fd, int human)
sync to file descriptor function
ROXML_API int roxml_commit_file(node_t *n, char *dest, int human)
sync to named file function
ROXML_STATIC ROXML_INT void roxml_write_node(node_t *n, FILE *f, char **buf, int human, int lvl, int *offset, int *len)
tree write function
ROXML_API char * roxml_get_content(node_t *n, char *buffer, int bufsize, int *size)
content getter function
ROXML_API char * roxml_get_name(node_t *n, char *buffer, int size)
name getter function
XML parsing core module.
#define ROXML_BASE_LEN
node_t structure
struct node * prnt
unsigned short type
struct node * ns
struct node * chld
struct node * attr
struct node * sibl