3315e8b3 |
1 | /* -*-c-*- |
2 | * |
9796a787 |
3 | * $Id: sw_arch.c,v 1.2 2004/04/08 01:52:19 mdw Exp $ |
3315e8b3 |
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 | |
3315e8b3 |
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 -------------------------------------------------*/ |