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