usage: Print metavariables in SHOUTY letters.
[sw-tools] / src / sw_arch.c
1 /* -*-c-*-
2 *
3 * $Id: sw_arch.c,v 1.2 2004/04/08 01:52:19 mdw Exp $
4 *
5 * Messing with architectures
6 *
7 * (c) 1999 EBI
8 */
9
10 /*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of sw-tools.
13 *
14 * sw-tools is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * sw-tools is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with sw-tools; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29 /*----- Header files ------------------------------------------------------*/
30
31 #include "config.h"
32
33 #include <ctype.h>
34 #include <errno.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include <mLib/alloc.h>
40 #include <mLib/dstr.h>
41 #include <mLib/quis.h>
42 #include <mLib/report.h>
43 #include <mLib/sub.h>
44
45 #include "sw_arch.h"
46 #include "sw_info.h"
47
48 /*----- Static variables --------------------------------------------------*/
49
50 static archcons *tab = 0;
51
52 /*----- Main code ---------------------------------------------------------*/
53
54 /* --- @arch_readtab@ --- *
55 *
56 * Arguments: ---
57 *
58 * Returns: The address of the archtab list.
59 *
60 * Use: Reads the archtab file (if necessary) and returns a list of
61 * its contents.
62 */
63
64 archcons *arch_readtab(void)
65 {
66 archcons **p;
67 FILE *fp;
68 dstr d = DSTR_INIT;
69
70 /* --- Return the list if I've already got it --- */
71
72 if (tab)
73 return (tab);
74
75 /* --- Open the file --- */
76
77 if ((fp = fopen(ARCHTAB, "r")) == 0)
78 die(1, "couldn't open `%s': %s", ARCHTAB, strerror(errno));
79
80 /* --- Read it in line-by-line --- */
81
82 p = &tab;
83 for (; dstr_putline(&d, fp) != EOF; DRESET(&d)) {
84 archent *a;
85 char *q = d.buf;
86 char *arch, *host;
87
88 /* --- Pick out the architecture name --- */
89
90 while (isspace((unsigned char)*q))
91 q++;
92 if (*q == '#' || *q == 0)
93 continue;
94 arch = q;
95 while (*q && !isspace((unsigned char)*q))
96 q++;
97 if (*q)
98 *q++ = 0;
99
100 /* --- Pick out the hostname --- */
101
102 while (isspace((unsigned char)*q))
103 q++;
104 if (!q)
105 continue;
106 host = q;
107 while (*q && !isspace((unsigned char)*q))
108 q++;
109 if (*q)
110 *q++ = 0;
111
112 /* --- Allocate a new link --- */
113
114 a = xmalloc(sizeof(*a));
115 a->arch = xstrdup(arch);
116 a->host = xstrdup(host);
117 a->cons.car = a;
118 a->r = 0;
119 a->pres = 0;
120 a->flags = 0;
121 if (strcmp(arch, ARCH) == 0)
122 a->flags |= archFlag_home;
123 *p = &a->cons;
124 p = &a->cons.cdr;
125 }
126
127 /* --- Done --- */
128
129 dstr_destroy(&d);
130 fclose(fp);
131 *p = 0;
132 return (tab);
133 }
134
135 /* --- @arch_lookup@ --- *
136 *
137 * Arguments: @const char *arch@ = pointer to archtecture name
138 * @int abbrev@ = whether abbreviations are OK
139 *
140 * Returns: Pointer to archtab block, or null.
141 *
142 * Use: Translates an architecture name into the name of a host
143 * supporting that architecture.
144 */
145
146 archent *arch_lookup(const char *arch, int abbrev)
147 {
148 size_t sz = strlen(arch);
149 archcons *a;
150 archent *chosen = 0;
151
152 for (a = arch_readtab(); a; a = a->cdr) {
153 archent *e = a->car;
154 if (strncmp(arch, e->arch, sz) == 0) {
155 if (e->arch[sz] == 0)
156 return (e);
157 else if (!abbrev)
158 continue;
159 else if (chosen)
160 return (0);
161 else
162 chosen = e;
163 }
164 }
165 return (chosen);
166 }
167
168 /* --- @arch_filter@ --- *
169 *
170 * Arguments: @archcons *a@ = input list to filter
171 * @const char *p@ = pointer to a textual list of architectures
172 * @unsigned and@, @unsigned xor@ = flags to look for
173 *
174 * Returns: A newly constructed architecture list containing only the
175 * listed architectures.
176 *
177 * Use: Filters the architecture list down to a few interesting
178 * architectures.
179 *
180 * If @p@ is non-null, it is a textual list of architecture
181 * names (possibly abbreviated), and separated by whitespace
182 * and/or commas: only the named architectures are included in
183 * the resulting list. If @p@ is null, all architectures are
184 * considered.
185 *
186 * The list is further trimmed down by examining the flags words
187 * in each entry. Only entries with flags @f@ where @(f ^ xor)
188 * & and@ is zero are left in the resulting list. (To include
189 * all entries, clear @and@ to zero. To require a flag to be
190 * clear, set the corresponding bit in @and@. To require a flag
191 * to be set, set the corresponding bit in both @and@ and @xor@.
192 *
193 * (Don't try to filter on the @archFlag_touched@ flag. That
194 * flag is for the internal use of this routine.)
195 */
196
197 archcons *arch_filter(archcons *a, const char *p,
198 unsigned and, unsigned xor)
199 {
200 archcons *h;
201
202 /* --- How this works --- *
203 *
204 * If I have a list of architecture names in @p@, then I scan the list and
205 * set the `touch' bit on matching entries, and clear it on nonmatching
206 * ones. Then I set the `touch' bit in the @and@ and @xor@ arguments.
207 * Otherwise I skip all of that, and clear the `touch' bit in @and@. After
208 * all that, I just scoop up the architectures with appropriate flags.
209 */
210
211 and &= ~archFlag_touched;
212 if (p) {
213
214 /* --- Clear all the touch flags --- */
215
216 {
217 archcons *aa;
218 for (aa = a; aa; aa = aa->cdr)
219 aa->car->flags &= ~archFlag_touched;
220 }
221
222 /* --- Set flags for entries in my list --- */
223
224 {
225 char *q = xstrdup(p);
226 for (p = strtok(q, ", \t"); p; p = strtok(0, ", \t")) {
227 archent *e = arch_lookup(p, 1);
228 if (!e)
229 die(1, "architecture `%s' not found", p);
230 e->flags |= archFlag_touched;
231 }
232 free(q);
233 }
234
235 /* --- Only include touched entries --- */
236
237 and |= archFlag_touched;
238 xor |= archFlag_touched;
239 }
240
241 /* --- Now trundle through the list accumulating matching entries --- */
242
243 {
244 archcons **p = &h;
245
246 for (; a; a = a->cdr) {
247 if (((a->car->flags ^ xor) & and) == 0) {
248 archcons *aa = CREATE(archcons);
249 aa->car = a->car;
250 *p = aa;
251 p = &aa->cdr;
252 }
253 }
254 *p = 0;
255 }
256
257 /* --- Done --- */
258
259 return (h);
260 }
261
262 /* --- @arch_free@ --- *
263 *
264 * Arguments: @archcons *a@ = pointer to a list
265 *
266 * Returns: ---
267 *
268 * Use: Contrary to anything you might have expected from the Lispy
269 * naming, old architecture lists don't get garbage collected.
270 * This routine throws away an old list when you don't want it
271 * any more. Don't call this on the main list! It will fail
272 * miserably, because the cons cells in the main list are
273 * faked.
274 */
275
276 void arch_free(archcons *a)
277 {
278 while (a) {
279 archcons *p = a->cdr;
280 DESTROY(a);
281 a = p;
282 }
283 }
284
285 /* --- @arch_toText@ --- *
286 *
287 * Arguments: @dstr *d@ = pointer to dynamic string to build result in
288 * @archcons *a@ = list to write into the string
289 * @unsigned and@, @unsigned xor@ = flags to look for
290 *
291 * Returns: ---
292 *
293 * Use: Writes a textual list of architectures to a string. This can
294 * then be used (for example) as the `only-arch' list in the
295 * info file, by filling it into a skeleton and calling
296 * @swinfo_update@. The @and@ and @xor@ arguments work in the
297 * same way as with @arch_filter@.
298 */
299
300 void arch_toText(dstr *d, archcons *a, unsigned and, unsigned xor)
301 {
302 int spc = 0;
303
304 for (; a; a = a->cdr) {
305 archent *e = a->car;
306 if (((e->flags ^ xor) & and) == 0) {
307 if (spc)
308 dstr_putc(d, ' ');
309 dstr_puts(d, e->arch);
310 spc = 1;
311 }
312 }
313 }
314
315 /*----- Subcommands -------------------------------------------------------*/
316
317 /* --- @sw_arch@ --- */
318
319 int sw_arch(int argc, char *argv[])
320 {
321 if (argc != 1)
322 die(1, "Usage: arch");
323 puts(ARCH);
324 return (0);
325 }
326
327 /* --- @sw_host@ --- */
328
329 int sw_host(int argc, char *argv[])
330 {
331 archent *a;
332 if (argc != 2)
333 die(1, "Usage: host ARCH");
334 if ((a = arch_lookup(argv[1], 1)) == 0)
335 die(1, "no host for architecture `%s'", argv[1]);
336 puts(a->host);
337 return (0);
338 }
339
340 /* --- @sw_listarch@ --- */
341
342 int sw_listarch(int argc, char *argv[])
343 {
344 archcons *a;
345 if (argc != 1)
346 die(1, "Usage: listarch");
347 for (a = arch_readtab(); a; a = a->cdr)
348 puts(a->car->arch);
349 return (0);
350 }
351
352 /* --- @sw_all@ --- */
353
354 int sw_all(int argc, char *argv[])
355 {
356 swinfo sw;
357 if (argc != 1)
358 die(1, "Usage: all");
359 if (swinfo_fetch(&sw)) {
360 die(1, "couldn't read build status: %s (try running setup)",
361 strerror(errno));
362 }
363 if (sw.only_arch) {
364 free(sw.only_arch);
365 sw.only_arch = 0;
366 swinfo_put(&sw);
367 }
368 return (0);
369 }
370
371 /* --- @sw_only@ --- */
372
373 int sw_only(int argc, char *argv[])
374 {
375 dstr d = DSTR_INIT;
376
377 /* --- Validate the arguments --- */
378
379 if (argc < 2)
380 die(1, "Usage: only-arch ARCH,...");
381
382 /* --- Gather the arguments into one buffer --- */
383
384 {
385 int i;
386 for (i = 1; i < argc; i++) {
387 dstr_putc(&d, ' ');
388 dstr_puts(&d, argv[i]);
389 }
390 }
391
392 /* --- Convert into a canonical list --- */
393
394 {
395 archcons *a = arch_filter(arch_readtab(), d.buf, 0, 0);
396 DRESET(&d);
397 arch_toText(&d, a, 0, 0);
398 arch_free(a);
399 }
400
401 /* --- Put the list into the information table --- */
402
403 {
404 swinfo sw, skel;
405
406 if (swinfo_fetch(&sw)) {
407 die(1, "couldn't read build status: %s (try running setup)",
408 strerror(errno));
409 }
410
411 swinfo_clear(&skel);
412 skel.only_arch = d.buf;
413 swinfo_update(&sw, &skel);
414
415 swinfo_put(&sw);
416 dstr_destroy(&d);
417 }
418
419 return (0);
420 }
421
422 /*----- That's all, folks -------------------------------------------------*/