/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */ #include #include #include "cmdutil.h" static int s_indent_size = 4; void CMD_SetIndentSize(int size) { s_indent_size = size; } #if 0 static void indent(PRFileDesc *out, int level) { int i, j; for (i=0; ifile = (outfile) ? outfile : PR_STDOUT; ps->width = (width > 0) ? width : 80; ps->indent = (indent > 0) ? indent : 0; ps->linepos = 0; } static void print_ps_indent(cmdPrintState *ps) { int j; if (ps->linepos != 0) { PR_fprintf(ps->file, "\n"); ps->linepos = 0; } for (j=0; j<=ps->indent; j++) PR_fprintf(ps->file, " "); ps->linepos = ps->indent; } static void print_ps_to_indent(cmdPrintState *ps) { if (ps->linepos > ps->indent) PR_fprintf(ps->file, "\n"); while (ps->linepos <= ps->indent) { PR_fprintf(ps->file, " "); ps->linepos++; } } static void nprintbuf(cmdPrintState *ps, char *buf, int start, int len) { int j; for (j=start; jfile, "\n"); ps->linepos = 0; print_ps_indent(ps); } else { PR_fprintf(ps->file, "%c", buf[j]); ps->linepos++; } } } static void nprintf(cmdPrintState *ps, char *msg, ...) { char buf[256]; int i, len, grouplen; PRBool openquote, openbracket, openparen, openangle, itsaword; va_list args; va_start(args, msg); vsprintf(buf, msg, args); len = strlen(buf); /* print_ps_indent(ps); */ if (len < ps->width - ps->linepos) { nprintbuf(ps, buf, 0, len + 1); return; } /* group in this order: " [ ( < word > ) ] " */ i=0; openquote=openbracket=openparen=openangle=itsaword=PR_FALSE; while (iwidth - ps->linepos) { nprintbuf(ps, buf, i, grouplen); } else if (grouplen < ps->width - ps->indent) { print_ps_indent(ps); nprintbuf(ps, buf, i, grouplen); } else { /* it's just too darn long. what to do? */ } i += grouplen; openquote=openbracket=openparen=openangle=itsaword=PR_FALSE; } va_end(args); } void CMD_PrintUsageString(cmdPrintState *ps, char *str) { nprintf(ps, "%s", str); } /* void because it exits with Usage() if failure */ static void command_line_okay(cmdCommand *cmd, char *progName) { int i, c = -1; /* user asked for help. hope somebody gives it to them. */ if (cmd->opt[0].on) return; /* check that the command got all of its needed options */ for (i=0; incmd; i++) { if (cmd->cmd[i].on) { if (c > 0) { fprintf(stderr, "%s: only one command can be given at a time.\n", progName); CMD_Usage(progName, cmd); } else { c = i; } } } if (cmd->cmd[c].argUse == CMDArgReq && cmd->cmd[c].arg == NULL) { /* where's the arg when you need it... */ fprintf(stderr, "%s: command --%s requires an argument.\n", progName, cmd->cmd[c].s); fprintf(stderr, "type \"%s --%s --help\" for help.\n", progName, cmd->cmd[c].s); CMD_Usage(progName, cmd); } for (i=0; inopt; i++) { if (cmd->cmd[c].req & CMDBIT(i)) { /* command requires this option */ if (!cmd->opt[i].on) { /* but it ain't there */ fprintf(stderr, "%s: command --%s requires option --%s.\n", progName, cmd->cmd[c].s, cmd->opt[i].s); } else { /* okay, its there, but does it have an arg? */ if (cmd->opt[i].argUse == CMDArgReq && !cmd->opt[i].arg) { fprintf(stderr, "%s: option --%s requires an argument.\n", progName, cmd->opt[i].s); } } } else if (cmd->cmd[c].opt & CMDBIT(i)) { /* this option is optional */ if (cmd->opt[i].on) { /* okay, its there, but does it have an arg? */ if (cmd->opt[i].argUse == CMDArgReq && !cmd->opt[i].arg) { fprintf(stderr, "%s: option --%s requires an argument.\n", progName, cmd->opt[i].s); } } } else { /* command knows nothing about it */ if (cmd->opt[i].on) { /* so why the h--- is it on? */ fprintf(stderr, "%s: option --%s not used with command --%s.\n", progName, cmd->opt[i].s, cmd->cmd[c].s); } } } } static char * get_arg(char *curopt, char **nextopt, int argc, int *index) { char *str; if (curopt) { str = curopt; } else { if (*index + 1 >= argc) return NULL; /* not really an argument but another flag */ if (nextopt[*index+1][0] == '-') return NULL; str = nextopt[++(*index)]; } /* parse the option */ return strdup(str); } int CMD_ParseCommandLine(int argc, char **argv, char *progName, cmdCommand *cmd) { int i, j, k; int cmdToRun = -1; char *flag; i=1; if (argc <= 1) return -2; /* gross hack for cmdless things like atob */ do { flag = argv[i]; if (strlen(flag) < 2) /* huh? */ return -1; if (flag[0] != '-') return -1; /* ignore everything after lone "--" (app-specific weirdness there) */ if (strcmp(flag, "--") == 0) return cmdToRun; /* single hyphen means short alias (single-char) */ if (flag[1] != '-') { j=1; /* collect a set of opts, ex. -abc */ while (flag[j] != '\0') { PRBool found = PR_FALSE; /* walk the command set looking for match */ for (k=0; kncmd; k++) { if (flag[j] == cmd->cmd[k].c) { /* done - only take one command at a time */ if (j > 1) return -1; cmd->cmd[k].on = found = PR_TRUE; cmdToRun = k; if (cmd->cmd[k].argUse != CMDNoArg) cmd->cmd[k].arg = get_arg(NULL, argv, argc, &i); goto next_flag; } } /* wasn't found in commands, try options */ for (k=0; knopt; k++) { if (flag[j] == cmd->opt[k].c) { /* collect this option and keep going */ cmd->opt[k].on = found = PR_TRUE; if (flag[j+1] == '\0') { if (cmd->opt[k].argUse != CMDNoArg) cmd->opt[k].arg = get_arg(NULL, argv, argc, &i); goto next_flag; } } } j++; if (!found) return -1; } } else { /* long alias, ex. --list */ char *fl = NULL, *arg = NULL; PRBool hyphened = PR_FALSE; fl = &flag[2]; arg = strchr(fl, '='); if (arg) { *arg++ = '\0'; } else { arg = strchr(fl, '-'); if (arg) { hyphened = PR_TRUE; /* watch this, see below */ *arg++ = '\0'; } } for (k=0; kncmd; k++) { if (strcmp(fl, cmd->cmd[k].s) == 0) { cmd->cmd[k].on = PR_TRUE; cmdToRun = k; if (cmd->cmd[k].argUse != CMDNoArg || hyphened) { cmd->cmd[k].arg = get_arg(arg, argv, argc, &i); } if (arg) arg[-1] = '='; goto next_flag; } } for (k=0; knopt; k++) { if (strcmp(fl, cmd->opt[k].s) == 0) { cmd->opt[k].on = PR_TRUE; if (cmd->opt[k].argUse != CMDNoArg || hyphened) { cmd->opt[k].arg = get_arg(arg, argv, argc, &i); } if (arg) arg[-1] = '='; goto next_flag; } } return -1; } next_flag: i++; } while (i < argc); command_line_okay(cmd, progName); return cmdToRun; } void CMD_LongUsage(char *progName, cmdCommand *cmd, cmdUsageCallback usage) { int i, j; PRBool oneCommand = PR_FALSE; cmdPrintState ps; init_print_ps(&ps, PR_STDERR, 80, 0); nprintf(&ps, "\n%s: ", progName); /* prints app-specific header */ ps.indent = strlen(progName) + 4; usage(&ps, 0, PR_FALSE, PR_TRUE, PR_FALSE); for (i=0; incmd; i++) if (cmd->cmd[i].on) oneCommand = PR_TRUE; for (i=0; incmd; i++) { if ((oneCommand && cmd->cmd[i].on) || !oneCommand) { ps.indent = 0; print_ps_indent(&ps); if (cmd->cmd[i].c != 0) { nprintf(&ps, "-%c, ", cmd->cmd[i].c); nprintf(&ps, "--%-16s ", cmd->cmd[i].s); } else { nprintf(&ps, "--%-20s ", cmd->cmd[i].s); } ps.indent += 20; usage(&ps, i, PR_TRUE, PR_FALSE, PR_FALSE); for (j=0; jnopt; j++) { if (cmd->cmd[i].req & CMDBIT(j)) { ps.indent = 0; print_ps_indent(&ps); nprintf(&ps, "%3s* ", ""); if (cmd->opt[j].c != 0) { nprintf(&ps, "-%c, ", cmd->opt[j].c); nprintf(&ps, "--%-16s ", cmd->opt[j].s); } else { nprintf(&ps, "--%-20s ", cmd->opt[j].s); } ps.indent += 29; usage(&ps, j, PR_FALSE, PR_FALSE, PR_FALSE); } } for (j=0; jnopt; j++) { if (cmd->cmd[i].opt & CMDBIT(j)) { ps.indent = 0; print_ps_indent(&ps); nprintf(&ps, "%5s", ""); if (cmd->opt[j].c != 0) { nprintf(&ps, "-%c, ", cmd->opt[j].c); nprintf(&ps, "--%-16s ", cmd->opt[j].s); } else { nprintf(&ps, "--%-20s ", cmd->opt[j].s); } ps.indent += 29; usage(&ps, j, PR_FALSE, PR_FALSE, PR_FALSE); } } } nprintf(&ps, "\n"); } ps.indent = 0; nprintf(&ps, "\n* - required flag for command\n\n"); /* prints app-specific footer */ usage(&ps, 0, PR_FALSE, PR_FALSE, PR_TRUE); /*nprintf(&ps, "\n\n");*/ exit(1); } void CMD_Usage(char *progName, cmdCommand *cmd) { int i, j, inc; PRBool first; cmdPrintState ps; init_print_ps(&ps, PR_STDERR, 80, 0); nprintf(&ps, "%s", progName); ps.indent = strlen(progName) + 1; print_ps_to_indent(&ps); for (i=0; incmd; i++) { if (cmd->cmd[i].c != 0) { nprintf(&ps, "-%c", cmd->cmd[i].c); inc = 4; } else { nprintf(&ps, "--%s", cmd->cmd[i].s); inc = 4 + strlen(cmd->cmd[i].s); } first = PR_TRUE; ps.indent += inc; print_ps_to_indent(&ps); for (j=0; jnopt; j++) { if (cmd->cmd[i].req & CMDBIT(j)) { if (cmd->opt[j].c != 0 && cmd->opt[j].argUse == CMDNoArg) { if (first) { nprintf(&ps, "-"); first = !first; } nprintf(&ps, "%c", cmd->opt[j].c); } } } for (j=0; jnopt; j++) { if (cmd->cmd[i].req & CMDBIT(j)) { if (cmd->opt[j].c != 0) nprintf(&ps, "-%c ", cmd->opt[j].c); else nprintf(&ps, "--%s ", cmd->opt[j].s); if (cmd->opt[j].argUse != CMDNoArg) nprintf(&ps, "%s ", cmd->opt[j].s); } } first = PR_TRUE; for (j=0; jnopt; j++) { if (cmd->cmd[i].opt & CMDBIT(j)) { if (cmd->opt[j].c != 0 && cmd->opt[j].argUse == CMDNoArg) { if (first) { nprintf(&ps, "[-"); first = !first; } nprintf(&ps, "%c", cmd->opt[j].c); } } } if (!first) nprintf(&ps, "] "); for (j=0; jnopt; j++) { if (cmd->cmd[i].opt & CMDBIT(j) && cmd->opt[j].argUse != CMDNoArg) { if (cmd->opt[j].c != 0) nprintf(&ps, "[-%c %s] ", cmd->opt[j].c, cmd->opt[j].s); else nprintf(&ps, "[--%s %s] ", cmd->opt[j].s, cmd->opt[j].s); } } ps.indent -= inc; print_ps_indent(&ps); } ps.indent = 0; nprintf(&ps, "\n"); exit(1); }