<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 
18 ROXML_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 
37 ROXML_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 
67 ROXML_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 
89 ROXML_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 
127 ROXML_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 
141 ROXML_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 
156 ROXML_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 
203 ROXML_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);
206  roxml_get_name(n, name, ROXML_BASE_LEN);
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 
249 ROXML_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 
272 ROXML_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 
296 ROXML_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 
317 ROXML_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 
357 ROXML_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_INVALID_DOC
Definition: roxml.h:235
#define ROXML_NS_NODE
Definition: roxml.h:102
node_t structure
Definition: roxml_types.h:133
ROXML_API void roxml_release(void *data)
memory cleanning function
Definition: roxml_mem.c:109
struct node * attr
Definition: roxml_types.h:145
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
Definition: roxml_commit.c:203
ROXML_API int roxml_commit_changes(node_t *n, char *dest, char **buffer, int human)
sync function
Definition: roxml_commit.c:357
#define ROXML_PI_NODE
Definition: roxml.h:94
struct node * chld
Definition: roxml_types.h:143
ROXML_API int roxml_commit_buffer(node_t *n, char **buffer, int human)
sync to a memory buffer function
Definition: roxml_commit.c:296
#define ROXML_API
Definition: roxml.h:24
#define ROXML_DOCTYPE_NODE
Definition: roxml.h:134
ROXML_API int roxml_commit_file(node_t *n, char *dest, int human)
sync to named file function
Definition: roxml_commit.c:272
struct node * sibl
Definition: roxml_types.h:142
#define ROXML_CMT_NODE
Definition: roxml.h:86
ROXML_STATIC ROXML_INT void roxml_write_string(FILE *f, char **buf, int *offset, int *len, char *str,...)
string writter function
Definition: roxml_commit.c:67
struct node * ns
Definition: roxml_types.h:147
XML parsing core module.
ROXML_API char * roxml_get_content(node_t *n, char *buffer, int bufsize, int *size)
content getter function
ROXML_API int roxml_commit_fd(node_t *n, int fd, int human)
sync to file descriptor function
Definition: roxml_commit.c:317
#define ROXML_ELM_NODE
Definition: roxml.h:70
struct node * prnt
Definition: roxml_types.h:144
#define ROXML_BASE_LEN
Definition: roxml_defines.h:91
#define ROXML_NODE_TYPES
Definition: roxml.h:158
ROXML_STATIC ROXML_INT void roxml_print_spaces(FILE *f, char **buf, int *offset, int *len, int lvl)
space printing function
Definition: roxml_commit.c:37
#define ROXML_TXT_NODE
Definition: roxml.h:78
unsigned short type
Definition: roxml_types.h:134
ROXML_API char * roxml_get_name(node_t *n, char *buffer, int size)
name getter function
#define ROXML_CDATA_NODE
Definition: roxml.h:126