chiark / gitweb /
Version bump.
[sw-tools] / src / sw.c
1 /* -*-c-*-
2  *
3  * $Id: sw.c,v 1.3 1999/09/10 15:27:32 mdw Exp $
4  *
5  * Main driver code for sw-tools
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.c,v $
32  * Revision 1.3  1999/09/10 15:27:32  mdw
33  * Include `%'-escape substitution.
34  *
35  * Revision 1.2  1999/07/16 12:50:43  mdw
36  * Replace deprecated `mdwopt' flag name with new version.
37  *
38  * Revision 1.1.1.1  1999/06/02 16:53:33  mdw
39  * Initial import.
40  *
41  */
42
43 /*----- Header files ------------------------------------------------------*/
44
45 #include "config.h"
46
47 #include <ctype.h>
48 #include <errno.h>
49 #include <signal.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53
54 #include <unistd.h>
55
56 #include <mLib/alloc.h>
57 #include <mLib/dstr.h>
58 #include <mLib/exc.h>
59 #include <mLib/mdwopt.h>
60 #include <mLib/quis.h>
61 #include <mLib/report.h>
62 #include <mLib/sub.h>
63
64 #define CMD_LINK 0
65 #include "sw.h"
66 #include "sw_arch.h"
67 #include "sw_build.h"
68 #include "sw_info.h"
69 #include "sw_links.h"
70 #include "sw_rsh.h"
71
72 /*----- Static variables --------------------------------------------------*/
73
74 static cmd *cmds = CMD_LINK;
75
76 /*----- Global option variables -------------------------------------------*
77  *
78  * It'd be nicer if these could be parsed by the build commands, but alas
79  * this is not to be.  Consider `sw configure --arch=i386-linux
80  * --with-diffutils': how is the program to know which options are for it and
81  * which are for the remote one?  The `configure' command is important,
82  * because it does some hairy stuff under the covers (inserting magical
83  * options, and running `../configure'), so I can't just require `sw run
84  * configure'.  Requiring the user to always put in a `--' to separate the
85  * two lots of options is horrific.  So they get picked up at the main
86  * program and stuffed into global variables.
87  *
88  * On the other hand, there is the advantage that `--output' options can be
89  * put in an environment variable here.
90  */
91
92 const char *opt_output = 0;
93 const char *opt_arch = 0;
94 unsigned int opt_flags = optFlag_percent;
95
96 /*----- Helpful GNUy message routines -------------------------------------*/
97
98 /* --- @version@ --- */
99
100 static void version(FILE *fp)
101 {
102   fprintf(fp, "%s v. " VERSION "\n", QUIS);
103 }
104
105 /* --- @usage@ --- */
106
107 static void usage(FILE *fp)
108 {
109   fprintf(fp, "Usage: %s [-fbip] [-a arch,...] [-o style] command [args]\n",
110           QUIS);
111 }
112
113 /* --- @help@ --- */
114
115 static void help(FILE *fp, int full)
116 {
117   cmd *p;
118   version(fp);
119   fputc('\n', fp);
120   usage(fp);
121   fputs("\n\
122 Performs various handy jobs with multiple-architecture builds.\n\
123 \n\
124 There are some options which affect a few of the available commands:\n\
125 \n\
126 -a, --arch=ARCH,...     Only build on the named architectures.\n\
127 -b, --beep              Beep when the build is complete.\n\
128 -i, --install           Mark architectures as done when build succeeds.\n\
129 -f, --force             Run build commands on installed architectures.\n\
130 -p, --percent           Enable `%'-escapes in build command arguments.\n\
131 -o, --output=STYLE      Display output in a particular style.  Use style\n\
132                         `help' for a list.\n\
133 \n", fp);
134
135   if (full) {
136     fputs("The various commands provided are:\n\n", fp);
137     for (p = cmds; p; p = p->next) {
138       fputs(p->help, fp);
139       fputc('\n', fp);
140     }
141     fprintf(fp,
142 "`%s' is an [mdw] production, brought to you in association with the\n\
143 European Bioinformatics Institute.\n", QUIS);
144   } else {
145     fputs("The various commands, in summary:\n\n", fp);
146     for (p = cmds; p; p = p->next) {
147       size_t sz = strcspn(p->help, "\n\t");
148       fwrite(p->help, 1, sz, fp);
149       fputc('\n', fp);
150     }
151     fprintf(fp,
152 "\nType `%s --help-full' for complete information.  There's a lot of it!\n",
153             QUIS);
154   }
155 }
156
157 /*----- Main code ---------------------------------------------------------*/
158
159 /* --- @main@ --- *
160  *
161  * Arguments:   @int argc@ = number of command line arguments
162  *              @char *argv[]@ = array of command line strings
163  *
164  * Returns:     Zero on success, nonzero on failure.
165  *
166  * Use:         Main program.  Parses some trivial arguments out, and
167  *              dispatches control to one of the subprogram handlers.
168  */
169
170 int main(int argc, char *argv[])
171 {
172   unsigned f = 0;
173
174   enum {
175     f_bogus = 1
176   };
177
178   /* --- Initialize the support library --- */
179
180   ego(argv[0]);
181   sub_init();
182
183   /* --- Parse command line flags --- */
184
185   for (;;) {
186     static struct option opt[] = {
187
188       /* --- Standard GNUy help options --- */
189
190       { "help",         0,              0,      'h' },
191       { "help-full",    0,              0,      'H' },
192       { "version",      0,              0,      'v' },
193       { "usage",        0,              0,      'u' },
194
195       /* --- Build options --- *
196        *
197        */
198
199       { "arch",         OPTF_ARGREQ,    0,      'a' },
200       { "force",        0,              0,      'f' },
201       { "install",      0,              0,      'i' },
202       { "output",       OPTF_ARGREQ,    0,      'o' },
203       { "beep",         OPTF_NEGATE,    0,      'b' },
204       { "percent",      OPTF_NEGATE,    0,      'p' },
205       { "escape",       OPTF_NEGATE,    0,      'p' },
206
207       /* --- Internal-use-only magical options --- *
208        *
209        * You get what you deserve if you use this.
210        */
211
212       { "me",           OPTF_ARGREQ,    0,      '=' },
213       { "remote",       OPTF_ARGREQ,    0,      '!' },
214
215       /* --- Termination marker --- */
216
217       { 0,              0,              0,      0 }
218     };
219     int i = mdwopt(argc, argv, "+hHvu a:b+p+fio:", opt, 0, 0,
220                    OPTF_ENVVAR | OPTF_NEGATION);
221     if (i < 0)
222       break;
223
224     switch (i) {
225
226       /* --- GNUy help --- */
227
228       case 'h':
229         help(stdout, 0);
230         exit(0);
231       case 'H':
232         help(stdout, 1);
233         exit(0);
234       case 'v':
235         version(stdout);
236         exit(0);
237       case 'u':
238         usage(stdout);
239         exit(0);
240
241       /* --- Build options --- */
242
243       case 'a':
244         opt_arch = optarg;
245         break;
246       case 'f':
247         opt_flags |= optFlag_force;
248         break;
249       case 'b':
250         opt_flags |= optFlag_beep;
251         break;
252       case 'b' | OPTF_NEGATED:
253         opt_flags &= ~optFlag_beep;
254         break;
255       case 'p':
256         opt_flags |= optFlag_percent;
257         break;
258       case 'p' | OPTF_NEGATED:
259         opt_flags &= ~optFlag_percent;
260         break;
261       case 'i':
262         opt_flags |= optFlag_install;
263         break;
264       case 'o':
265         opt_output = optarg;
266         break;
267
268       /* --- Magical options for internal use --- */
269
270       case '=':
271         ego(optarg);
272         break;
273       case '!':
274         swrsh_remote(optarg);
275         _exit(1);
276
277       /* --- The user screwed up --- */
278
279       default:
280         f |= f_bogus;
281         break;
282     }
283   }
284
285   if (f & f_bogus || argc == optind) {
286     usage(stderr);
287     exit(1);
288   }
289
290   /* --- Pick up the operation name --- */
291
292   argc -= optind;
293   argv += optind;
294   optind = 0;
295
296   {
297     cmd *p, *chosen = 0;
298     const char *which = argv[0];
299     size_t sz = strlen(which);
300
301     for (p = cmds; p; p = p->next) {
302       if (strncmp(which, p->name, sz) == 0) {
303         if (p->name[sz] == 0) {
304           chosen = p;
305           break;
306         } else if (chosen)
307           die(1, "ambiguous command name `%s'", which);
308         chosen = p;
309       }
310     }
311
312     if (!chosen)
313       die(1, "unknown command name `%s'", which);
314     signal(SIGPIPE, SIG_IGN);
315     TRY
316       return (chosen->cmd(argc, argv));
317     CATCH switch (exc_type) {
318       case EXC_NOMEM:
319         die(1, "not enough memory");
320       default:
321         RETHROW;
322     } END_TRY;
323   }
324   return (127);
325 }
326
327 /*----- That's all, folks -------------------------------------------------*/