2
* The contents of this file are subject to the Mozilla Public
3
* License Version 1.1 (the "License"); you may not use this file
4
* except in compliance with the License. You may obtain a copy of
5
* the License at http://www.mozilla.org/MPL/
7
* Software distributed under the License is distributed on an "AS
8
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9
* implied. See the License for the specific language governing
10
* rights and limitations under the License.
12
* The Original Code is the Netscape security libraries.
14
* The Initial Developer of the Original Code is Netscape
15
* Communications Corporation. Portions created by Netscape are
16
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
21
* Alternatively, the contents of this file may be used under the
22
* terms of the GNU General Public License Version 2 or later (the
23
* "GPL"), in which case the provisions of the GPL are applicable
24
* instead of those above. If you wish to allow use of your
25
* version of this file only under the terms of the GPL and not to
26
* allow others to use your version of this file under the MPL,
27
* indicate your decision by deleting the provisions above and
28
* replace them with the notice and other provisions required by
29
* the GPL. If you do not delete the provisions above, a recipient
30
* may use your version of this file under either the MPL or the
39
static int s_indent_size = 4;
42
CMD_SetIndentSize(int size)
49
indent(PRFileDesc *out, int level)
52
for (i=0; i<level; i++)
53
for (j=0; j<s_indent_size; j++)
58
struct cmdPrintStateStr {
66
init_print_ps(cmdPrintState *ps, PRFileDesc *outfile, int width, int indent)
68
ps->file = (outfile) ? outfile : PR_STDOUT;
69
ps->width = (width > 0) ? width : 80;
70
ps->indent = (indent > 0) ? indent : 0;
75
print_ps_indent(cmdPrintState *ps)
78
if (ps->linepos != 0) {
79
PR_fprintf(ps->file, "\n");
82
for (j=0; j<=ps->indent; j++) PR_fprintf(ps->file, " ");
83
ps->linepos = ps->indent;
87
print_ps_to_indent(cmdPrintState *ps)
89
if (ps->linepos > ps->indent)
90
PR_fprintf(ps->file, "\n");
91
while (ps->linepos <= ps->indent) {
92
PR_fprintf(ps->file, " ");
98
nprintbuf(cmdPrintState *ps, char *buf, int start, int len)
101
for (j=start; j<start + len; j++) {
102
if (buf[j] == '\n') {
103
PR_fprintf(ps->file, "\n");
107
PR_fprintf(ps->file, "%c", buf[j]);
114
nprintf(cmdPrintState *ps, char *msg, ...)
117
int i, len, grouplen;
118
PRBool openquote, openbracket, openparen, openangle, itsaword;
121
vsprintf(buf, msg, args);
123
/* print_ps_indent(ps); */
124
if (len < ps->width - ps->linepos) {
125
nprintbuf(ps, buf, 0, len + 1);
128
/* group in this order: " [ ( < word > ) ] " */
130
openquote=openbracket=openparen=openangle=itsaword=PR_FALSE;
133
if (buf[i] == '\"') { openquote = PR_TRUE; grouplen = 1; }
134
else if (buf[i] == '[') { openbracket = PR_TRUE; grouplen = 1; }
135
else if (buf[i] == '(') { openparen = PR_TRUE; grouplen = 1; }
136
else if (buf[i] == '<') { openangle = PR_TRUE; grouplen = 1; }
137
else itsaword = PR_TRUE;
138
while (grouplen < len && buf[i+grouplen] != '\0' &&
139
((openquote && buf[i+grouplen] != '\"') ||
140
(openbracket && buf[i+grouplen] != ']') ||
141
(openparen && buf[i+grouplen] != ')') ||
142
(openangle && buf[i+grouplen] != '>') ||
143
(itsaword && !isspace(buf[i+grouplen]))))
145
grouplen++; /* grab the terminator (whitespace for word) */
146
if (!itsaword && isspace(buf[i+grouplen])) grouplen++;
147
if (grouplen < ps->width - ps->linepos) {
148
nprintbuf(ps, buf, i, grouplen);
149
} else if (grouplen < ps->width - ps->indent) {
151
nprintbuf(ps, buf, i, grouplen);
153
/* it's just too darn long. what to do? */
156
openquote=openbracket=openparen=openangle=itsaword=PR_FALSE;
162
CMD_PrintUsageString(cmdPrintState *ps, char *str)
164
nprintf(ps, "%s", str);
167
/* void because it exits with Usage() if failure */
169
command_line_okay(cmdCommand *cmd, char *progName)
172
/* user asked for help. hope somebody gives it to them. */
173
if (cmd->opt[0].on) return;
174
/* check that the command got all of its needed options */
175
for (i=0; i<cmd->ncmd; i++) {
176
if (cmd->cmd[i].on) {
179
"%s: only one command can be given at a time.\n",
181
CMD_Usage(progName, cmd);
187
if (cmd->cmd[c].argUse == CMDArgReq && cmd->cmd[c].arg == NULL) {
188
/* where's the arg when you need it... */
189
fprintf(stderr, "%s: command --%s requires an argument.\n",
190
progName, cmd->cmd[c].s);
191
fprintf(stderr, "type \"%s --%s --help\" for help.\n",
192
progName, cmd->cmd[c].s);
193
CMD_Usage(progName, cmd);
195
for (i=0; i<cmd->nopt; i++) {
196
if (cmd->cmd[c].req & CMDBIT(i)) {
197
/* command requires this option */
198
if (!cmd->opt[i].on) {
199
/* but it ain't there */
200
fprintf(stderr, "%s: command --%s requires option --%s.\n",
201
progName, cmd->cmd[c].s, cmd->opt[i].s);
203
/* okay, its there, but does it have an arg? */
204
if (cmd->opt[i].argUse == CMDArgReq && !cmd->opt[i].arg) {
205
fprintf(stderr, "%s: option --%s requires an argument.\n",
206
progName, cmd->opt[i].s);
209
} else if (cmd->cmd[c].opt & CMDBIT(i)) {
210
/* this option is optional */
211
if (cmd->opt[i].on) {
212
/* okay, its there, but does it have an arg? */
213
if (cmd->opt[i].argUse == CMDArgReq && !cmd->opt[i].arg) {
214
fprintf(stderr, "%s: option --%s requires an argument.\n",
215
progName, cmd->opt[i].s);
219
/* command knows nothing about it */
220
if (cmd->opt[i].on) {
221
/* so why the h--- is it on? */
222
fprintf(stderr, "%s: option --%s not used with command --%s.\n",
223
progName, cmd->opt[i].s, cmd->cmd[c].s);
230
get_arg(char *curopt, char **nextopt, int argc, int *index)
236
if (*index + 1 >= argc) return NULL;
237
/* not really an argument but another flag */
238
if (nextopt[*index+1][0] == '-') return NULL;
239
str = nextopt[++(*index)];
241
/* parse the option */
246
CMD_ParseCommandLine(int argc, char **argv, char *progName, cmdCommand *cmd)
252
if (argc <= 1) return -2; /* gross hack for cmdless things like atob */
255
if (strlen(flag) < 2) /* huh? */
259
/* ignore everything after lone "--" (app-specific weirdness there) */
260
if (strcmp(flag, "--") == 0)
262
/* single hyphen means short alias (single-char) */
263
if (flag[1] != '-') {
265
/* collect a set of opts, ex. -abc */
266
while (flag[j] != '\0') {
267
PRBool found = PR_FALSE;
268
/* walk the command set looking for match */
269
for (k=0; k<cmd->ncmd; k++) {
270
if (flag[j] == cmd->cmd[k].c) {
271
/* done - only take one command at a time */
272
if (j > 1) return -1;
273
cmd->cmd[k].on = found = PR_TRUE;
275
if (cmd->cmd[k].argUse != CMDNoArg)
276
cmd->cmd[k].arg = get_arg(NULL, argv, argc, &i);
280
/* wasn't found in commands, try options */
281
for (k=0; k<cmd->nopt; k++) {
282
if (flag[j] == cmd->opt[k].c) {
283
/* collect this option and keep going */
284
cmd->opt[k].on = found = PR_TRUE;
285
if (flag[j+1] == '\0') {
286
if (cmd->opt[k].argUse != CMDNoArg)
287
cmd->opt[k].arg = get_arg(NULL, argv, argc, &i);
293
if (!found) return -1;
295
} else { /* long alias, ex. --list */
296
char *fl = NULL, *arg = NULL;
297
PRBool hyphened = PR_FALSE;
299
arg = strchr(fl, '=');
303
arg = strchr(fl, '-');
305
hyphened = PR_TRUE; /* watch this, see below */
309
for (k=0; k<cmd->ncmd; k++) {
310
if (strcmp(fl, cmd->cmd[k].s) == 0) {
311
cmd->cmd[k].on = PR_TRUE;
313
if (cmd->cmd[k].argUse != CMDNoArg || hyphened) {
314
cmd->cmd[k].arg = get_arg(arg, argv, argc, &i);
316
if (arg) arg[-1] = '=';
320
for (k=0; k<cmd->nopt; k++) {
321
if (strcmp(fl, cmd->opt[k].s) == 0) {
322
cmd->opt[k].on = PR_TRUE;
323
if (cmd->opt[k].argUse != CMDNoArg || hyphened) {
324
cmd->opt[k].arg = get_arg(arg, argv, argc, &i);
326
if (arg) arg[-1] = '=';
335
command_line_okay(cmd, progName);
340
CMD_LongUsage(char *progName, cmdCommand *cmd, cmdUsageCallback usage)
343
PRBool oneCommand = PR_FALSE;
345
init_print_ps(&ps, PR_STDERR, 80, 0);
346
nprintf(&ps, "\n%s: ", progName);
347
/* prints app-specific header */
348
ps.indent = strlen(progName) + 4;
349
usage(&ps, 0, PR_FALSE, PR_TRUE, PR_FALSE);
350
for (i=0; i<cmd->ncmd; i++) if (cmd->cmd[i].on) oneCommand = PR_TRUE;
351
for (i=0; i<cmd->ncmd; i++) {
352
if ((oneCommand && cmd->cmd[i].on) || !oneCommand) {
354
print_ps_indent(&ps);
355
if (cmd->cmd[i].c != 0) {
356
nprintf(&ps, "-%c, ", cmd->cmd[i].c);
357
nprintf(&ps, "--%-16s ", cmd->cmd[i].s);
359
nprintf(&ps, "--%-20s ", cmd->cmd[i].s);
362
usage(&ps, i, PR_TRUE, PR_FALSE, PR_FALSE);
363
for (j=0; j<cmd->nopt; j++) {
364
if (cmd->cmd[i].req & CMDBIT(j)) {
366
print_ps_indent(&ps);
367
nprintf(&ps, "%3s* ", "");
368
if (cmd->opt[j].c != 0) {
369
nprintf(&ps, "-%c, ", cmd->opt[j].c);
370
nprintf(&ps, "--%-16s ", cmd->opt[j].s);
372
nprintf(&ps, "--%-20s ", cmd->opt[j].s);
375
usage(&ps, j, PR_FALSE, PR_FALSE, PR_FALSE);
378
for (j=0; j<cmd->nopt; j++) {
379
if (cmd->cmd[i].opt & CMDBIT(j)) {
381
print_ps_indent(&ps);
382
nprintf(&ps, "%5s", "");
383
if (cmd->opt[j].c != 0) {
384
nprintf(&ps, "-%c, ", cmd->opt[j].c);
385
nprintf(&ps, "--%-16s ", cmd->opt[j].s);
387
nprintf(&ps, "--%-20s ", cmd->opt[j].s);
390
usage(&ps, j, PR_FALSE, PR_FALSE, PR_FALSE);
397
nprintf(&ps, "\n* - required flag for command\n\n");
398
/* prints app-specific footer */
399
usage(&ps, 0, PR_FALSE, PR_FALSE, PR_TRUE);
400
/*nprintf(&ps, "\n\n");*/
405
CMD_Usage(char *progName, cmdCommand *cmd)
410
init_print_ps(&ps, PR_STDERR, 80, 0);
411
nprintf(&ps, "%s", progName);
412
ps.indent = strlen(progName) + 1;
413
print_ps_to_indent(&ps);
414
for (i=0; i<cmd->ncmd; i++) {
415
if (cmd->cmd[i].c != 0) {
416
nprintf(&ps, "-%c", cmd->cmd[i].c);
419
nprintf(&ps, "--%s", cmd->cmd[i].s);
420
inc = 4 + strlen(cmd->cmd[i].s);
424
print_ps_to_indent(&ps);
425
for (j=0; j<cmd->nopt; j++) {
426
if (cmd->cmd[i].req & CMDBIT(j)) {
427
if (cmd->opt[j].c != 0 && cmd->opt[j].argUse == CMDNoArg) {
432
nprintf(&ps, "%c", cmd->opt[j].c);
436
for (j=0; j<cmd->nopt; j++) {
437
if (cmd->cmd[i].req & CMDBIT(j)) {
438
if (cmd->opt[j].c != 0)
439
nprintf(&ps, "-%c ", cmd->opt[j].c);
441
nprintf(&ps, "--%s ", cmd->opt[j].s);
442
if (cmd->opt[j].argUse != CMDNoArg)
443
nprintf(&ps, "%s ", cmd->opt[j].s);
447
for (j=0; j<cmd->nopt; j++) {
448
if (cmd->cmd[i].opt & CMDBIT(j)) {
449
if (cmd->opt[j].c != 0 && cmd->opt[j].argUse == CMDNoArg) {
454
nprintf(&ps, "%c", cmd->opt[j].c);
458
if (!first) nprintf(&ps, "] ");
459
for (j=0; j<cmd->nopt; j++) {
460
if (cmd->cmd[i].opt & CMDBIT(j) &&
461
cmd->opt[j].argUse != CMDNoArg) {
462
if (cmd->opt[j].c != 0)
463
nprintf(&ps, "[-%c %s] ", cmd->opt[j].c, cmd->opt[j].s);
465
nprintf(&ps, "[--%s %s] ", cmd->opt[j].s, cmd->opt[j].s);
469
print_ps_indent(&ps);