/* * This file is part of the bayou project. * * Copyright (C) 2008 Advanced Micro Devices, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc. */ #define _GNU_SOURCE #include <stdlib.h> #include <string.h> #include <expat.h> #include <ctype.h> #include "pbuilder.h" #define STATE_NONE 0x00 #define STATE_BAYOUCONFIG 0x01 #define STATE_GLOBAL 0x02 #define STATE_GLOBAL_TIMEOUT 0x03 #define STATE_PAYLOADS 0x04 #define STATE_PAYLOAD 0x05 #define STATE_PAYLOAD_TITLE 0x06 #define STATE_PAYLOAD_FILE 0x07 #define STATE_PAYLOAD_LARNAME 0x08 #define STATE_PAYLOAD_CHAIN 0x09 #define STATE_PAYLOAD_CHAIN_FILE 0x0A #define STATE_PAYLOAD_CHAIN_LARNAME 0x0B static struct userdata { struct config *config; struct pentry *payload; struct pentry *chain; int state; } userdata; static char buffer[8192]; static struct { char *element; int pstate; int state; } states[] = { {"BayouConfig", STATE_NONE, STATE_BAYOUCONFIG}, {"global", STATE_BAYOUCONFIG, STATE_GLOBAL}, {"timeout", STATE_GLOBAL, STATE_GLOBAL_TIMEOUT}, {"payloads", STATE_BAYOUCONFIG, STATE_PAYLOADS}, {"payload", STATE_PAYLOADS, STATE_PAYLOAD}, {"title", STATE_PAYLOAD, STATE_PAYLOAD_TITLE}, {"lar", STATE_PAYLOAD, STATE_PAYLOAD_LARNAME}, {"file", STATE_PAYLOAD, STATE_PAYLOAD_FILE}, {"chain", STATE_PAYLOAD, STATE_PAYLOAD_CHAIN}, {"file", STATE_PAYLOAD_CHAIN, STATE_PAYLOAD_CHAIN_FILE}, {"lar", STATE_PAYLOAD_CHAIN, STATE_PAYLOAD_CHAIN_LARNAME}, {NULL}, }; #ifndef __LINUX__ static char *strndup (const char *s, size_t n) { size_t len = strlen (s); len = (len<n)?len:n; char *cpy = malloc (len + 1); if (cpy == NULL) return NULL; cpy[len] = '\0'; memcpy (cpy, s, len); return cpy; } #endif static struct pentry *newPayload(struct config *config) { struct pentry **tmp, *ret; tmp = realloc(config->entries, (config->n_entries + 1) * sizeof(struct pentry *)); if (tmp == NULL) return NULL; config->entries = tmp; ret = config->entries[config->n_entries] = calloc(sizeof(*ret), 1); if (ret == NULL) return NULL; /* Yes, I want this to be ++config->n_entries (the index is 1 based). */ ret->index = ++config->n_entries; return ret; } static void parseFlags(struct pentry *entry, const char *flags) { char *p = (char *)flags; char *n; while (*p) { n = strchr(p, ','); if (n) *(n++) = 0; if (!strcmp(p, "default")) entry->flags |= BPT_FLAG_DEFAULT; else if (!strcmp(p, "nolist")) entry->flags |= BPT_FLAG_NOSHOW; else warn("W: Unknown payload flag %s\n", p); if (!n) break; for (p = n; *p && isspace(*p); p++) ; } } static struct pentry *addPayload(struct config *config, const char **attr) { struct pentry *ret = newPayload(config); int i = 0; if (ret == NULL) die("E: Could not allocate memory for a new payload\n"); while (attr[i] != NULL) { if (!strcmp(attr[i], "type")) { if (!strcmp(attr[i + 1], "chain")) ret->type = BPT_TYPE_CHAIN; else if (!strcmp(attr[i + 1], "chooser")) ret->type = BPT_TYPE_CHOOSER; else die("E: Invalid payload type %s\n", attr[i + 1]); } else if (!strcmp(attr[i], "flags")) parseFlags(ret, attr[i + 1]); i += 2; } return ret; } static struct pentry *addChain(struct config *config, struct pentry *parent) { struct pentry *ret = newPayload(config); if (ret == NULL) die("E: Could not allocate memory for a new payload\n"); ret->parent = parent->index; ret->type = BPT_TYPE_SUBCHAIN; return ret; } static void start(void *data, const char *el, const char **attr) { int i; struct userdata *d = (struct userdata *)data; for (i = 0; states[i].element != NULL; i++) { if (d->state != states[i].pstate) continue; if (!strcmp(el, states[i].element)) { d->state = states[i].state; break; } } if (states[i].element == NULL) die("E: Unknown element %s\n", el); if (d->state == STATE_PAYLOAD) d->payload = addPayload(d->config, attr); if (d->state == STATE_PAYLOAD_CHAIN) d->chain = addChain(d->config, d->payload); } static void data(void *data, const char *val, int len) { struct userdata *d = (struct userdata *)data; int l; switch (d->state) { case STATE_GLOBAL_TIMEOUT: d->config->timeout = atoi(val); break; case STATE_PAYLOAD_TITLE: l = sizeof(d->payload->title) - 1 > len ? len : sizeof(d->payload->title) - 1; strncpy((char *)d->payload->title, (char *)val, l); d->payload->title[l] = '\0'; break; case STATE_PAYLOAD_FILE: d->payload->file = strndup(val, len); break; case STATE_PAYLOAD_LARNAME: d->payload->larname = strndup(val, len); break; case STATE_PAYLOAD_CHAIN_FILE: d->chain->file = strndup(val, len); break; case STATE_PAYLOAD_CHAIN_LARNAME: d->chain->larname = strndup(val, len); break; default: break; } } static void end(void *data, const char *el) { struct userdata *d = (struct userdata *)data; int i; if (d->state == STATE_PAYLOAD_CHAIN) d->chain = NULL; if (d->state == STATE_PAYLOAD) d->payload = NULL; for (i = 0; states[i].element != NULL; i++) { if (d->state != states[i].state) continue; if (!strcmp(el, states[i].element)) { d->state = states[i].pstate; break; } } if (states[i].element == NULL) die("E: Unable to find the reverse state for %s\n", el); } void parseconfig(FILE *stream, struct config *config) { XML_Parser p = XML_ParserCreate(NULL); int eof = 0; if (p == NULL) die("E: Could not create the parser\n"); XML_SetElementHandler(p, start, end); XML_SetCharacterDataHandler(p, data); userdata.config = config; XML_SetUserData(p, &userdata); while (!eof) { int len = fread(buffer, 1, 8192, stream); eof = feof(stream); if (ferror(stream)) die("E: Error reading the stream\n"); if (!XML_Parse(p, buffer, len, eof)) die("E: Error parsing the XML data\n"); } }