3315e8b3 |
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 -------------------------------------------------*/ |