root/opal/mca/hwloc/hwloc201/hwloc/hwloc/topology-xml-nolibxml.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hwloc__nolibxml_import_ignore_spaces
  2. hwloc__nolibxml_import_next_attr
  3. hwloc__nolibxml_import_find_child
  4. hwloc__nolibxml_import_close_tag
  5. hwloc__nolibxml_import_close_child
  6. hwloc__nolibxml_import_get_content
  7. hwloc__nolibxml_import_close_content
  8. hwloc_nolibxml_look_init
  9. hwloc_nolibxml_free_buffers
  10. hwloc_nolibxml_look_done
  11. hwloc_nolibxml_backend_exit
  12. hwloc_nolibxml_read_file
  13. hwloc_nolibxml_backend_init
  14. hwloc_nolibxml_import_diff
  15. hwloc__nolibxml_export_update_buffer
  16. hwloc__nolibxml_export_escape_string
  17. hwloc__nolibxml_export_new_child
  18. hwloc__nolibxml_export_new_prop
  19. hwloc__nolibxml_export_end_object
  20. hwloc__nolibxml_export_add_content
  21. hwloc___nolibxml_prepare_export
  22. hwloc_nolibxml_export_buffer
  23. hwloc_nolibxml_export_file
  24. hwloc___nolibxml_prepare_export_diff
  25. hwloc_nolibxml_export_diff_buffer
  26. hwloc_nolibxml_export_diff_file
  27. hwloc_nolibxml_free_buffer

   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  */
   8 
   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>
  16 
  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
  24 
  25 /*******************
  26  * Import routines *
  27  *******************/
  28 
  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 */
  33 };
  34 
  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;
  41 
  42 static char *
  43 hwloc__nolibxml_import_ignore_spaces(char *buffer)
  44 {
  45   return buffer + strspn(buffer, " \t\n");
  46 }
  47 
  48 static int
  49 hwloc__nolibxml_import_next_attr(hwloc__xml_import_state_t state, char **namep, char **valuep)
  50 {
  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;
  55 
  56   if (!nstate->attrbuffer)
  57     return -1;
  58 
  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;
  66 
  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;
  95       }
  96     } else {
  97       value[len] = value[len+escaped];
  98     }
  99     len++;
 100     if (value[len+escaped] == '\0')
 101       return -1;
 102   }
 103   value[len] = '\0';
 104 
 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;
 109 }
 110 
 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)
 115 {
 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   char *tag;
 121   size_t namelen;
 122 
 123   childstate->parent = state;
 124   childstate->global = state->global;
 125 
 126   /* auto-closed tags have no children */
 127   if (nstate->closed)
 128     return 0;
 129 
 130   /* find the beginning of the tag */
 131   buffer = hwloc__nolibxml_import_ignore_spaces(buffer);
 132   if (buffer[0] != '<')
 133     return -1;
 134   buffer++;
 135 
 136   /* if closing tag, return nothing and do not advance */
 137   if (buffer[0] == '/')
 138     return 0;
 139 
 140   /* normal tag */
 141   tag = nchildstate->tagname = buffer;
 142 
 143   /* find the end, mark it and return it */
 144   end = strchr(buffer, '>');
 145   if (!end)
 146     return -1;
 147   end[0] = '\0';
 148   nchildstate->tagbuffer = end+1;
 149 
 150   /* handle auto-closing tags */
 151   if (end[-1] == '/') {
 152     nchildstate->closed = 1;
 153     end[-1] = '\0';
 154   } else
 155     nchildstate->closed = 0;
 156 
 157   /* find attributes */
 158   namelen = strspn(buffer, "abcdefghijklmnopqrstuvwxyz1234567890_");
 159 
 160   if (buffer[namelen] == '\0') {
 161     /* no attributes */
 162     nchildstate->attrbuffer = NULL;
 163     *tagp = tag;
 164     return 1;
 165   }
 166 
 167   if (buffer[namelen] != ' ')
 168     return -1;
 169 
 170   /* found a space, likely starting attributes */
 171   buffer[namelen] = '\0';
 172   nchildstate->attrbuffer = buffer+namelen+1;
 173   *tagp = tag;
 174   return 1;
 175 }
 176 
 177 static int
 178 hwloc__nolibxml_import_close_tag(hwloc__xml_import_state_t state)
 179 {
 180   hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
 181   char *buffer = nstate->tagbuffer;
 182   char *end;
 183 
 184   /* auto-closed tags need nothing */
 185   if (nstate->closed)
 186     return 0;
 187 
 188   /* find the beginning of the tag */
 189   buffer = hwloc__nolibxml_import_ignore_spaces(buffer);
 190   if (buffer[0] != '<')
 191     return -1;
 192   buffer++;
 193 
 194   /* find the end, mark it and return it to the parent */
 195   end = strchr(buffer, '>');
 196   if (!end)
 197     return -1;
 198   end[0] = '\0';
 199   nstate->tagbuffer = end+1;
 200 
 201   /* if closing tag, return nothing */
 202   if (buffer[0] != '/' || strcmp(buffer+1, nstate->tagname) )
 203     return -1;
 204   return 0;
 205 }
 206 
 207 static void
 208 hwloc__nolibxml_import_close_child(hwloc__xml_import_state_t state)
 209 {
 210   hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
 211   hwloc__nolibxml_import_state_data_t nparent = (void*) state->parent->data;
 212   nparent->tagbuffer = nstate->tagbuffer;
 213 }
 214 
 215 static int
 216 hwloc__nolibxml_import_get_content(hwloc__xml_import_state_t state,
 217                                    char **beginp, size_t expected_length)
 218 {
 219   hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
 220   char *buffer = nstate->tagbuffer;
 221   size_t length;
 222   char *end;
 223 
 224   /* auto-closed tags have no content */
 225   if (nstate->closed) {
 226     if (expected_length)
 227       return -1;
 228     *beginp = (char *) "";
 229     return 0;
 230   }
 231 
 232   /* find the next tag, where the content ends */
 233   end = strchr(buffer, '<');
 234   if (!end)
 235     return -1;
 236 
 237   length = (size_t) (end-buffer);
 238   if (length != expected_length)
 239     return -1;
 240   nstate->tagbuffer = end;
 241   *end = '\0'; /* mark as 0-terminated for now */
 242   *beginp = buffer;
 243   return 1;
 244 }
 245 
 246 static void
 247 hwloc__nolibxml_import_close_content(hwloc__xml_import_state_t state)
 248 {
 249   /* put back the '<' that we overwrote to 0-terminate the content */
 250   hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
 251   if (!nstate->closed)
 252     *nstate->tagbuffer = '<';
 253 }
 254 
 255 static int
 256 hwloc_nolibxml_look_init(struct hwloc_xml_backend_data_s *bdata,
 257                          struct hwloc__xml_import_state_s *state)
 258 {
 259   hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
 260   struct hwloc__nolibxml_backend_data_s *nbdata = bdata->data;
 261   unsigned major, minor;
 262   char *end;
 263   char *buffer;
 264 
 265   HWLOC_BUILD_ASSERT(sizeof(*nstate) <= sizeof(state->data));
 266 
 267   /* use a copy in the temporary buffer, we may modify during parsing */
 268   buffer = nbdata->copy;
 269   memcpy(buffer, nbdata->buffer, nbdata->buflen);
 270 
 271   /* skip headers */
 272   while (!strncmp(buffer, "<?xml ", 6) || !strncmp(buffer, "<!DOCTYPE ", 10)) {
 273     buffer = strchr(buffer, '\n');
 274     if (!buffer)
 275       goto failed;
 276     buffer++;
 277   }
 278 
 279   /* find topology tag */
 280   if (sscanf(buffer, "<topology version=\"%u.%u\">", &major, &minor) == 2) {
 281     bdata->version_major = major;
 282     bdata->version_minor = minor;
 283     end = strchr(buffer, '>') + 1;
 284   } else if (!strncmp(buffer, "<topology>", 10)) {
 285     bdata->version_major = 1;
 286     bdata->version_minor = 0;
 287     end = buffer + 10;
 288   } else if (!strncmp(buffer, "<root>", 6)) {
 289     bdata->version_major = 0;
 290     bdata->version_minor = 9;
 291     end = buffer + 6;
 292   } else
 293     goto failed;
 294 
 295   state->global->next_attr = hwloc__nolibxml_import_next_attr;
 296   state->global->find_child = hwloc__nolibxml_import_find_child;
 297   state->global->close_tag = hwloc__nolibxml_import_close_tag;
 298   state->global->close_child = hwloc__nolibxml_import_close_child;
 299   state->global->get_content = hwloc__nolibxml_import_get_content;
 300   state->global->close_content = hwloc__nolibxml_import_close_content;
 301   state->parent = NULL;
 302   nstate->closed = 0;
 303   nstate->tagbuffer = end;
 304   nstate->tagname = (char *) "topology";
 305   nstate->attrbuffer = NULL;
 306   return 0; /* success */
 307 
 308  failed:
 309   return -1; /* failed */
 310 }
 311 
 312 /* can be called at the end of the import (to cleanup things early),
 313  * or by backend_exit() if load failed for other reasons.
 314  */
 315 static void
 316 hwloc_nolibxml_free_buffers(struct hwloc_xml_backend_data_s *bdata)
 317 {
 318   struct hwloc__nolibxml_backend_data_s *nbdata = bdata->data;
 319   if (nbdata->buffer) {
 320     free(nbdata->buffer);
 321     nbdata->buffer = NULL;
 322   }
 323   if (nbdata->copy) {
 324     free(nbdata->copy);
 325     nbdata->copy = NULL;
 326   }
 327 }
 328 
 329 static void
 330 hwloc_nolibxml_look_done(struct hwloc_xml_backend_data_s *bdata, int result)
 331 {
 332   hwloc_nolibxml_free_buffers(bdata);
 333 
 334   if (result < 0 && hwloc__xml_verbose())
 335     fprintf(stderr, "Failed to parse XML input with the minimalistic parser. If it was not\n"
 336             "generated by hwloc, try enabling full XML support with libxml2.\n");
 337 }
 338 
 339 /********************
 340  * Backend routines *
 341  ********************/
 342 
 343 static void
 344 hwloc_nolibxml_backend_exit(struct hwloc_xml_backend_data_s *bdata)
 345 {
 346   struct hwloc__nolibxml_backend_data_s *nbdata = bdata->data;
 347   hwloc_nolibxml_free_buffers(bdata);
 348   free(nbdata);
 349 }
 350 
 351 static int
 352 hwloc_nolibxml_read_file(const char *xmlpath, char **bufferp, size_t *buflenp)
 353 {
 354   FILE * file;
 355   size_t buflen, offset, readlen;
 356   struct stat statbuf;
 357   char *buffer, *tmp;
 358   size_t ret;
 359 
 360   if (!strcmp(xmlpath, "-"))
 361     xmlpath = "/dev/stdin";
 362 
 363   file = fopen(xmlpath, "r");
 364   if (!file)
 365     goto out;
 366 
 367   /* find the required buffer size for regular files, or use 4k when unknown, we'll realloc later if needed */
 368   buflen = 4096;
 369   if (!stat(xmlpath, &statbuf))
 370     if (S_ISREG(statbuf.st_mode))
 371       buflen = statbuf.st_size+1; /* one additional byte so that the first fread() gets EOF too */
 372 
 373   buffer = malloc(buflen+1); /* one more byte for the ending \0 */
 374   if (!buffer)
 375     goto out_with_file;
 376 
 377   offset = 0; readlen = buflen;
 378   while (1) {
 379     ret = fread(buffer+offset, 1, readlen, file);
 380 
 381     offset += ret;
 382     buffer[offset] = 0;
 383 
 384     if (ret != readlen)
 385       break;
 386 
 387     buflen *= 2;
 388     tmp = realloc(buffer, buflen+1);
 389     if (!tmp)
 390       goto out_with_buffer;
 391     buffer = tmp;
 392     readlen = buflen/2;
 393   }
 394 
 395   fclose(file);
 396   *bufferp = buffer;
 397   *buflenp = offset+1;
 398   return 0;
 399 
 400  out_with_buffer:
 401   free(buffer);
 402  out_with_file:
 403   fclose(file);
 404  out:
 405   return -1;
 406 }
 407 
 408 static int
 409 hwloc_nolibxml_backend_init(struct hwloc_xml_backend_data_s *bdata,
 410                             const char *xmlpath, const char *xmlbuffer, int xmlbuflen)
 411 {
 412   struct hwloc__nolibxml_backend_data_s *nbdata = malloc(sizeof(*nbdata));
 413 
 414   if (!nbdata)
 415     goto out;
 416   bdata->data = nbdata;
 417 
 418   if (xmlbuffer) {
 419     nbdata->buffer = malloc(xmlbuflen);
 420     if (!nbdata->buffer)
 421       goto out_with_nbdata;
 422     nbdata->buflen = xmlbuflen;
 423     memcpy(nbdata->buffer, xmlbuffer, xmlbuflen);
 424 
 425   } else {
 426     int err = hwloc_nolibxml_read_file(xmlpath, &nbdata->buffer, &nbdata->buflen);
 427     if (err < 0)
 428       goto out_with_nbdata;
 429   }
 430 
 431   /* allocate a temporary copy buffer that we may modify during parsing */
 432   nbdata->copy = malloc(nbdata->buflen);
 433   if (!nbdata->copy)
 434     goto out_with_buffer;
 435 
 436   bdata->look_init = hwloc_nolibxml_look_init;
 437   bdata->look_done = hwloc_nolibxml_look_done;
 438   bdata->backend_exit = hwloc_nolibxml_backend_exit;
 439   return 0;
 440 
 441 out_with_buffer:
 442   free(nbdata->buffer);
 443 out_with_nbdata:
 444   free(nbdata);
 445 out:
 446   return -1;
 447 }
 448 
 449 static int
 450 hwloc_nolibxml_import_diff(struct hwloc__xml_import_state_s *state,
 451                            const char *xmlpath, const char *xmlbuffer, int xmlbuflen,
 452                            hwloc_topology_diff_t *firstdiffp, char **refnamep)
 453 {
 454   hwloc__nolibxml_import_state_data_t nstate = (void*) state->data;
 455   struct hwloc__xml_import_state_s childstate;
 456   char *refname = NULL;
 457   char *buffer, *tmp, *tag;
 458   size_t buflen;
 459   int ret;
 460 
 461   HWLOC_BUILD_ASSERT(sizeof(*nstate) <= sizeof(state->data));
 462 
 463   if (xmlbuffer) {
 464     buffer = malloc(xmlbuflen);
 465     if (!buffer)
 466       goto out;
 467     memcpy(buffer, xmlbuffer, xmlbuflen);
 468     buflen = xmlbuflen;
 469 
 470   } else {
 471     ret = hwloc_nolibxml_read_file(xmlpath, &buffer, &buflen);
 472     if (ret < 0)
 473       goto out;
 474   }
 475 
 476   /* skip headers */
 477   tmp = buffer;
 478   while (!strncmp(tmp, "<?xml ", 6) || !strncmp(tmp, "<!DOCTYPE ", 10)) {
 479     tmp = strchr(tmp, '\n');
 480     if (!tmp)
 481       goto out_with_buffer;
 482     tmp++;
 483   }
 484 
 485   state->global->next_attr = hwloc__nolibxml_import_next_attr;
 486   state->global->find_child = hwloc__nolibxml_import_find_child;
 487   state->global->close_tag = hwloc__nolibxml_import_close_tag;
 488   state->global->close_child = hwloc__nolibxml_import_close_child;
 489   state->global->get_content = hwloc__nolibxml_import_get_content;
 490   state->global->close_content = hwloc__nolibxml_import_close_content;
 491   state->parent = NULL;
 492   nstate->closed = 0;
 493   nstate->tagbuffer = tmp;
 494   nstate->tagname = NULL;
 495   nstate->attrbuffer = NULL;
 496 
 497   /* find root */
 498   ret = hwloc__nolibxml_import_find_child(state, &childstate, &tag);
 499   if (ret < 0)
 500     goto out_with_buffer;
 501   if (strcmp(tag, "topologydiff"))
 502     goto out_with_buffer;
 503 
 504   while (1) {
 505     char *attrname, *attrvalue;
 506     if (hwloc__nolibxml_import_next_attr(&childstate, &attrname, &attrvalue) < 0)
 507       break;
 508     if (!strcmp(attrname, "refname")) {
 509       free(refname);
 510       refname = strdup(attrvalue);
 511     } else
 512       goto out_with_buffer;
 513   }
 514 
 515   ret = hwloc__xml_import_diff(&childstate, firstdiffp);
 516   if (refnamep && !ret)
 517     *refnamep = refname;
 518   else
 519     free(refname);
 520 
 521   free(buffer);
 522   return ret;
 523 
 524 out_with_buffer:
 525   free(buffer);
 526 out:
 527   return -1;
 528 }
 529 
 530 /*******************
 531  * Export routines *
 532  *******************/
 533 
 534 typedef struct hwloc__nolibxml_export_state_data_s {
 535   char *buffer; /* (moving) buffer where to write */
 536   size_t written; /* how many bytes were written (or would have be written if not truncated) */
 537   size_t remaining; /* how many bytes are still available in the buffer */
 538   unsigned indent; /* indentation level for the next line */
 539   unsigned nr_children;
 540   unsigned has_content;
 541 } __hwloc_attribute_may_alias * hwloc__nolibxml_export_state_data_t;
 542 
 543 static void
 544 hwloc__nolibxml_export_update_buffer(hwloc__nolibxml_export_state_data_t ndata, int res)
 545 {
 546   if (res >= 0) {
 547     ndata->written += res;
 548     if (res >= (int) ndata->remaining)
 549       res = ndata->remaining>0 ? (int)ndata->remaining-1 : 0;
 550     ndata->buffer += res;
 551     ndata->remaining -= res;
 552   }
 553 }
 554 
 555 static char *
 556 hwloc__nolibxml_export_escape_string(const char *src)
 557 {
 558   size_t fulllen, sublen;
 559   char *escaped, *dst;
 560 
 561   fulllen = strlen(src);
 562 
 563   sublen = strcspn(src, "\n\r\t\"<>&");
 564   if (sublen == fulllen)
 565     return NULL; /* nothing to escape */
 566 
 567   escaped = malloc(fulllen*6+1); /* escaped chars are replaced by at most 6 char */
 568   dst = escaped;
 569 
 570   memcpy(dst, src, sublen);
 571   src += sublen;
 572   dst += sublen;
 573 
 574   while (*src) {
 575     int replen;
 576     switch (*src) {
 577     case '\n': strcpy(dst, "&#10;");  replen=5; break;
 578     case '\r': strcpy(dst, "&#13;");  replen=5; break;
 579     case '\t': strcpy(dst, "&#9;");   replen=4; break;
 580     case '\"': strcpy(dst, "&quot;"); replen=6; break;
 581     case '<':  strcpy(dst, "&lt;");   replen=4; break;
 582     case '>':  strcpy(dst, "&gt;");   replen=4; break;
 583     case '&':  strcpy(dst, "&amp;");  replen=5; break;
 584     default: replen=0; break;
 585     }
 586     dst+=replen; src++;
 587 
 588     sublen = strcspn(src, "\n\r\t\"<>&");
 589     memcpy(dst, src, sublen);
 590     src += sublen;
 591     dst += sublen;
 592   }
 593 
 594   *dst = 0;
 595   return escaped;
 596 }
 597 
 598 static void
 599 hwloc__nolibxml_export_new_child(hwloc__xml_export_state_t parentstate,
 600                                  hwloc__xml_export_state_t state,
 601                                  const char *name)
 602 {
 603   hwloc__nolibxml_export_state_data_t npdata = (void *) parentstate->data;
 604   hwloc__nolibxml_export_state_data_t ndata = (void *) state->data;
 605   int res;
 606 
 607   assert(!npdata->has_content);
 608   if (!npdata->nr_children) {
 609     res = hwloc_snprintf(npdata->buffer, npdata->remaining, ">\n");
 610     hwloc__nolibxml_export_update_buffer(npdata, res);
 611   }
 612   npdata->nr_children++;
 613 
 614   state->parent = parentstate;
 615   state->new_child = parentstate->new_child;
 616   state->new_prop = parentstate->new_prop;
 617   state->add_content = parentstate->add_content;
 618   state->end_object = parentstate->end_object;
 619   state->global = parentstate->global;
 620 
 621   ndata->buffer = npdata->buffer;
 622   ndata->written = npdata->written;
 623   ndata->remaining = npdata->remaining;
 624   ndata->indent = npdata->indent + 2;
 625 
 626   ndata->nr_children = 0;
 627   ndata->has_content = 0;
 628 
 629   res = hwloc_snprintf(ndata->buffer, ndata->remaining, "%*s<%s", (int) npdata->indent, "", name);
 630   hwloc__nolibxml_export_update_buffer(ndata, res);
 631 }
 632 
 633 static void
 634 hwloc__nolibxml_export_new_prop(hwloc__xml_export_state_t state, const char *name, const char *value)
 635 {
 636   hwloc__nolibxml_export_state_data_t ndata = (void *) state->data;
 637   char *escaped = hwloc__nolibxml_export_escape_string(value);
 638   int res = hwloc_snprintf(ndata->buffer, ndata->remaining, " %s=\"%s\"", name, escaped ? (const char *) escaped : value);
 639   hwloc__nolibxml_export_update_buffer(ndata, res);
 640   free(escaped);
 641 }
 642 
 643 static void
 644 hwloc__nolibxml_export_end_object(hwloc__xml_export_state_t state, const char *name)
 645 {
 646   hwloc__nolibxml_export_state_data_t ndata = (void *) state->data;
 647   hwloc__nolibxml_export_state_data_t npdata = (void *) state->parent->data;
 648   int res;
 649 
 650   assert (!(ndata->has_content && ndata->nr_children));
 651   if (ndata->has_content) {
 652     res = hwloc_snprintf(ndata->buffer, ndata->remaining, "</%s>\n", name);
 653   } else if (ndata->nr_children) {
 654     res = hwloc_snprintf(ndata->buffer, ndata->remaining, "%*s</%s>\n", (int) npdata->indent, "", name);
 655   } else {
 656     res = hwloc_snprintf(ndata->buffer, ndata->remaining, "/>\n");
 657   }
 658   hwloc__nolibxml_export_update_buffer(ndata, res);
 659 
 660   npdata->buffer = ndata->buffer;
 661   npdata->written = ndata->written;
 662   npdata->remaining = ndata->remaining;
 663 }
 664 
 665 static void
 666 hwloc__nolibxml_export_add_content(hwloc__xml_export_state_t state, const char *buffer, size_t length)
 667 {
 668   hwloc__nolibxml_export_state_data_t ndata = (void *) state->data;
 669   int res;
 670 
 671   assert(!ndata->nr_children);
 672   if (!ndata->has_content) {
 673     res = hwloc_snprintf(ndata->buffer, ndata->remaining, ">");
 674     hwloc__nolibxml_export_update_buffer(ndata, res);
 675   }
 676   ndata->has_content = 1;
 677 
 678   res = hwloc_snprintf(ndata->buffer, ndata->remaining, buffer, length);
 679   hwloc__nolibxml_export_update_buffer(ndata, res);
 680 }
 681 
 682 static size_t
 683 hwloc___nolibxml_prepare_export(hwloc_topology_t topology, struct hwloc__xml_export_data_s *edata,
 684                                 char *xmlbuffer, int buflen, unsigned long flags)
 685 {
 686   struct hwloc__xml_export_state_s state, childstate;
 687   hwloc__nolibxml_export_state_data_t ndata = (void *) &state.data;
 688   int v1export = flags & HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1;
 689   int res;
 690 
 691   HWLOC_BUILD_ASSERT(sizeof(*ndata) <= sizeof(state.data));
 692 
 693   state.new_child = hwloc__nolibxml_export_new_child;
 694   state.new_prop = hwloc__nolibxml_export_new_prop;
 695   state.add_content = hwloc__nolibxml_export_add_content;
 696   state.end_object = hwloc__nolibxml_export_end_object;
 697   state.global = edata;
 698 
 699   ndata->indent = 0;
 700   ndata->written = 0;
 701   ndata->buffer = xmlbuffer;
 702   ndata->remaining = buflen;
 703 
 704   ndata->nr_children = 1; /* don't close a non-existing previous tag when opening the topology tag */
 705   ndata->has_content = 0;
 706 
 707   res = hwloc_snprintf(ndata->buffer, ndata->remaining,
 708                  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
 709                  "<!DOCTYPE topology SYSTEM \"%s\">\n", v1export ? "hwloc.dtd" : "hwloc2.dtd");
 710   hwloc__nolibxml_export_update_buffer(ndata, res);
 711   hwloc__nolibxml_export_new_child(&state, &childstate, "topology");
 712   if (!(flags & HWLOC_TOPOLOGY_EXPORT_XML_FLAG_V1))
 713     hwloc__nolibxml_export_new_prop(&childstate, "version", "2.0");
 714   hwloc__xml_export_topology (&childstate, topology, flags);
 715   hwloc__nolibxml_export_end_object(&childstate, "topology");
 716 
 717   return ndata->written+1;
 718 }
 719 
 720 static int
 721 hwloc_nolibxml_export_buffer(hwloc_topology_t topology, struct hwloc__xml_export_data_s *edata,
 722                              char **bufferp, int *buflenp, unsigned long flags)
 723 {
 724   char *buffer;
 725   size_t bufferlen, res;
 726 
 727   bufferlen = 16384; /* random guess for large enough default */
 728   buffer = malloc(bufferlen);
 729   if (!buffer)
 730     return -1;
 731   res = hwloc___nolibxml_prepare_export(topology, edata, buffer, (int)bufferlen, flags);
 732 
 733   if (res > bufferlen) {
 734     char *tmp = realloc(buffer, res);
 735     if (!tmp) {
 736       free(buffer);
 737       return -1;
 738     }
 739     buffer = tmp;
 740     hwloc___nolibxml_prepare_export(topology, edata, buffer, (int)res, flags);
 741   }
 742 
 743   *bufferp = buffer;
 744   *buflenp = (int)res;
 745   return 0;
 746 }
 747 
 748 static int
 749 hwloc_nolibxml_export_file(hwloc_topology_t topology, struct hwloc__xml_export_data_s *edata,
 750                            const char *filename, unsigned long flags)
 751 {
 752   FILE *file;
 753   char *buffer;
 754   int bufferlen;
 755   int ret;
 756 
 757   ret = hwloc_nolibxml_export_buffer(topology, edata, &buffer, &bufferlen, flags);
 758   if (ret < 0)
 759     return -1;
 760 
 761   if (!strcmp(filename, "-")) {
 762     file = stdout;
 763   } else {
 764     file = fopen(filename, "w");
 765     if (!file) {
 766       free(buffer);
 767       return -1;
 768     }
 769   }
 770 
 771   ret = (int)fwrite(buffer, 1, bufferlen-1 /* don't write the ending \0 */, file);
 772   if (ret == bufferlen-1) {
 773     ret = 0;
 774   } else {
 775     errno = ferror(file);
 776     ret = -1;
 777   }
 778 
 779   free(buffer);
 780 
 781   if (file != stdout)
 782     fclose(file);
 783   return ret;
 784 }
 785 
 786 static size_t
 787 hwloc___nolibxml_prepare_export_diff(hwloc_topology_diff_t diff, const char *refname, char *xmlbuffer, int buflen)
 788 {
 789   struct hwloc__xml_export_state_s state, childstate;
 790   hwloc__nolibxml_export_state_data_t ndata = (void *) &state.data;
 791   int res;
 792 
 793   HWLOC_BUILD_ASSERT(sizeof(*ndata) <= sizeof(state.data));
 794 
 795   state.new_child = hwloc__nolibxml_export_new_child;
 796   state.new_prop = hwloc__nolibxml_export_new_prop;
 797   state.add_content = hwloc__nolibxml_export_add_content;
 798   state.end_object = hwloc__nolibxml_export_end_object;
 799 
 800   ndata->indent = 0;
 801   ndata->written = 0;
 802   ndata->buffer = xmlbuffer;
 803   ndata->remaining = buflen;
 804 
 805   ndata->nr_children = 1; /* don't close a non-existing previous tag when opening the topology tag */
 806   ndata->has_content = 0;
 807 
 808   res = hwloc_snprintf(ndata->buffer, ndata->remaining,
 809                  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
 810                  "<!DOCTYPE topologydiff SYSTEM \"hwloc2-diff.dtd\">\n");
 811   hwloc__nolibxml_export_update_buffer(ndata, res);
 812   hwloc__nolibxml_export_new_child(&state, &childstate, "topologydiff");
 813   if (refname)
 814     hwloc__nolibxml_export_new_prop(&childstate, "refname", refname);
 815   hwloc__xml_export_diff (&childstate, diff);
 816   hwloc__nolibxml_export_end_object(&childstate, "topologydiff");
 817 
 818   return ndata->written+1;
 819 }
 820 
 821 static int
 822 hwloc_nolibxml_export_diff_buffer(hwloc_topology_diff_t diff, const char *refname, char **bufferp, int *buflenp)
 823 {
 824   char *buffer;
 825   size_t bufferlen, res;
 826 
 827   bufferlen = 16384; /* random guess for large enough default */
 828   buffer = malloc(bufferlen);
 829   if (!buffer)
 830     return -1;
 831   res = hwloc___nolibxml_prepare_export_diff(diff, refname, buffer, (int)bufferlen);
 832 
 833   if (res > bufferlen) {
 834     char *tmp = realloc(buffer, res);
 835     if (!tmp) {
 836       free(buffer);
 837       return -1;
 838     }
 839     buffer = tmp;
 840     hwloc___nolibxml_prepare_export_diff(diff, refname, buffer, (int)res);
 841   }
 842 
 843   *bufferp = buffer;
 844   *buflenp = (int)res;
 845   return 0;
 846 }
 847 
 848 static int
 849 hwloc_nolibxml_export_diff_file(hwloc_topology_diff_t diff, const char *refname, const char *filename)
 850 {
 851   FILE *file;
 852   char *buffer;
 853   int bufferlen;
 854   int ret;
 855 
 856   ret = hwloc_nolibxml_export_diff_buffer(diff, refname, &buffer, &bufferlen);
 857   if (ret < 0)
 858     return -1;
 859 
 860   if (!strcmp(filename, "-")) {
 861     file = stdout;
 862   } else {
 863     file = fopen(filename, "w");
 864     if (!file) {
 865       free(buffer);
 866       return -1;
 867     }
 868   }
 869 
 870   ret = (int)fwrite(buffer, 1, bufferlen-1 /* don't write the ending \0 */, file);
 871   if (ret == bufferlen-1) {
 872     ret = 0;
 873   } else {
 874     errno = ferror(file);
 875     ret = -1;
 876   }
 877 
 878   free(buffer);
 879 
 880   if (file != stdout)
 881     fclose(file);
 882   return ret;
 883 }
 884 
 885 static void
 886 hwloc_nolibxml_free_buffer(void *xmlbuffer)
 887 {
 888   free(xmlbuffer);
 889 }
 890 
 891 /*************
 892  * Callbacks *
 893  *************/
 894 
 895 static struct hwloc_xml_callbacks hwloc_xml_nolibxml_callbacks = {
 896   hwloc_nolibxml_backend_init,
 897   hwloc_nolibxml_export_file,
 898   hwloc_nolibxml_export_buffer,
 899   hwloc_nolibxml_free_buffer,
 900   hwloc_nolibxml_import_diff,
 901   hwloc_nolibxml_export_diff_file,
 902   hwloc_nolibxml_export_diff_buffer
 903 };
 904 
 905 static struct hwloc_xml_component hwloc_nolibxml_xml_component = {
 906   &hwloc_xml_nolibxml_callbacks,
 907   NULL
 908 };
 909 
 910 const struct hwloc_component hwloc_xml_nolibxml_component = {
 911   HWLOC_COMPONENT_ABI,
 912   NULL, NULL,
 913   HWLOC_COMPONENT_TYPE_XML,
 914   0,
 915   &hwloc_nolibxml_xml_component
 916 };

/* [<][>][^][v][top][bottom][index][help] */