17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM * CDDL HEADER START
37836SJohn.Forte@Sun.COM *
47836SJohn.Forte@Sun.COM * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM *
87836SJohn.Forte@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM * and limitations under the License.
127836SJohn.Forte@Sun.COM *
137836SJohn.Forte@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM *
197836SJohn.Forte@Sun.COM * CDDL HEADER END
207836SJohn.Forte@Sun.COM */
217836SJohn.Forte@Sun.COM /*
229585STim.Szeto@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237836SJohn.Forte@Sun.COM * Use is subject to license terms.
247836SJohn.Forte@Sun.COM */
257836SJohn.Forte@Sun.COM
267836SJohn.Forte@Sun.COM #include <stdlib.h>
277836SJohn.Forte@Sun.COM #include <stdio.h>
287836SJohn.Forte@Sun.COM #include <sys/types.h>
297836SJohn.Forte@Sun.COM #include <unistd.h>
307836SJohn.Forte@Sun.COM #include <libintl.h>
317836SJohn.Forte@Sun.COM #include <errno.h>
327836SJohn.Forte@Sun.COM #include <string.h>
337836SJohn.Forte@Sun.COM #include <assert.h>
347836SJohn.Forte@Sun.COM #include <getopt.h>
357836SJohn.Forte@Sun.COM #include <cmdparse.h>
367836SJohn.Forte@Sun.COM
377836SJohn.Forte@Sun.COM
387836SJohn.Forte@Sun.COM /* Usage types */
397836SJohn.Forte@Sun.COM #define GENERAL_USAGE 1
407836SJohn.Forte@Sun.COM #define DETAIL_USAGE 2
417836SJohn.Forte@Sun.COM
427836SJohn.Forte@Sun.COM /* printable ascii character set len */
437836SJohn.Forte@Sun.COM #define MAXOPTIONS (uint_t)('~' - '!' + 1)
447836SJohn.Forte@Sun.COM
457836SJohn.Forte@Sun.COM /*
467836SJohn.Forte@Sun.COM * MAXOPTIONSTRING is the max length of the options string used in getopt and
477836SJohn.Forte@Sun.COM * will be the printable character set + ':' for each character,
487836SJohn.Forte@Sun.COM * providing for options with arguments. e.g. "t:Cs:hglr:"
497836SJohn.Forte@Sun.COM */
507836SJohn.Forte@Sun.COM #define MAXOPTIONSTRING MAXOPTIONS * 2
517836SJohn.Forte@Sun.COM
527836SJohn.Forte@Sun.COM /* standard command options table to support -?, -V */
537836SJohn.Forte@Sun.COM struct option standardCmdOptions[] = {
547836SJohn.Forte@Sun.COM {"help", no_argument, NULL, '?'},
557836SJohn.Forte@Sun.COM {"version", no_argument, NULL, 'V'},
567836SJohn.Forte@Sun.COM {NULL, 0, NULL, 0}
577836SJohn.Forte@Sun.COM };
587836SJohn.Forte@Sun.COM
597836SJohn.Forte@Sun.COM /* standard subcommand options table to support -? */
607836SJohn.Forte@Sun.COM struct option standardSubCmdOptions[] = {
617836SJohn.Forte@Sun.COM {"help", no_argument, NULL, '?'},
627836SJohn.Forte@Sun.COM {NULL, 0, NULL, 0}
637836SJohn.Forte@Sun.COM };
647836SJohn.Forte@Sun.COM
657836SJohn.Forte@Sun.COM /* forward declarations */
667836SJohn.Forte@Sun.COM static int getSubcommandProps(char *, subCommandProps_t **);
677836SJohn.Forte@Sun.COM static char *getExecBasename(char *);
687836SJohn.Forte@Sun.COM static void usage(uint_t);
697836SJohn.Forte@Sun.COM static void subUsage(uint_t, subCommandProps_t *);
707836SJohn.Forte@Sun.COM static char *getLongOption(int);
717836SJohn.Forte@Sun.COM static char *getOptionArgDesc(int);
727836SJohn.Forte@Sun.COM
737836SJohn.Forte@Sun.COM /* global data */
747836SJohn.Forte@Sun.COM static struct option *_longOptions;
757836SJohn.Forte@Sun.COM static subCommandProps_t *_subCommandProps;
767836SJohn.Forte@Sun.COM static optionTbl_t *_clientOptionTbl;
777836SJohn.Forte@Sun.COM static char *commandName;
787836SJohn.Forte@Sun.COM
797836SJohn.Forte@Sun.COM
807836SJohn.Forte@Sun.COM /*
817836SJohn.Forte@Sun.COM * input:
827836SJohn.Forte@Sun.COM * subCommand - subcommand value
837836SJohn.Forte@Sun.COM * output:
847836SJohn.Forte@Sun.COM * subCommandProps - pointer to subCommandProps_t structure allocated by caller
857836SJohn.Forte@Sun.COM *
867836SJohn.Forte@Sun.COM * On successful return, subCommandProps contains the properties for the value
877836SJohn.Forte@Sun.COM * in subCommand. On failure, the contents of subCommandProps is unspecified.
887836SJohn.Forte@Sun.COM *
897836SJohn.Forte@Sun.COM * Returns:
907836SJohn.Forte@Sun.COM * zero on success
917836SJohn.Forte@Sun.COM * non-zero on failure
927836SJohn.Forte@Sun.COM *
937836SJohn.Forte@Sun.COM */
947836SJohn.Forte@Sun.COM static int
getSubcommandProps(char * subCommand,subCommandProps_t ** subCommandProps)957836SJohn.Forte@Sun.COM getSubcommandProps(char *subCommand, subCommandProps_t **subCommandProps)
967836SJohn.Forte@Sun.COM {
977836SJohn.Forte@Sun.COM subCommandProps_t *sp;
987836SJohn.Forte@Sun.COM int len;
997836SJohn.Forte@Sun.COM
1007836SJohn.Forte@Sun.COM for (sp = _subCommandProps; sp->name; sp++) {
1017836SJohn.Forte@Sun.COM len = strlen(subCommand);
1027836SJohn.Forte@Sun.COM if (len == strlen(sp->name) &&
1037836SJohn.Forte@Sun.COM strncasecmp(subCommand, sp->name, len) == 0) {
1047836SJohn.Forte@Sun.COM *subCommandProps = sp;
1057836SJohn.Forte@Sun.COM return (0);
1067836SJohn.Forte@Sun.COM }
1077836SJohn.Forte@Sun.COM }
1087836SJohn.Forte@Sun.COM return (1);
1097836SJohn.Forte@Sun.COM }
1107836SJohn.Forte@Sun.COM
1117836SJohn.Forte@Sun.COM /*
1127836SJohn.Forte@Sun.COM * input:
1137836SJohn.Forte@Sun.COM * shortOption - short option character for which to return the
1147836SJohn.Forte@Sun.COM * associated long option string
1157836SJohn.Forte@Sun.COM *
1167836SJohn.Forte@Sun.COM * Returns:
1177836SJohn.Forte@Sun.COM * on success, long option name
1187836SJohn.Forte@Sun.COM * on failure, NULL
1197836SJohn.Forte@Sun.COM */
1207836SJohn.Forte@Sun.COM static char *
getLongOption(int shortOption)1217836SJohn.Forte@Sun.COM getLongOption(int shortOption)
1227836SJohn.Forte@Sun.COM {
1237836SJohn.Forte@Sun.COM struct option *op;
1247836SJohn.Forte@Sun.COM for (op = _longOptions; op->name; op++) {
1257836SJohn.Forte@Sun.COM if (shortOption == op->val) {
1267836SJohn.Forte@Sun.COM return (op->name);
1277836SJohn.Forte@Sun.COM }
1287836SJohn.Forte@Sun.COM }
1297836SJohn.Forte@Sun.COM return (NULL);
1307836SJohn.Forte@Sun.COM }
1317836SJohn.Forte@Sun.COM
1327836SJohn.Forte@Sun.COM /*
1337836SJohn.Forte@Sun.COM * input
1347836SJohn.Forte@Sun.COM * shortOption - short option character for which to return the
1357836SJohn.Forte@Sun.COM * option argument
1367836SJohn.Forte@Sun.COM * Returns:
1377836SJohn.Forte@Sun.COM * on success, argument string
1387836SJohn.Forte@Sun.COM * on failure, NULL
1397836SJohn.Forte@Sun.COM */
1407836SJohn.Forte@Sun.COM static char *
getOptionArgDesc(int shortOption)1417836SJohn.Forte@Sun.COM getOptionArgDesc(int shortOption)
1427836SJohn.Forte@Sun.COM {
1437836SJohn.Forte@Sun.COM optionTbl_t *op;
1447836SJohn.Forte@Sun.COM for (op = _clientOptionTbl; op->name; op++) {
1457836SJohn.Forte@Sun.COM if (op->val == shortOption &&
1467836SJohn.Forte@Sun.COM op->has_arg == required_argument) {
1477836SJohn.Forte@Sun.COM return (op->argDesc);
1487836SJohn.Forte@Sun.COM }
1497836SJohn.Forte@Sun.COM }
1507836SJohn.Forte@Sun.COM return (NULL);
1517836SJohn.Forte@Sun.COM }
1527836SJohn.Forte@Sun.COM
1537836SJohn.Forte@Sun.COM
1547836SJohn.Forte@Sun.COM /*
1557836SJohn.Forte@Sun.COM * Print usage for a subcommand.
1567836SJohn.Forte@Sun.COM *
1577836SJohn.Forte@Sun.COM * input:
1587836SJohn.Forte@Sun.COM * usage type - GENERAL_USAGE, DETAIL_USAGE
1597836SJohn.Forte@Sun.COM * subcommand - pointer to subCommandProps_t structure
1607836SJohn.Forte@Sun.COM *
1617836SJohn.Forte@Sun.COM * Returns:
1627836SJohn.Forte@Sun.COM * none
1637836SJohn.Forte@Sun.COM *
1647836SJohn.Forte@Sun.COM */
1657836SJohn.Forte@Sun.COM static void
subUsage(uint_t usageType,subCommandProps_t * subcommand)1667836SJohn.Forte@Sun.COM subUsage(uint_t usageType, subCommandProps_t *subcommand)
1677836SJohn.Forte@Sun.COM {
1687836SJohn.Forte@Sun.COM int i;
1697836SJohn.Forte@Sun.COM char *optionArgDesc;
1707836SJohn.Forte@Sun.COM char *longOpt;
1717836SJohn.Forte@Sun.COM
1727836SJohn.Forte@Sun.COM if (usageType == GENERAL_USAGE) {
1737836SJohn.Forte@Sun.COM (void) printf("%s:\t%s %s [", gettext("Usage"), commandName,
1747836SJohn.Forte@Sun.COM subcommand->name);
1757836SJohn.Forte@Sun.COM for (i = 0; standardSubCmdOptions[i].name; i++) {
1767836SJohn.Forte@Sun.COM (void) printf("-%c", standardSubCmdOptions[i].val);
1777836SJohn.Forte@Sun.COM if (standardSubCmdOptions[i+1].name)
1787836SJohn.Forte@Sun.COM (void) printf(",");
1797836SJohn.Forte@Sun.COM }
1807836SJohn.Forte@Sun.COM (void) fprintf(stdout, "]\n");
1817836SJohn.Forte@Sun.COM return;
1827836SJohn.Forte@Sun.COM }
1837836SJohn.Forte@Sun.COM
1847836SJohn.Forte@Sun.COM /* print subcommand usage */
1857836SJohn.Forte@Sun.COM (void) printf("\n%s:\t%s %s ", gettext("Usage"), commandName,
1867836SJohn.Forte@Sun.COM subcommand->name);
1877836SJohn.Forte@Sun.COM
1887836SJohn.Forte@Sun.COM /* print options if applicable */
1897836SJohn.Forte@Sun.COM if (subcommand->optionString != NULL) {
1907836SJohn.Forte@Sun.COM if (subcommand->required) {
1917836SJohn.Forte@Sun.COM (void) printf("%s", gettext("<"));
1927836SJohn.Forte@Sun.COM } else {
1937836SJohn.Forte@Sun.COM (void) printf("%s", gettext("["));
1947836SJohn.Forte@Sun.COM }
1957836SJohn.Forte@Sun.COM (void) printf("%s", gettext("OPTIONS"));
1967836SJohn.Forte@Sun.COM if (subcommand->required) {
1977836SJohn.Forte@Sun.COM (void) printf("%s ", gettext(">"));
1987836SJohn.Forte@Sun.COM } else {
1997836SJohn.Forte@Sun.COM (void) printf("%s ", gettext("]"));
2007836SJohn.Forte@Sun.COM }
2017836SJohn.Forte@Sun.COM }
2027836SJohn.Forte@Sun.COM
2037836SJohn.Forte@Sun.COM /* print operand requirements */
2047836SJohn.Forte@Sun.COM if (!(subcommand->operand & OPERAND_NONE) &&
2057836SJohn.Forte@Sun.COM !(subcommand->operand & OPERAND_MANDATORY)) {
2067836SJohn.Forte@Sun.COM (void) printf(gettext("["));
2077836SJohn.Forte@Sun.COM }
2087836SJohn.Forte@Sun.COM
2097836SJohn.Forte@Sun.COM if (subcommand->operand & OPERAND_MANDATORY) {
2107836SJohn.Forte@Sun.COM (void) printf(gettext("<"));
2117836SJohn.Forte@Sun.COM }
2127836SJohn.Forte@Sun.COM
2137836SJohn.Forte@Sun.COM if (!(subcommand->operand & OPERAND_NONE)) {
2147836SJohn.Forte@Sun.COM assert(subcommand->operandDefinition);
2157836SJohn.Forte@Sun.COM (void) printf("%s", subcommand->operandDefinition);
2167836SJohn.Forte@Sun.COM }
2177836SJohn.Forte@Sun.COM
2187836SJohn.Forte@Sun.COM if (subcommand->operand & OPERAND_MULTIPLE) {
2197836SJohn.Forte@Sun.COM (void) printf(gettext(" ..."));
2207836SJohn.Forte@Sun.COM }
2217836SJohn.Forte@Sun.COM
2227836SJohn.Forte@Sun.COM if (subcommand->operand & OPERAND_MANDATORY) {
2237836SJohn.Forte@Sun.COM (void) printf(gettext(">"));
2247836SJohn.Forte@Sun.COM }
2257836SJohn.Forte@Sun.COM
2267836SJohn.Forte@Sun.COM if (!(subcommand->operand & OPERAND_NONE) &&
2277836SJohn.Forte@Sun.COM !(subcommand->operand & OPERAND_MANDATORY)) {
2287836SJohn.Forte@Sun.COM (void) printf(gettext("]"));
2297836SJohn.Forte@Sun.COM }
2307836SJohn.Forte@Sun.COM
2317836SJohn.Forte@Sun.COM /* print options for subcommand */
2327836SJohn.Forte@Sun.COM if (subcommand->optionString != NULL) {
2337836SJohn.Forte@Sun.COM (void) printf("\n\t%s:", gettext("OPTIONS"));
2347836SJohn.Forte@Sun.COM for (i = 0; i < strlen(subcommand->optionString); i++) {
2357836SJohn.Forte@Sun.COM assert((longOpt = getLongOption(
2367836SJohn.Forte@Sun.COM subcommand->optionString[i])) != NULL);
2377836SJohn.Forte@Sun.COM (void) printf("\n\t\t-%c, --%s ",
2387836SJohn.Forte@Sun.COM subcommand->optionString[i],
2397836SJohn.Forte@Sun.COM longOpt);
2407836SJohn.Forte@Sun.COM optionArgDesc =
2417836SJohn.Forte@Sun.COM getOptionArgDesc(subcommand->optionString[i]);
2427836SJohn.Forte@Sun.COM if (optionArgDesc != NULL) {
2437836SJohn.Forte@Sun.COM (void) printf("<%s>", optionArgDesc);
2447836SJohn.Forte@Sun.COM }
2457836SJohn.Forte@Sun.COM if (subcommand->exclusive &&
2467836SJohn.Forte@Sun.COM strchr(subcommand->exclusive,
2477836SJohn.Forte@Sun.COM subcommand->optionString[i])) {
2487836SJohn.Forte@Sun.COM (void) printf(" (%s)", gettext("exclusive"));
2497836SJohn.Forte@Sun.COM }
2507836SJohn.Forte@Sun.COM }
2517836SJohn.Forte@Sun.COM }
2527836SJohn.Forte@Sun.COM (void) fprintf(stdout, "\n");
2539585STim.Szeto@Sun.COM if (subcommand->helpText) {
2549585STim.Szeto@Sun.COM (void) printf("%s\n", subcommand->helpText);
2559585STim.Szeto@Sun.COM }
2567836SJohn.Forte@Sun.COM }
2577836SJohn.Forte@Sun.COM
2587836SJohn.Forte@Sun.COM /*
2597836SJohn.Forte@Sun.COM * input:
2607836SJohn.Forte@Sun.COM * type of usage statement to print
2617836SJohn.Forte@Sun.COM *
2627836SJohn.Forte@Sun.COM * Returns:
2637836SJohn.Forte@Sun.COM * return value of subUsage
2647836SJohn.Forte@Sun.COM */
2657836SJohn.Forte@Sun.COM static void
usage(uint_t usageType)2667836SJohn.Forte@Sun.COM usage(uint_t usageType)
2677836SJohn.Forte@Sun.COM {
2687836SJohn.Forte@Sun.COM int i;
2697836SJohn.Forte@Sun.COM subCommandProps_t *sp;
2707836SJohn.Forte@Sun.COM
2717836SJohn.Forte@Sun.COM /* print general command usage */
2727836SJohn.Forte@Sun.COM (void) printf("%s:\t%s ", gettext("Usage"), commandName);
2737836SJohn.Forte@Sun.COM
2747836SJohn.Forte@Sun.COM for (i = 0; standardCmdOptions[i].name; i++) {
2757836SJohn.Forte@Sun.COM (void) printf("-%c", standardCmdOptions[i].val);
2767836SJohn.Forte@Sun.COM if (standardCmdOptions[i+1].name)
2777836SJohn.Forte@Sun.COM (void) printf(",");
2787836SJohn.Forte@Sun.COM }
2797836SJohn.Forte@Sun.COM
2807836SJohn.Forte@Sun.COM if (usageType == GENERAL_USAGE) {
2817836SJohn.Forte@Sun.COM for (i = 0; standardSubCmdOptions[i].name; i++) {
2827836SJohn.Forte@Sun.COM (void) printf(",--%s", standardSubCmdOptions[i].name);
2837836SJohn.Forte@Sun.COM if (standardSubCmdOptions[i+1].name)
2847836SJohn.Forte@Sun.COM (void) printf(",");
2857836SJohn.Forte@Sun.COM }
2867836SJohn.Forte@Sun.COM }
2877836SJohn.Forte@Sun.COM
2887836SJohn.Forte@Sun.COM (void) fprintf(stdout, "\n");
2897836SJohn.Forte@Sun.COM
2907836SJohn.Forte@Sun.COM
2917836SJohn.Forte@Sun.COM /* print all subcommand usage */
2927836SJohn.Forte@Sun.COM for (sp = _subCommandProps; sp->name; sp++) {
2937836SJohn.Forte@Sun.COM subUsage(usageType, sp);
2947836SJohn.Forte@Sun.COM }
2957836SJohn.Forte@Sun.COM }
2967836SJohn.Forte@Sun.COM
2977836SJohn.Forte@Sun.COM /*
2987836SJohn.Forte@Sun.COM * input:
2997836SJohn.Forte@Sun.COM * execFullName - exec name of program (argv[0])
3007836SJohn.Forte@Sun.COM *
3017836SJohn.Forte@Sun.COM * Returns:
3027836SJohn.Forte@Sun.COM * command name portion of execFullName
3037836SJohn.Forte@Sun.COM */
3047836SJohn.Forte@Sun.COM static char *
getExecBasename(char * execFullname)3057836SJohn.Forte@Sun.COM getExecBasename(char *execFullname)
3067836SJohn.Forte@Sun.COM {
3077836SJohn.Forte@Sun.COM char *lastSlash, *execBasename;
3087836SJohn.Forte@Sun.COM
3097836SJohn.Forte@Sun.COM /* guard against '/' at end of command invocation */
3107836SJohn.Forte@Sun.COM for (;;) {
3117836SJohn.Forte@Sun.COM lastSlash = strrchr(execFullname, '/');
3127836SJohn.Forte@Sun.COM if (lastSlash == NULL) {
3137836SJohn.Forte@Sun.COM execBasename = execFullname;
3147836SJohn.Forte@Sun.COM break;
3157836SJohn.Forte@Sun.COM } else {
3167836SJohn.Forte@Sun.COM execBasename = lastSlash + 1;
3177836SJohn.Forte@Sun.COM if (*execBasename == '\0') {
3187836SJohn.Forte@Sun.COM *lastSlash = '\0';
3197836SJohn.Forte@Sun.COM continue;
3207836SJohn.Forte@Sun.COM }
3217836SJohn.Forte@Sun.COM break;
3227836SJohn.Forte@Sun.COM }
3237836SJohn.Forte@Sun.COM }
3247836SJohn.Forte@Sun.COM return (execBasename);
3257836SJohn.Forte@Sun.COM }
3267836SJohn.Forte@Sun.COM
3277836SJohn.Forte@Sun.COM /*
3287836SJohn.Forte@Sun.COM * cmdParse is a parser that checks syntax of the input command against
3297836SJohn.Forte@Sun.COM * various rules tables.
3307836SJohn.Forte@Sun.COM *
3317836SJohn.Forte@Sun.COM * It provides usage feedback based upon the passed rules tables by calling
3327836SJohn.Forte@Sun.COM * two usage functions, usage, subUsage
3337836SJohn.Forte@Sun.COM *
3347836SJohn.Forte@Sun.COM * When syntax is successfully validated, the associated function is called
3357836SJohn.Forte@Sun.COM * using the subcommands table functions.
3367836SJohn.Forte@Sun.COM *
3377836SJohn.Forte@Sun.COM * Syntax is as follows:
3387836SJohn.Forte@Sun.COM * command subcommand [<options>] [<operand>]
3397836SJohn.Forte@Sun.COM *
3407836SJohn.Forte@Sun.COM * There are two standard short and long options assumed:
3417836SJohn.Forte@Sun.COM * -?, --help Provides usage on a command or subcommand
3427836SJohn.Forte@Sun.COM * and stops further processing of the arguments
3437836SJohn.Forte@Sun.COM *
3447836SJohn.Forte@Sun.COM * -V, --version Provides version information on the command
3457836SJohn.Forte@Sun.COM * and stops further processing of the arguments
3467836SJohn.Forte@Sun.COM *
3477836SJohn.Forte@Sun.COM * These options are loaded by this function.
3487836SJohn.Forte@Sun.COM *
3497836SJohn.Forte@Sun.COM * input:
3507836SJohn.Forte@Sun.COM * argc, argv from main
3517836SJohn.Forte@Sun.COM * syntax rules tables (synTables_t structure)
3527836SJohn.Forte@Sun.COM * callArgs - void * passed by caller to be passed to subcommand function
3537836SJohn.Forte@Sun.COM *
3547836SJohn.Forte@Sun.COM * output:
3557836SJohn.Forte@Sun.COM * funcRet - pointer to int that holds subcommand function return value
3567836SJohn.Forte@Sun.COM *
3577836SJohn.Forte@Sun.COM * Returns:
3587836SJohn.Forte@Sun.COM *
3597836SJohn.Forte@Sun.COM * zero on successful syntax parse and function call
3607836SJohn.Forte@Sun.COM *
3617836SJohn.Forte@Sun.COM * 1 on unsuccessful syntax parse (no function has been called)
3627836SJohn.Forte@Sun.COM * This could be due to a version or help call or simply a
3637836SJohn.Forte@Sun.COM * general usage call.
3647836SJohn.Forte@Sun.COM *
3657836SJohn.Forte@Sun.COM * -1 check errno, call failed
3667836SJohn.Forte@Sun.COM *
3677836SJohn.Forte@Sun.COM * This module is not MT-safe.
3687836SJohn.Forte@Sun.COM *
3697836SJohn.Forte@Sun.COM */
3707836SJohn.Forte@Sun.COM int
cmdParse(int argc,char * argv[],synTables_t synTable,void * callArgs,int * funcRet)3717836SJohn.Forte@Sun.COM cmdParse(int argc, char *argv[], synTables_t synTable, void *callArgs,
3727836SJohn.Forte@Sun.COM int *funcRet)
3737836SJohn.Forte@Sun.COM {
3747836SJohn.Forte@Sun.COM int getoptargc;
3757836SJohn.Forte@Sun.COM char **getoptargv;
3767836SJohn.Forte@Sun.COM int opt;
3777836SJohn.Forte@Sun.COM int operInd;
3787836SJohn.Forte@Sun.COM int i, j;
3797836SJohn.Forte@Sun.COM int len;
3807836SJohn.Forte@Sun.COM int requiredOptionCnt = 0, requiredOptionEntered = 0;
3817836SJohn.Forte@Sun.COM char *availOptions;
3827836SJohn.Forte@Sun.COM char *versionString;
3837836SJohn.Forte@Sun.COM char optionStringAll[MAXOPTIONSTRING + 1];
3847836SJohn.Forte@Sun.COM subCommandProps_t *subcommand;
3857836SJohn.Forte@Sun.COM cmdOptions_t cmdOptions[MAXOPTIONS + 1];
3867836SJohn.Forte@Sun.COM optionTbl_t *optionTbl;
3877836SJohn.Forte@Sun.COM struct option *lp;
3887836SJohn.Forte@Sun.COM struct option intLongOpt[MAXOPTIONS + 1];
3897836SJohn.Forte@Sun.COM
3907836SJohn.Forte@Sun.COM /*
3917836SJohn.Forte@Sun.COM * Check for NULLs on mandatory input arguments
3927836SJohn.Forte@Sun.COM *
3937836SJohn.Forte@Sun.COM * Note: longOptionTbl can be NULL in the case
3947836SJohn.Forte@Sun.COM * where there is no caller defined options
3957836SJohn.Forte@Sun.COM *
3967836SJohn.Forte@Sun.COM */
3977836SJohn.Forte@Sun.COM assert(synTable.versionString);
3987836SJohn.Forte@Sun.COM assert(synTable.subCommandPropsTbl);
3997836SJohn.Forte@Sun.COM assert(funcRet);
4007836SJohn.Forte@Sun.COM
4017836SJohn.Forte@Sun.COM versionString = synTable.versionString;
4027836SJohn.Forte@Sun.COM
4037836SJohn.Forte@Sun.COM /* set global command name */
4047836SJohn.Forte@Sun.COM commandName = getExecBasename(argv[0]);
4057836SJohn.Forte@Sun.COM
4067836SJohn.Forte@Sun.COM /* Set unbuffered output */
4077836SJohn.Forte@Sun.COM setbuf(stdout, NULL);
4087836SJohn.Forte@Sun.COM
4097836SJohn.Forte@Sun.COM /* load globals */
4107836SJohn.Forte@Sun.COM _subCommandProps = synTable.subCommandPropsTbl;
4117836SJohn.Forte@Sun.COM _clientOptionTbl = synTable.longOptionTbl;
4127836SJohn.Forte@Sun.COM
4137836SJohn.Forte@Sun.COM /* There must be at least two arguments */
4147836SJohn.Forte@Sun.COM if (argc < 2) {
4157836SJohn.Forte@Sun.COM usage(GENERAL_USAGE);
4167836SJohn.Forte@Sun.COM return (1);
4177836SJohn.Forte@Sun.COM }
4187836SJohn.Forte@Sun.COM
4197836SJohn.Forte@Sun.COM (void) memset(&intLongOpt[0], 0, sizeof (intLongOpt));
4207836SJohn.Forte@Sun.COM
4217836SJohn.Forte@Sun.COM /*
4227836SJohn.Forte@Sun.COM * load standard subcommand options to internal long options table
4237836SJohn.Forte@Sun.COM * Two separate getopt_long(3C) tables are used.
4247836SJohn.Forte@Sun.COM */
4257836SJohn.Forte@Sun.COM for (i = 0; standardSubCmdOptions[i].name; i++) {
4267836SJohn.Forte@Sun.COM intLongOpt[i].name = standardSubCmdOptions[i].name;
4277836SJohn.Forte@Sun.COM intLongOpt[i].has_arg = standardSubCmdOptions[i].has_arg;
4287836SJohn.Forte@Sun.COM intLongOpt[i].flag = standardSubCmdOptions[i].flag;
4297836SJohn.Forte@Sun.COM intLongOpt[i].val = standardSubCmdOptions[i].val;
4307836SJohn.Forte@Sun.COM }
4317836SJohn.Forte@Sun.COM
4327836SJohn.Forte@Sun.COM /*
4337836SJohn.Forte@Sun.COM * copy caller's long options into internal long options table
4347836SJohn.Forte@Sun.COM * We do this for two reasons:
4357836SJohn.Forte@Sun.COM * 1) We need to use the getopt_long option structure internally
4367836SJohn.Forte@Sun.COM * 2) We need to prepend the table with the standard option
4377836SJohn.Forte@Sun.COM * for all subcommands (currently -?)
4387836SJohn.Forte@Sun.COM */
4397836SJohn.Forte@Sun.COM for (optionTbl = synTable.longOptionTbl;
4407836SJohn.Forte@Sun.COM optionTbl && optionTbl->name; optionTbl++, i++) {
4417836SJohn.Forte@Sun.COM if (i > MAXOPTIONS - 1) {
4427836SJohn.Forte@Sun.COM /* option table too long */
4437836SJohn.Forte@Sun.COM assert(0);
4447836SJohn.Forte@Sun.COM }
4457836SJohn.Forte@Sun.COM intLongOpt[i].name = optionTbl->name;
4467836SJohn.Forte@Sun.COM intLongOpt[i].has_arg = optionTbl->has_arg;
4477836SJohn.Forte@Sun.COM intLongOpt[i].flag = NULL;
4487836SJohn.Forte@Sun.COM intLongOpt[i].val = optionTbl->val;
4497836SJohn.Forte@Sun.COM }
4507836SJohn.Forte@Sun.COM
4517836SJohn.Forte@Sun.COM /* set option table global */
4527836SJohn.Forte@Sun.COM _longOptions = &intLongOpt[0];
4537836SJohn.Forte@Sun.COM
4547836SJohn.Forte@Sun.COM
4557836SJohn.Forte@Sun.COM /*
4567836SJohn.Forte@Sun.COM * Check for help/version request immediately following command
4577836SJohn.Forte@Sun.COM * '+' in option string ensures POSIX compliance in getopt_long()
4587836SJohn.Forte@Sun.COM * which means that processing will stop at first non-option
4597836SJohn.Forte@Sun.COM * argument.
4607836SJohn.Forte@Sun.COM */
4617836SJohn.Forte@Sun.COM while ((opt = getopt_long(argc, argv, "+?V", standardCmdOptions,
4627836SJohn.Forte@Sun.COM NULL)) != EOF) {
4637836SJohn.Forte@Sun.COM switch (opt) {
4647836SJohn.Forte@Sun.COM case '?':
4657836SJohn.Forte@Sun.COM /*
4667836SJohn.Forte@Sun.COM * getopt can return a '?' when no
4677836SJohn.Forte@Sun.COM * option letters match string. Check for
4687836SJohn.Forte@Sun.COM * the 'real' '?' in optopt.
4697836SJohn.Forte@Sun.COM */
4707836SJohn.Forte@Sun.COM if (optopt == '?') {
4717836SJohn.Forte@Sun.COM usage(DETAIL_USAGE);
4727836SJohn.Forte@Sun.COM exit(0);
4737836SJohn.Forte@Sun.COM } else {
4747836SJohn.Forte@Sun.COM usage(GENERAL_USAGE);
4757836SJohn.Forte@Sun.COM return (1);
4767836SJohn.Forte@Sun.COM }
4777836SJohn.Forte@Sun.COM break;
4787836SJohn.Forte@Sun.COM case 'V':
4797836SJohn.Forte@Sun.COM (void) fprintf(stdout, "%s: %s %s\n",
4807836SJohn.Forte@Sun.COM commandName, gettext("Version"),
4817836SJohn.Forte@Sun.COM versionString);
4827836SJohn.Forte@Sun.COM exit(0);
4837836SJohn.Forte@Sun.COM break;
4847836SJohn.Forte@Sun.COM default:
4857836SJohn.Forte@Sun.COM break;
4867836SJohn.Forte@Sun.COM }
4877836SJohn.Forte@Sun.COM }
4887836SJohn.Forte@Sun.COM
4897836SJohn.Forte@Sun.COM /*
4907836SJohn.Forte@Sun.COM * subcommand is always in the second argument. If there is no
4917836SJohn.Forte@Sun.COM * recognized subcommand in the second argument, print error,
4927836SJohn.Forte@Sun.COM * general usage and then return.
4937836SJohn.Forte@Sun.COM */
4947836SJohn.Forte@Sun.COM if (getSubcommandProps(argv[1], &subcommand) != 0) {
4957836SJohn.Forte@Sun.COM (void) printf("%s: %s\n", commandName,
4967836SJohn.Forte@Sun.COM gettext("invalid subcommand"));
4977836SJohn.Forte@Sun.COM usage(GENERAL_USAGE);
4987836SJohn.Forte@Sun.COM return (1);
4997836SJohn.Forte@Sun.COM }
5007836SJohn.Forte@Sun.COM
5017836SJohn.Forte@Sun.COM getoptargv = argv;
5027836SJohn.Forte@Sun.COM getoptargv++;
5037836SJohn.Forte@Sun.COM getoptargc = argc;
5047836SJohn.Forte@Sun.COM getoptargc -= 1;
5057836SJohn.Forte@Sun.COM
5067836SJohn.Forte@Sun.COM (void) memset(optionStringAll, 0, sizeof (optionStringAll));
5077836SJohn.Forte@Sun.COM (void) memset(&cmdOptions[0], 0, sizeof (cmdOptions));
5087836SJohn.Forte@Sun.COM
5097836SJohn.Forte@Sun.COM j = 0;
5107836SJohn.Forte@Sun.COM /*
5117836SJohn.Forte@Sun.COM * Build optionStringAll from long options table
5127836SJohn.Forte@Sun.COM */
5137836SJohn.Forte@Sun.COM for (lp = _longOptions; lp->name; lp++, j++) {
5147836SJohn.Forte@Sun.COM /* sanity check on string length */
5157836SJohn.Forte@Sun.COM if (j + 1 >= sizeof (optionStringAll)) {
5167836SJohn.Forte@Sun.COM /* option table too long */
5177836SJohn.Forte@Sun.COM assert(0);
5187836SJohn.Forte@Sun.COM }
5197836SJohn.Forte@Sun.COM optionStringAll[j] = lp->val;
5207836SJohn.Forte@Sun.COM if (lp->has_arg == required_argument) {
5217836SJohn.Forte@Sun.COM optionStringAll[++j] = ':';
5227836SJohn.Forte@Sun.COM }
5237836SJohn.Forte@Sun.COM }
5247836SJohn.Forte@Sun.COM
5257836SJohn.Forte@Sun.COM i = 0;
5267836SJohn.Forte@Sun.COM /*
5277836SJohn.Forte@Sun.COM * Run getopt for all arguments against all possible options
5287836SJohn.Forte@Sun.COM * Store all options/option arguments in an array for retrieval
5297836SJohn.Forte@Sun.COM * later.
5307836SJohn.Forte@Sun.COM *
5317836SJohn.Forte@Sun.COM * Once all options are retrieved, a validity check against
5327836SJohn.Forte@Sun.COM * subcommand table is performed.
5337836SJohn.Forte@Sun.COM */
5347836SJohn.Forte@Sun.COM while ((opt = getopt_long(getoptargc, getoptargv, optionStringAll,
5357836SJohn.Forte@Sun.COM _longOptions, NULL)) != EOF) {
5367836SJohn.Forte@Sun.COM switch (opt) {
5377836SJohn.Forte@Sun.COM case '?':
5387836SJohn.Forte@Sun.COM subUsage(DETAIL_USAGE, subcommand);
539*10652SHyon.Kim@Sun.COM /*
540*10652SHyon.Kim@Sun.COM * getopt can return a '?' when no
541*10652SHyon.Kim@Sun.COM * option letters match string. Check for
542*10652SHyon.Kim@Sun.COM * the 'real' '?' in optopt.
543*10652SHyon.Kim@Sun.COM */
544*10652SHyon.Kim@Sun.COM if (optopt == '?') {
545*10652SHyon.Kim@Sun.COM exit(0);
546*10652SHyon.Kim@Sun.COM } else {
547*10652SHyon.Kim@Sun.COM exit(1);
548*10652SHyon.Kim@Sun.COM }
5497836SJohn.Forte@Sun.COM default:
5507836SJohn.Forte@Sun.COM cmdOptions[i].optval = opt;
5517836SJohn.Forte@Sun.COM if (optarg) {
5527836SJohn.Forte@Sun.COM len = strlen(optarg);
5537836SJohn.Forte@Sun.COM if (len > sizeof (cmdOptions[i].optarg)
5547836SJohn.Forte@Sun.COM - 1) {
5557836SJohn.Forte@Sun.COM (void) printf("%s: %s\n",
5567836SJohn.Forte@Sun.COM commandName,
5577836SJohn.Forte@Sun.COM gettext("option too long"));
5587836SJohn.Forte@Sun.COM errno = EINVAL;
5597836SJohn.Forte@Sun.COM return (-1);
5607836SJohn.Forte@Sun.COM }
5617836SJohn.Forte@Sun.COM (void) strncpy(cmdOptions[i].optarg,
5627836SJohn.Forte@Sun.COM optarg, len);
5637836SJohn.Forte@Sun.COM }
5647836SJohn.Forte@Sun.COM i++;
5657836SJohn.Forte@Sun.COM break;
5667836SJohn.Forte@Sun.COM }
5677836SJohn.Forte@Sun.COM }
5687836SJohn.Forte@Sun.COM
5697836SJohn.Forte@Sun.COM /*
5707836SJohn.Forte@Sun.COM * increment past last option
5717836SJohn.Forte@Sun.COM */
5727836SJohn.Forte@Sun.COM operInd = optind + 1;
5737836SJohn.Forte@Sun.COM
5747836SJohn.Forte@Sun.COM /*
5757836SJohn.Forte@Sun.COM * Check validity of given options, if any were given
5767836SJohn.Forte@Sun.COM */
5777836SJohn.Forte@Sun.COM
5787836SJohn.Forte@Sun.COM /* get option string for this subcommand */
5797836SJohn.Forte@Sun.COM availOptions = subcommand->optionString;
5807836SJohn.Forte@Sun.COM
5817836SJohn.Forte@Sun.COM /* Get count of required options */
5827836SJohn.Forte@Sun.COM if (subcommand->required) {
5837836SJohn.Forte@Sun.COM requiredOptionCnt = strlen(subcommand->required);
5847836SJohn.Forte@Sun.COM }
5857836SJohn.Forte@Sun.COM
5867836SJohn.Forte@Sun.COM if (cmdOptions[0].optval != 0) { /* options were input */
5877836SJohn.Forte@Sun.COM if (availOptions == NULL) { /* no options permitted */
5887836SJohn.Forte@Sun.COM (void) printf("%s: %s\n", commandName,
5897836SJohn.Forte@Sun.COM gettext("no options permitted"));
5907836SJohn.Forte@Sun.COM subUsage(DETAIL_USAGE, subcommand);
5917836SJohn.Forte@Sun.COM return (1);
5927836SJohn.Forte@Sun.COM }
5937836SJohn.Forte@Sun.COM for (i = 0; cmdOptions[i].optval; i++) {
5947836SJohn.Forte@Sun.COM /* is the option in the available option string? */
5957836SJohn.Forte@Sun.COM if (!(strchr(availOptions, cmdOptions[i].optval))) {
5967836SJohn.Forte@Sun.COM (void) printf("%s: '-%c': %s\n", commandName,
5977836SJohn.Forte@Sun.COM cmdOptions[i].optval,
5987836SJohn.Forte@Sun.COM gettext("invalid option"));
5997836SJohn.Forte@Sun.COM subUsage(DETAIL_USAGE, subcommand);
6007836SJohn.Forte@Sun.COM return (1);
6017836SJohn.Forte@Sun.COM /* increment required options entered */
6027836SJohn.Forte@Sun.COM } else if (subcommand->required &&
6037836SJohn.Forte@Sun.COM (strchr(subcommand->required,
6047836SJohn.Forte@Sun.COM cmdOptions[i].optval))) {
6057836SJohn.Forte@Sun.COM requiredOptionEntered++;
6067836SJohn.Forte@Sun.COM /* Check for exclusive options */
6077836SJohn.Forte@Sun.COM } else if (cmdOptions[1].optval != 0 &&
6087836SJohn.Forte@Sun.COM subcommand->exclusive &&
6097836SJohn.Forte@Sun.COM strchr(subcommand->exclusive,
6107836SJohn.Forte@Sun.COM cmdOptions[i].optval)) {
6117836SJohn.Forte@Sun.COM (void) printf("%s: '-%c': %s\n",
6127836SJohn.Forte@Sun.COM commandName, cmdOptions[i].optval,
6137836SJohn.Forte@Sun.COM gettext("is an exclusive option"));
6147836SJohn.Forte@Sun.COM subUsage(DETAIL_USAGE, subcommand);
6157836SJohn.Forte@Sun.COM return (1);
6167836SJohn.Forte@Sun.COM }
6177836SJohn.Forte@Sun.COM }
6187836SJohn.Forte@Sun.COM } else { /* no options were input */
6197836SJohn.Forte@Sun.COM if (availOptions != NULL && subcommand->required) {
6207836SJohn.Forte@Sun.COM (void) printf("%s: %s\n", commandName,
6217836SJohn.Forte@Sun.COM gettext("at least one option required"));
6227836SJohn.Forte@Sun.COM subUsage(DETAIL_USAGE, subcommand);
6237836SJohn.Forte@Sun.COM return (1);
6247836SJohn.Forte@Sun.COM }
6257836SJohn.Forte@Sun.COM }
6267836SJohn.Forte@Sun.COM
6277836SJohn.Forte@Sun.COM /* Were all required options entered? */
6287836SJohn.Forte@Sun.COM if (requiredOptionEntered != requiredOptionCnt) {
6297836SJohn.Forte@Sun.COM (void) printf("%s: %s: %s\n", commandName,
6307836SJohn.Forte@Sun.COM gettext("Following option(s) required"),
6317836SJohn.Forte@Sun.COM subcommand->required);
6327836SJohn.Forte@Sun.COM subUsage(DETAIL_USAGE, subcommand);
6337836SJohn.Forte@Sun.COM return (1);
6347836SJohn.Forte@Sun.COM }
6357836SJohn.Forte@Sun.COM
6367836SJohn.Forte@Sun.COM
6377836SJohn.Forte@Sun.COM /*
6387836SJohn.Forte@Sun.COM * If there are no operands,
6397836SJohn.Forte@Sun.COM * check to see if this is okay
6407836SJohn.Forte@Sun.COM */
6417836SJohn.Forte@Sun.COM if ((operInd == argc) &&
6427836SJohn.Forte@Sun.COM (subcommand->operand & OPERAND_MANDATORY)) {
6437836SJohn.Forte@Sun.COM (void) printf("%s: %s %s\n", commandName, subcommand->name,
6447836SJohn.Forte@Sun.COM gettext("requires an operand"));
6457836SJohn.Forte@Sun.COM subUsage(DETAIL_USAGE, subcommand);
6467836SJohn.Forte@Sun.COM return (1);
6477836SJohn.Forte@Sun.COM }
6487836SJohn.Forte@Sun.COM
6497836SJohn.Forte@Sun.COM /*
6507836SJohn.Forte@Sun.COM * If there are more operands,
6517836SJohn.Forte@Sun.COM * check to see if this is okay
6527836SJohn.Forte@Sun.COM */
6537836SJohn.Forte@Sun.COM if ((argc > operInd) &&
6547836SJohn.Forte@Sun.COM (subcommand->operand & OPERAND_NONE)) {
6557836SJohn.Forte@Sun.COM (void) fprintf(stderr, "%s: %s %s\n", commandName,
6567836SJohn.Forte@Sun.COM subcommand->name, gettext("takes no operands"));
6577836SJohn.Forte@Sun.COM subUsage(DETAIL_USAGE, subcommand);
6587836SJohn.Forte@Sun.COM return (1);
6597836SJohn.Forte@Sun.COM }
6607836SJohn.Forte@Sun.COM
6617836SJohn.Forte@Sun.COM /*
6627836SJohn.Forte@Sun.COM * If there is more than one more operand,
6637836SJohn.Forte@Sun.COM * check to see if this is okay
6647836SJohn.Forte@Sun.COM */
6657836SJohn.Forte@Sun.COM if ((argc > operInd) && ((argc - operInd) != 1) &&
6667836SJohn.Forte@Sun.COM (subcommand->operand & OPERAND_SINGLE)) {
6677836SJohn.Forte@Sun.COM (void) printf("%s: %s %s\n", commandName,
6687836SJohn.Forte@Sun.COM subcommand->name, gettext("accepts only a single operand"));
6697836SJohn.Forte@Sun.COM subUsage(DETAIL_USAGE, subcommand);
6707836SJohn.Forte@Sun.COM return (1);
6717836SJohn.Forte@Sun.COM }
6727836SJohn.Forte@Sun.COM
6737836SJohn.Forte@Sun.COM /* Finished syntax checks */
6747836SJohn.Forte@Sun.COM
6757836SJohn.Forte@Sun.COM
6767836SJohn.Forte@Sun.COM /* Call appropriate function */
6777836SJohn.Forte@Sun.COM *funcRet = subcommand->handler(argc - operInd, &argv[operInd],
6787836SJohn.Forte@Sun.COM &cmdOptions[0], callArgs);
6797836SJohn.Forte@Sun.COM
6807836SJohn.Forte@Sun.COM return (0);
6817836SJohn.Forte@Sun.COM }
682