chiark / gitweb /
Stupid thing doesn't automatically distribute manpages.
[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 -------------------------------------------------*/