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