Libpayload: default DESTDIR for 'make install'
[coreboot.git] / payloads / bayou / util / pbuilder / config.c
1 /*
2  * This file is part of the bayou project.
3  *
4  * Copyright (C) 2008 Advanced Micro Devices, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  */
19
20 #define _GNU_SOURCE
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <expat.h>
25 #include <ctype.h>
26 #include "pbuilder.h"
27
28 #define STATE_NONE                   0x00
29 #define STATE_BAYOUCONFIG            0x01
30 #define STATE_GLOBAL                 0x02
31 #define STATE_GLOBAL_TIMEOUT         0x03
32 #define STATE_PAYLOADS               0x04
33 #define STATE_PAYLOAD                0x05
34 #define STATE_PAYLOAD_TITLE          0x06
35 #define STATE_PAYLOAD_FILE           0x07
36 #define STATE_PAYLOAD_LARNAME        0x08
37 #define STATE_PAYLOAD_CHAIN          0x09
38 #define STATE_PAYLOAD_CHAIN_FILE     0x0A
39 #define STATE_PAYLOAD_CHAIN_LARNAME  0x0B
40
41 static struct userdata {
42         struct config *config;
43         struct pentry *payload;
44         struct pentry *chain;
45         int state;
46 } userdata;
47
48 static char buffer[8192];
49
50 static struct {
51         char *element;
52         int pstate;
53         int state;
54 } states[] = {
55         {"BayouConfig", STATE_NONE, STATE_BAYOUCONFIG},
56         {"global", STATE_BAYOUCONFIG, STATE_GLOBAL},
57         {"timeout", STATE_GLOBAL, STATE_GLOBAL_TIMEOUT},
58         {"payloads", STATE_BAYOUCONFIG, STATE_PAYLOADS},
59         {"payload", STATE_PAYLOADS, STATE_PAYLOAD},
60         {"title", STATE_PAYLOAD, STATE_PAYLOAD_TITLE},
61         {"lar", STATE_PAYLOAD, STATE_PAYLOAD_LARNAME},
62         {"file", STATE_PAYLOAD, STATE_PAYLOAD_FILE},
63         {"chain", STATE_PAYLOAD, STATE_PAYLOAD_CHAIN},
64         {"file", STATE_PAYLOAD_CHAIN, STATE_PAYLOAD_CHAIN_FILE},
65         {"lar", STATE_PAYLOAD_CHAIN, STATE_PAYLOAD_CHAIN_LARNAME},
66         {NULL},
67 };
68
69 #ifndef __LINUX__
70 static char *strndup (const char *s, size_t n)
71 {
72         size_t len = strlen (s);
73         len = (len<n)?len:n;
74         char *cpy = malloc (len + 1);
75         if (cpy == NULL)
76                 return NULL;
77         cpy[len] = '\0';
78         memcpy (cpy, s, len);
79         return cpy;
80 }
81 #endif
82
83 static struct pentry *newPayload(struct config *config)
84 {
85         struct pentry **tmp, *ret;
86
87         tmp = realloc(config->entries,
88                       (config->n_entries + 1) * sizeof(struct pentry *));
89
90         if (tmp == NULL)
91                 return NULL;
92
93         config->entries = tmp;
94
95         ret = config->entries[config->n_entries] = calloc(sizeof(*ret), 1);
96
97         if (ret == NULL)
98                 return NULL;
99
100         /* Yes, I want this to be ++config->n_entries (the index is 1 based). */
101         ret->index = ++config->n_entries;
102
103         return ret;
104 }
105
106 static void parseFlags(struct pentry *entry, const char *flags)
107 {
108         char *p = (char *)flags;
109         char *n;
110
111         while (*p) {
112                 n = strchr(p, ',');
113
114                 if (n)
115                         *(n++) = 0;
116
117                 if (!strcmp(p, "default"))
118                         entry->flags |= BPT_FLAG_DEFAULT;
119                 else if (!strcmp(p, "nolist"))
120                         entry->flags |= BPT_FLAG_NOSHOW;
121                 else
122                         warn("W: Unknown payload flag %s\n", p);
123
124                 if (!n)
125                         break;
126
127                 for (p = n; *p && isspace(*p); p++) ;
128         }
129 }
130
131 static struct pentry *addPayload(struct config *config, const char **attr)
132 {
133         struct pentry *ret = newPayload(config);
134         int i = 0;
135
136         if (ret == NULL)
137                 die("E: Could not allocate memory for a new payload\n");
138
139         while (attr[i] != NULL) {
140                 if (!strcmp(attr[i], "type")) {
141                         if (!strcmp(attr[i + 1], "chain"))
142                                 ret->type = BPT_TYPE_CHAIN;
143                         else if (!strcmp(attr[i + 1], "chooser"))
144                                 ret->type = BPT_TYPE_CHOOSER;
145                         else
146                                 die("E: Invalid payload type %s\n",
147                                     attr[i + 1]);
148                 } else if (!strcmp(attr[i], "flags"))
149                         parseFlags(ret, attr[i + 1]);
150
151                 i += 2;
152         }
153
154         return ret;
155 }
156
157 static struct pentry *addChain(struct config *config, struct pentry *parent)
158 {
159         struct pentry *ret = newPayload(config);
160
161         if (ret == NULL)
162                 die("E: Could not allocate memory for a new payload\n");
163
164         ret->parent = parent->index;
165         ret->type = BPT_TYPE_SUBCHAIN;
166
167         return ret;
168 }
169
170 static void start(void *data, const char *el, const char **attr)
171 {
172         int i;
173         struct userdata *d = (struct userdata *)data;
174
175         for (i = 0; states[i].element != NULL; i++) {
176                 if (d->state != states[i].pstate)
177                         continue;
178
179                 if (!strcmp(el, states[i].element)) {
180                         d->state = states[i].state;
181                         break;
182                 }
183         }
184
185         if (states[i].element == NULL)
186                 die("E: Unknown element %s\n", el);
187
188         if (d->state == STATE_PAYLOAD)
189                 d->payload = addPayload(d->config, attr);
190
191         if (d->state == STATE_PAYLOAD_CHAIN)
192                 d->chain = addChain(d->config, d->payload);
193 }
194
195 static void data(void *data, const char *val, int len)
196 {
197         struct userdata *d = (struct userdata *)data;
198         int l;
199
200         switch (d->state) {
201         case STATE_GLOBAL_TIMEOUT:
202                 d->config->timeout = atoi(val);
203                 break;
204         case STATE_PAYLOAD_TITLE:
205                 l = sizeof(d->payload->title) - 1 > len ?
206                     len : sizeof(d->payload->title) - 1;
207
208                 strncpy((char *)d->payload->title, (char *)val, l);
209                 d->payload->title[l] = '\0';
210                 break;
211         case STATE_PAYLOAD_FILE:
212                 d->payload->file = strndup(val, len);
213                 break;
214         case STATE_PAYLOAD_LARNAME:
215                 d->payload->larname = strndup(val, len);
216                 break;
217         case STATE_PAYLOAD_CHAIN_FILE:
218                 d->chain->file = strndup(val, len);
219                 break;
220         case STATE_PAYLOAD_CHAIN_LARNAME:
221                 d->chain->larname = strndup(val, len);
222                 break;
223         default:
224                 break;
225         }
226 }
227
228 static void end(void *data, const char *el)
229 {
230         struct userdata *d = (struct userdata *)data;
231         int i;
232
233         if (d->state == STATE_PAYLOAD_CHAIN)
234                 d->chain = NULL;
235
236         if (d->state == STATE_PAYLOAD)
237                 d->payload = NULL;
238
239         for (i = 0; states[i].element != NULL; i++) {
240                 if (d->state != states[i].state)
241                         continue;
242
243                 if (!strcmp(el, states[i].element)) {
244                         d->state = states[i].pstate;
245                         break;
246                 }
247         }
248
249         if (states[i].element == NULL)
250                 die("E:  Unable to find the reverse state for %s\n", el);
251 }
252
253 void parseconfig(FILE *stream, struct config *config)
254 {
255         XML_Parser p = XML_ParserCreate(NULL);
256         int eof = 0;
257
258         if (p == NULL)
259                 die("E: Could not create the parser\n");
260
261         XML_SetElementHandler(p, start, end);
262         XML_SetCharacterDataHandler(p, data);
263
264         userdata.config = config;
265
266         XML_SetUserData(p, &userdata);
267
268         while (!eof) {
269                 int len = fread(buffer, 1, 8192, stream);
270
271                 eof = feof(stream);
272
273                 if (ferror(stream))
274                         die("E: Error reading the stream\n");
275
276                 if (!XML_Parse(p, buffer, len, eof))
277                         die("E: Error parsing the XML data\n");
278         }
279 }