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