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