Update hwloc to v1.11.12
[charm.git] / contrib / hwloc / src / topology-xml-nolibxml.c
blobd288198ede52ba2cb63d5ec4374f070dc297d912
1 /*
2 * Copyright © 2009 CNRS
3 * Copyright © 2009-2018 Inria. All rights reserved.
4 * Copyright © 2009-2011 Université Bordeaux
5 * Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
6 * See COPYING in top-level directory.
7 */
9 #include <private/autogen/config.h>
10 #include <hwloc.h>
11 #include <hwloc/plugins.h>
12 #include <private/private.h>
13 #include <private/misc.h>
14 #include <private/xml.h>
15 #include <private/debug.h>
17 #include <string.h>
18 #include <assert.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #ifdef HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
25 /*******************
26 * Import routines *
27 *******************/
29 struct hwloc__nolibxml_backend_data_s {
30 size_t buflen; /* size of both buffer and copy buffers, set during backend_init() */
31 char *buffer; /* allocated and filled during backend_init() */
32 char *copy; /* allocated during backend_init(), used later during actual parsing */
35 typedef struct hwloc__nolibxml_import_state_data_s {
36 char *tagbuffer; /* buffer containing the next tag */
37 char *attrbuffer; /* buffer containing the next attribute of the current node */
38 char *tagname; /* tag name of the current node */
39 int closed; /* set if the current node is auto-closing */
40 } __hwloc_attribute_may_alias * hwloc__nolibxml_import_state_data_t;
42 static char *
43 hwloc__nolibxml_import_ignore_spaces(char *buffer)
45 return buffer + strspn(buffer, " \t\n");
48 static int
49 hwloc__nolibxml_import_next_attr(hwloc__xml_import_state_t state, char **namep, char **valuep)
51 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
52 size_t namelen;
53 size_t len, escaped;
54 char *buffer, *value, *end;
56 if (!nstate->attrbuffer)
57 return -1;
59 /* find the beginning of an attribute */
60 buffer = hwloc__nolibxml_import_ignore_spaces(nstate->attrbuffer);
61 namelen = strspn(buffer, "abcdefghijklmnopqrstuvwxyz_");
62 if (buffer[namelen] != '=' || buffer[namelen+1] != '\"')
63 return -1;
64 buffer[namelen] = '\0';
65 *namep = buffer;
67 /* find the beginning of its value, and unescape it */
68 *valuep = value = buffer+namelen+2;
69 len = 0; escaped = 0;
70 while (value[len+escaped] != '\"') {
71 if (value[len+escaped] == '&') {
72 if (!strncmp(&value[1+len+escaped], "#10;", 4)) {
73 escaped += 4;
74 value[len] = '\n';
75 } else if (!strncmp(&value[1+len+escaped], "#13;", 4)) {
76 escaped += 4;
77 value[len] = '\r';
78 } else if (!strncmp(&value[1+len+escaped], "#9;", 3)) {
79 escaped += 3;
80 value[len] = '\t';
81 } else if (!strncmp(&value[1+len+escaped], "quot;", 5)) {
82 escaped += 5;
83 value[len] = '\"';
84 } else if (!strncmp(&value[1+len+escaped], "lt;", 3)) {
85 escaped += 3;
86 value[len] = '<';
87 } else if (!strncmp(&value[1+len+escaped], "gt;", 3)) {
88 escaped += 3;
89 value[len] = '>';
90 } else if (!strncmp(&value[1+len+escaped], "amp;", 4)) {
91 escaped += 4;
92 value[len] = '&';
93 } else {
94 return -1;
96 } else {
97 value[len] = value[len+escaped];
99 len++;
100 if (value[len+escaped] == '\0')
101 return -1;
103 value[len] = '\0';
105 /* find next attribute */
106 end = &value[len+escaped+1]; /* skip the ending " */
107 nstate->attrbuffer = hwloc__nolibxml_import_ignore_spaces(end);
108 return 0;
111 static int
112 hwloc__nolibxml_import_find_child(hwloc__xml_import_state_t state,
113 hwloc__xml_import_state_t childstate,
114 char **tagp)
116 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
117 hwloc__nolibxml_import_state_data_t nchildstate = (void*) childstate->data;
118 char *buffer = nstate->tagbuffer;
119 char *end;
120 size_t namelen;
122 childstate->parent = state;
123 childstate->global = state->global;
125 /* auto-closed tags have no children */
126 if (nstate->closed)
127 return 0;
129 /* find the beginning of the tag */
130 buffer = hwloc__nolibxml_import_ignore_spaces(buffer);
131 if (buffer[0] != '<')
132 return -1;
133 buffer++;
135 /* if closing tag, return nothing and do not advance */
136 if (buffer[0] == '/')
137 return 0;
139 /* normal tag */
140 *tagp = nchildstate->tagname = buffer;
142 /* find the end, mark it and return it */
143 end = strchr(buffer, '>');
144 if (!end)
145 return -1;
146 end[0] = '\0';
147 nchildstate->tagbuffer = end+1;
149 /* handle auto-closing tags */
150 if (end[-1] == '/') {
151 nchildstate->closed = 1;
152 end[-1] = '\0';
153 } else
154 nchildstate->closed = 0;
156 /* find attributes */
157 namelen = strspn(buffer, "abcdefghijklmnopqrstuvwxyz_");
159 if (buffer[namelen] == '\0') {
160 /* no attributes */
161 nchildstate->attrbuffer = NULL;
162 return 1;
165 if (buffer[namelen] != ' ')
166 return -1;
168 /* found a space, likely starting attributes */
169 buffer[namelen] = '\0';
170 nchildstate->attrbuffer = buffer+namelen+1;
171 return 1;
174 static int
175 hwloc__nolibxml_import_close_tag(hwloc__xml_import_state_t state)
177 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
178 char *buffer = nstate->tagbuffer;
179 char *end;
181 /* auto-closed tags need nothing */
182 if (nstate->closed)
183 return 0;
185 /* find the beginning of the tag */
186 buffer = hwloc__nolibxml_import_ignore_spaces(buffer);
187 if (buffer[0] != '<')
188 return -1;
189 buffer++;
191 /* find the end, mark it and return it to the parent */
192 end = strchr(buffer, '>');
193 if (!end)
194 return -1;
195 end[0] = '\0';
196 nstate->tagbuffer = end+1;
198 /* if closing tag, return nothing */
199 if (buffer[0] != '/' || strcmp(buffer+1, nstate->tagname) )
200 return -1;
201 return 0;
204 static void
205 hwloc__nolibxml_import_close_child(hwloc__xml_import_state_t state)
207 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
208 hwloc__nolibxml_import_state_data_t nparent = (void*) state->parent->data;
209 nparent->tagbuffer = nstate->tagbuffer;
212 static int
213 hwloc__nolibxml_import_get_content(hwloc__xml_import_state_t state,
214 char **beginp, size_t expected_length)
216 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
217 char *buffer = nstate->tagbuffer;
218 size_t length;
219 char *end;
221 /* auto-closed tags have no content */
222 if (nstate->closed) {
223 if (expected_length)
224 return -1;
225 *beginp = (char *) "";
226 return 0;
229 /* find the next tag, where the content ends */
230 end = strchr(buffer, '<');
231 if (!end)
232 return -1;
234 length = (size_t) (end-buffer);
235 if (length != expected_length)
236 return -1;
237 nstate->tagbuffer = end;
238 *end = '\0'; /* mark as 0-terminated for now */
239 *beginp = buffer;
240 return 1;
243 static void
244 hwloc__nolibxml_import_close_content(hwloc__xml_import_state_t state)
246 /* put back the '<' that we overwrote to 0-terminate the content */
247 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
248 if (!nstate->closed)
249 *nstate->tagbuffer = '<';
252 static int
253 hwloc_nolibxml_look_init(struct hwloc_xml_backend_data_s *bdata,
254 struct hwloc__xml_import_state_s *state)
256 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
257 struct hwloc__nolibxml_backend_data_s *nbdata = bdata->data;
258 char *buffer;
260 HWLOC_BUILD_ASSERT(sizeof(*nstate) <= sizeof(state->data));
262 /* use a copy in the temporary buffer, we may modify during parsing */
263 buffer = nbdata->copy;
264 memcpy(buffer, nbdata->buffer, nbdata->buflen);
266 /* skip headers */
267 while (!strncmp(buffer, "<?xml ", 6) || !strncmp(buffer, "<!DOCTYPE ", 10)) {
268 buffer = strchr(buffer, '\n');
269 if (!buffer)
270 goto failed;
271 buffer++;
274 /* find topology tag */
275 if (strncmp(buffer, "<topology>", 10)) {
276 if (hwloc__xml_verbose()) {
277 if (!strncmp(buffer, "<topology version=", 18))
278 fprintf(stderr, "%s: hwloc v1.x cannot import topology version >= 2.\n",
279 state->global->msgprefix);
280 else
281 fprintf(stderr, "%s: failed to find starting tag <topology>\n",
282 state->global->msgprefix);
284 goto failed;
287 state->global->next_attr = hwloc__nolibxml_import_next_attr;
288 state->global->find_child = hwloc__nolibxml_import_find_child;
289 state->global->close_tag = hwloc__nolibxml_import_close_tag;
290 state->global->close_child = hwloc__nolibxml_import_close_child;
291 state->global->get_content = hwloc__nolibxml_import_get_content;
292 state->global->close_content = hwloc__nolibxml_import_close_content;
293 state->parent = NULL;
294 nstate->closed = 0;
295 nstate->tagbuffer = buffer+10;
296 nstate->tagname = (char *) "topology";
297 nstate->attrbuffer = NULL;
298 return 0; /* success */
300 failed:
301 return -1; /* failed */
304 static void
305 hwloc_nolibxml_look_failed(struct hwloc_xml_backend_data_s *bdata __hwloc_attribute_unused)
307 if (hwloc__xml_verbose())
308 fprintf(stderr, "Failed to parse XML input with the minimalistic parser. If it was not\n"
309 "generated by hwloc, try enabling full XML support with libxml2.\n");
312 /********************
313 * Backend routines *
314 ********************/
316 static void
317 hwloc_nolibxml_backend_exit(struct hwloc_xml_backend_data_s *bdata)
319 struct hwloc__nolibxml_backend_data_s *nbdata = bdata->data;
320 free(nbdata->buffer);
321 free(nbdata->copy);
322 free(nbdata);
325 static int
326 hwloc_nolibxml_read_file(const char *xmlpath, char **bufferp, size_t *buflenp)
328 FILE * file;
329 size_t buflen, offset, readlen;
330 struct stat statbuf;
331 char *buffer, *tmp;
332 size_t ret;
334 if (!strcmp(xmlpath, "-"))
335 xmlpath = "/dev/stdin";
337 file = fopen(xmlpath, "r");
338 if (!file)
339 goto out;
341 /* find the required buffer size for regular files, or use 4k when unknown, we'll realloc later if needed */
342 buflen = 4096;
343 if (!stat(xmlpath, &statbuf))
344 if (S_ISREG(statbuf.st_mode))
345 buflen = statbuf.st_size+1; /* one additional byte so that the first fread() gets EOF too */
347 buffer = malloc(buflen+1); /* one more byte for the ending \0 */
348 if (!buffer)
349 goto out_with_file;
351 offset = 0; readlen = buflen;
352 while (1) {
353 ret = fread(buffer+offset, 1, readlen, file);
355 offset += ret;
356 buffer[offset] = 0;
358 if (ret != readlen)
359 break;
361 buflen *= 2;
362 tmp = realloc(buffer, buflen+1);
363 if (!tmp)
364 goto out_with_buffer;
365 buffer = tmp;
366 readlen = buflen/2;
369 fclose(file);
370 *bufferp = buffer;
371 *buflenp = offset+1;
372 return 0;
374 out_with_buffer:
375 free(buffer);
376 out_with_file:
377 fclose(file);
378 out:
379 return -1;
382 static int
383 hwloc_nolibxml_backend_init(struct hwloc_xml_backend_data_s *bdata,
384 const char *xmlpath, const char *xmlbuffer, int xmlbuflen)
386 struct hwloc__nolibxml_backend_data_s *nbdata = malloc(sizeof(*nbdata));
388 if (!nbdata)
389 goto out;
390 bdata->data = nbdata;
392 if (xmlbuffer) {
393 nbdata->buffer = malloc(xmlbuflen+1);
394 if (!nbdata->buffer)
395 goto out_with_nbdata;
396 nbdata->buflen = xmlbuflen+1;
397 memcpy(nbdata->buffer, xmlbuffer, xmlbuflen);
398 nbdata->buffer[xmlbuflen] = '\0';
400 } else {
401 int err = hwloc_nolibxml_read_file(xmlpath, &nbdata->buffer, &nbdata->buflen);
402 if (err < 0)
403 goto out_with_nbdata;
406 /* allocate a temporary copy buffer that we may modify during parsing */
407 nbdata->copy = malloc(nbdata->buflen+1);
408 if (!nbdata->copy)
409 goto out_with_buffer;
410 nbdata->copy[nbdata->buflen] = '\0';
412 bdata->look_init = hwloc_nolibxml_look_init;
413 bdata->look_failed = hwloc_nolibxml_look_failed;
414 bdata->backend_exit = hwloc_nolibxml_backend_exit;
415 return 0;
417 out_with_buffer:
418 free(nbdata->buffer);
419 out_with_nbdata:
420 free(nbdata);
421 out:
422 return -1;
425 static int
426 hwloc_nolibxml_import_diff(struct hwloc__xml_import_state_s *state,
427 const char *xmlpath, const char *xmlbuffer, int xmlbuflen,
428 hwloc_topology_diff_t *firstdiffp, char **refnamep)
430 hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
431 struct hwloc__xml_import_state_s childstate;
432 char *refname = NULL;
433 char *buffer, *tmp, *tag;
434 size_t buflen;
435 int ret;
437 HWLOC_BUILD_ASSERT(sizeof(*nstate) <= sizeof(state->data));
439 if (xmlbuffer) {
440 buffer = malloc(xmlbuflen);
441 if (!buffer)
442 goto out;
443 memcpy(buffer, xmlbuffer, xmlbuflen);
444 buflen = xmlbuflen;
446 } else {
447 ret = hwloc_nolibxml_read_file(xmlpath, &buffer, &buflen);
448 if (ret < 0)
449 goto out;
452 /* skip headers */
453 tmp = buffer;
454 while (!strncmp(tmp, "<?xml ", 6) || !strncmp(tmp, "<!DOCTYPE ", 10)) {
455 tmp = strchr(tmp, '\n');
456 if (!tmp)
457 goto out_with_buffer;
458 tmp++;
461 state->global->next_attr = hwloc__nolibxml_import_next_attr;
462 state->global->find_child = hwloc__nolibxml_import_find_child;
463 state->global->close_tag = hwloc__nolibxml_import_close_tag;
464 state->global->close_child = hwloc__nolibxml_import_close_child;
465 state->global->get_content = hwloc__nolibxml_import_get_content;
466 state->global->close_content = hwloc__nolibxml_import_close_content;
467 state->parent = NULL;
468 nstate->closed = 0;
469 nstate->tagbuffer = tmp;
470 nstate->tagname = NULL;
471 nstate->attrbuffer = NULL;
473 /* find root */
474 ret = hwloc__nolibxml_import_find_child(state, &childstate, &tag);
475 if (ret < 0)
476 goto out_with_buffer;
477 if (!tag || strcmp(tag, "topologydiff"))
478 goto out_with_buffer;
480 while (1) {
481 char *attrname, *attrvalue;
482 if (hwloc__nolibxml_import_next_attr(&childstate, &attrname, &attrvalue) < 0)
483 break;
484 if (!strcmp(attrname, "refname")) {
485 free(refname);
486 refname = strdup(attrvalue);
487 } else
488 goto out_with_buffer;
491 ret = hwloc__xml_import_diff(&childstate, firstdiffp);
492 if (refnamep && !ret)
493 *refnamep = refname;
494 else
495 free(refname);
497 free(buffer);
498 return ret;
500 out_with_buffer:
501 free(buffer);
502 free(refname);
503 out:
504 return -1;
507 /*******************
508 * Export routines *
509 *******************/
511 typedef struct hwloc__nolibxml_export_state_data_s {
512 char *buffer; /* (moving) buffer where to write */
513 size_t written; /* how many bytes were written (or would have be written if not truncated) */
514 size_t remaining; /* how many bytes are still available in the buffer */
515 unsigned indent; /* indentation level for the next line */
516 unsigned nr_children;
517 unsigned has_content;
518 } __hwloc_attribute_may_alias * hwloc__nolibxml_export_state_data_t;
520 static void
521 hwloc__nolibxml_export_update_buffer(hwloc__nolibxml_export_state_data_t ndata, int res)
523 if (res >= 0) {
524 ndata->written += res;
525 if (res >= (int) ndata->remaining)
526 res = ndata->remaining>0 ? (int)ndata->remaining-1 : 0;
527 ndata->buffer += res;
528 ndata->remaining -= res;
532 static char *
533 hwloc__nolibxml_export_escape_string(const char *src)
535 size_t fulllen, sublen;
536 char *escaped, *dst;
538 fulllen = strlen(src);
540 sublen = strcspn(src, "\n\r\t\"<>&");
541 if (sublen == fulllen)
542 return NULL; /* nothing to escape */
544 escaped = malloc(fulllen*6+1); /* escaped chars are replaced by at most 6 char */
545 dst = escaped;
547 memcpy(dst, src, sublen);
548 src += sublen;
549 dst += sublen;
551 while (*src) {
552 int replen;
553 switch (*src) {
554 case '\n': strcpy(dst, "&#10;"); replen=5; break;
555 case '\r': strcpy(dst, "&#13;"); replen=5; break;
556 case '\t': strcpy(dst, "&#9;"); replen=4; break;
557 case '\"': strcpy(dst, "&quot;"); replen=6; break;
558 case '<': strcpy(dst, "&lt;"); replen=4; break;
559 case '>': strcpy(dst, "&gt;"); replen=4; break;
560 case '&': strcpy(dst, "&amp;"); replen=5; break;
561 default: replen=0; break;
563 dst+=replen; src++;
565 sublen = strcspn(src, "\n\r\t\"<>&");
566 memcpy(dst, src, sublen);
567 src += sublen;
568 dst += sublen;
571 *dst = 0;
572 return escaped;
575 static void
576 hwloc__nolibxml_export_new_child(hwloc__xml_export_state_t parentstate,
577 hwloc__xml_export_state_t state,
578 const char *name)
580 hwloc__nolibxml_export_state_data_t npdata = (void *) parentstate->data;
581 hwloc__nolibxml_export_state_data_t ndata = (void *) state->data;
582 int res;
584 assert(!npdata->has_content);
585 if (!npdata->nr_children) {
586 res = hwloc_snprintf(npdata->buffer, npdata->remaining, ">\n");
587 hwloc__nolibxml_export_update_buffer(npdata, res);
589 npdata->nr_children++;
591 state->parent = parentstate;
592 state->new_child = parentstate->new_child;
593 state->new_prop = parentstate->new_prop;
594 state->add_content = parentstate->add_content;
595 state->end_object = parentstate->end_object;
597 ndata->buffer = npdata->buffer;
598 ndata->written = npdata->written;
599 ndata->remaining = npdata->remaining;
600 ndata->indent = npdata->indent + 2;
602 ndata->nr_children = 0;
603 ndata->has_content = 0;
605 res = hwloc_snprintf(ndata->buffer, ndata->remaining, "%*s<%s", (int) npdata->indent, "", name);
606 hwloc__nolibxml_export_update_buffer(ndata, res);
609 static void
610 hwloc__nolibxml_export_new_prop(hwloc__xml_export_state_t state, const char *name, const char *value)
612 hwloc__nolibxml_export_state_data_t ndata = (void *) state->data;
613 char *escaped = hwloc__nolibxml_export_escape_string(value);
614 int res = hwloc_snprintf(ndata->buffer, ndata->remaining, " %s=\"%s\"", name, escaped ? (const char *) escaped : value);
615 hwloc__nolibxml_export_update_buffer(ndata, res);
616 free(escaped);
619 static void
620 hwloc__nolibxml_export_end_object(hwloc__xml_export_state_t state, const char *name)
622 hwloc__nolibxml_export_state_data_t ndata = (void *) state->data;
623 hwloc__nolibxml_export_state_data_t npdata = (void *) state->parent->data;
624 int res;
626 assert (!(ndata->has_content && ndata->nr_children));
627 if (ndata->has_content) {
628 res = hwloc_snprintf(ndata->buffer, ndata->remaining, "</%s>\n", name);
629 } else if (ndata->nr_children) {
630 res = hwloc_snprintf(ndata->buffer, ndata->remaining, "%*s</%s>\n", (int) npdata->indent, "", name);
631 } else {
632 res = hwloc_snprintf(ndata->buffer, ndata->remaining, "/>\n");
634 hwloc__nolibxml_export_update_buffer(ndata, res);
636 npdata->buffer = ndata->buffer;
637 npdata->written = ndata->written;
638 npdata->remaining = ndata->remaining;
641 static void
642 hwloc__nolibxml_export_add_content(hwloc__xml_export_state_t state, const char *buffer, size_t length)
644 hwloc__nolibxml_export_state_data_t ndata = (void *) state->data;
645 int res;
647 assert(!ndata->nr_children);
648 if (!ndata->has_content) {
649 res = hwloc_snprintf(ndata->buffer, ndata->remaining, ">");
650 hwloc__nolibxml_export_update_buffer(ndata, res);
652 ndata->has_content = 1;
654 res = hwloc_snprintf(ndata->buffer, ndata->remaining, buffer, length);
655 hwloc__nolibxml_export_update_buffer(ndata, res);
658 static size_t
659 hwloc___nolibxml_prepare_export(hwloc_topology_t topology, char *xmlbuffer, int buflen)
661 struct hwloc__xml_export_state_s state, childstate;
662 hwloc__nolibxml_export_state_data_t ndata = (void *) &state.data;
663 int res;
665 HWLOC_BUILD_ASSERT(sizeof(*ndata) <= sizeof(state.data));
667 state.new_child = hwloc__nolibxml_export_new_child;
668 state.new_prop = hwloc__nolibxml_export_new_prop;
669 state.add_content = hwloc__nolibxml_export_add_content;
670 state.end_object = hwloc__nolibxml_export_end_object;
672 ndata->indent = 0;
673 ndata->written = 0;
674 ndata->buffer = xmlbuffer;
675 ndata->remaining = buflen;
677 ndata->nr_children = 1; /* don't close a non-existing previous tag when opening the topology tag */
678 ndata->has_content = 0;
680 res = hwloc_snprintf(ndata->buffer, ndata->remaining,
681 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
682 "<!DOCTYPE topology SYSTEM \"hwloc.dtd\">\n");
683 hwloc__nolibxml_export_update_buffer(ndata, res);
684 hwloc__nolibxml_export_new_child(&state, &childstate, "topology");
685 hwloc__xml_export_object (&childstate, topology, hwloc_get_root_obj(topology));
686 hwloc__nolibxml_export_end_object(&childstate, "topology");
688 return ndata->written+1; /* ending \0 */
691 static int
692 hwloc_nolibxml_export_buffer(hwloc_topology_t topology, char **bufferp, int *buflenp)
694 char *buffer;
695 size_t bufferlen, res;
697 bufferlen = 16384; /* random guess for large enough default */
698 buffer = malloc(bufferlen);
699 if (!buffer)
700 return -1;
701 res = hwloc___nolibxml_prepare_export(topology, buffer, (int)bufferlen);
703 if (res > bufferlen) {
704 char *tmp = realloc(buffer, res);
705 if (!tmp) {
706 free(buffer);
707 return -1;
709 buffer = tmp;
710 hwloc___nolibxml_prepare_export(topology, buffer, (int)res);
713 *bufferp = buffer;
714 *buflenp = (int)res;
715 return 0;
718 static int
719 hwloc_nolibxml_export_file(hwloc_topology_t topology, const char *filename)
721 FILE *file;
722 char *buffer;
723 int bufferlen;
724 int ret;
726 ret = hwloc_nolibxml_export_buffer(topology, &buffer, &bufferlen);
727 if (ret < 0)
728 return -1;
730 if (!strcmp(filename, "-")) {
731 file = stdout;
732 } else {
733 file = fopen(filename, "w");
734 if (!file) {
735 free(buffer);
736 return -1;
740 ret = (int)fwrite(buffer, 1, bufferlen-1 /* don't write the ending \0 */, file);
741 if (ret == bufferlen-1) {
742 ret = 0;
743 } else {
744 errno = ferror(file);
745 ret = -1;
748 free(buffer);
750 if (file != stdout)
751 fclose(file);
752 return ret;
755 static size_t
756 hwloc___nolibxml_prepare_export_diff(hwloc_topology_diff_t diff, const char *refname, char *xmlbuffer, int buflen)
758 struct hwloc__xml_export_state_s state, childstate;
759 hwloc__nolibxml_export_state_data_t ndata = (void *) &state.data;
760 int res;
762 HWLOC_BUILD_ASSERT(sizeof(*ndata) <= sizeof(state.data));
764 state.new_child = hwloc__nolibxml_export_new_child;
765 state.new_prop = hwloc__nolibxml_export_new_prop;
766 state.add_content = hwloc__nolibxml_export_add_content;
767 state.end_object = hwloc__nolibxml_export_end_object;
769 ndata->indent = 0;
770 ndata->written = 0;
771 ndata->buffer = xmlbuffer;
772 ndata->remaining = buflen;
774 ndata->nr_children = 1; /* don't close a non-existing previous tag when opening the topology tag */
775 ndata->has_content = 0;
777 res = hwloc_snprintf(ndata->buffer, ndata->remaining,
778 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
779 "<!DOCTYPE topologydiff SYSTEM \"hwloc.dtd\">\n");
780 hwloc__nolibxml_export_update_buffer(ndata, res);
781 hwloc__nolibxml_export_new_child(&state, &childstate, "topologydiff");
782 if (refname)
783 hwloc__nolibxml_export_new_prop(&childstate, "refname", refname);
784 hwloc__xml_export_diff (&childstate, diff);
785 hwloc__nolibxml_export_end_object(&childstate, "topologydiff");
787 return ndata->written+1;
790 static int
791 hwloc_nolibxml_export_diff_buffer(hwloc_topology_diff_t diff, const char *refname, char **bufferp, int *buflenp)
793 char *buffer;
794 size_t bufferlen, res;
796 bufferlen = 16384; /* random guess for large enough default */
797 buffer = malloc(bufferlen);
798 if (!buffer)
799 return -1;
800 res = hwloc___nolibxml_prepare_export_diff(diff, refname, buffer, (int)bufferlen);
802 if (res > bufferlen) {
803 char *tmp = realloc(buffer, res);
804 if (!tmp) {
805 free(buffer);
806 return -1;
808 buffer = tmp;
809 hwloc___nolibxml_prepare_export_diff(diff, refname, buffer, (int)res);
812 *bufferp = buffer;
813 *buflenp = (int)res;
814 return 0;
817 static int
818 hwloc_nolibxml_export_diff_file(hwloc_topology_diff_t diff, const char *refname, const char *filename)
820 FILE *file;
821 char *buffer;
822 int bufferlen;
823 int ret;
825 ret = hwloc_nolibxml_export_diff_buffer(diff, refname, &buffer, &bufferlen);
826 if (ret < 0)
827 return -1;
829 if (!strcmp(filename, "-")) {
830 file = stdout;
831 } else {
832 file = fopen(filename, "w");
833 if (!file) {
834 free(buffer);
835 return -1;
839 ret = (int)fwrite(buffer, 1, bufferlen-1 /* don't write the ending \0 */, file);
840 if (ret == bufferlen-1) {
841 ret = 0;
842 } else {
843 errno = ferror(file);
844 ret = -1;
847 free(buffer);
849 if (file != stdout)
850 fclose(file);
851 return ret;
854 static void
855 hwloc_nolibxml_free_buffer(void *xmlbuffer)
857 free(xmlbuffer);
860 /*************
861 * Callbacks *
862 *************/
864 static struct hwloc_xml_callbacks hwloc_xml_nolibxml_callbacks = {
865 hwloc_nolibxml_backend_init,
866 hwloc_nolibxml_export_file,
867 hwloc_nolibxml_export_buffer,
868 hwloc_nolibxml_free_buffer,
869 hwloc_nolibxml_import_diff,
870 hwloc_nolibxml_export_diff_file,
871 hwloc_nolibxml_export_diff_buffer
874 static struct hwloc_xml_component hwloc_nolibxml_xml_component = {
875 &hwloc_xml_nolibxml_callbacks,
876 NULL
879 const struct hwloc_component hwloc_xml_nolibxml_component = {
880 HWLOC_COMPONENT_ABI,
881 NULL, NULL,
882 HWLOC_COMPONENT_TYPE_XML,
884 &hwloc_nolibxml_xml_component