1*fcf3ce44SJohn Forte /* 2*fcf3ce44SJohn Forte * CDDL HEADER START 3*fcf3ce44SJohn Forte * 4*fcf3ce44SJohn Forte * The contents of this file are subject to the terms of the 5*fcf3ce44SJohn Forte * Common Development and Distribution License (the "License"). 6*fcf3ce44SJohn Forte * You may not use this file except in compliance with the License. 7*fcf3ce44SJohn Forte * 8*fcf3ce44SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*fcf3ce44SJohn Forte * or http://www.opensolaris.org/os/licensing. 10*fcf3ce44SJohn Forte * See the License for the specific language governing permissions 11*fcf3ce44SJohn Forte * and limitations under the License. 12*fcf3ce44SJohn Forte * 13*fcf3ce44SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each 14*fcf3ce44SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*fcf3ce44SJohn Forte * If applicable, add the following below this CDDL HEADER, with the 16*fcf3ce44SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying 17*fcf3ce44SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner] 18*fcf3ce44SJohn Forte * 19*fcf3ce44SJohn Forte * CDDL HEADER END 20*fcf3ce44SJohn Forte */ 21*fcf3ce44SJohn Forte /* 22*fcf3ce44SJohn Forte * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*fcf3ce44SJohn Forte * Use is subject to license terms. 24*fcf3ce44SJohn Forte */ 25*fcf3ce44SJohn Forte 26*fcf3ce44SJohn Forte #include <stdlib.h> 27*fcf3ce44SJohn Forte #include <stdio.h> 28*fcf3ce44SJohn Forte #include <sys/types.h> 29*fcf3ce44SJohn Forte #include <unistd.h> 30*fcf3ce44SJohn Forte #include <libintl.h> 31*fcf3ce44SJohn Forte #include <errno.h> 32*fcf3ce44SJohn Forte #include <string.h> 33*fcf3ce44SJohn Forte #include <assert.h> 34*fcf3ce44SJohn Forte #include <getopt.h> 35*fcf3ce44SJohn Forte #include <cmdparse.h> 36*fcf3ce44SJohn Forte 37*fcf3ce44SJohn Forte 38*fcf3ce44SJohn Forte /* Usage types */ 39*fcf3ce44SJohn Forte #define GENERAL_USAGE 1 40*fcf3ce44SJohn Forte #define DETAIL_USAGE 2 41*fcf3ce44SJohn Forte 42*fcf3ce44SJohn Forte /* printable ascii character set len */ 43*fcf3ce44SJohn Forte #define MAXOPTIONS (uint_t)('~' - '!' + 1) 44*fcf3ce44SJohn Forte 45*fcf3ce44SJohn Forte /* 46*fcf3ce44SJohn Forte * MAXOPTIONSTRING is the max length of the options string used in getopt and 47*fcf3ce44SJohn Forte * will be the printable character set + ':' for each character, 48*fcf3ce44SJohn Forte * providing for options with arguments. e.g. "t:Cs:hglr:" 49*fcf3ce44SJohn Forte */ 50*fcf3ce44SJohn Forte #define MAXOPTIONSTRING MAXOPTIONS * 2 51*fcf3ce44SJohn Forte 52*fcf3ce44SJohn Forte /* standard command options table to support -?, -V */ 53*fcf3ce44SJohn Forte struct option standardCmdOptions[] = { 54*fcf3ce44SJohn Forte {"help", no_argument, NULL, '?'}, 55*fcf3ce44SJohn Forte {"version", no_argument, NULL, 'V'}, 56*fcf3ce44SJohn Forte {NULL, 0, NULL, 0} 57*fcf3ce44SJohn Forte }; 58*fcf3ce44SJohn Forte 59*fcf3ce44SJohn Forte /* standard subcommand options table to support -? */ 60*fcf3ce44SJohn Forte struct option standardSubCmdOptions[] = { 61*fcf3ce44SJohn Forte {"help", no_argument, NULL, '?'}, 62*fcf3ce44SJohn Forte {NULL, 0, NULL, 0} 63*fcf3ce44SJohn Forte }; 64*fcf3ce44SJohn Forte 65*fcf3ce44SJohn Forte /* forward declarations */ 66*fcf3ce44SJohn Forte static int getSubcommandProps(char *, subCommandProps_t **); 67*fcf3ce44SJohn Forte static char *getExecBasename(char *); 68*fcf3ce44SJohn Forte static void usage(uint_t); 69*fcf3ce44SJohn Forte static void subUsage(uint_t, subCommandProps_t *); 70*fcf3ce44SJohn Forte static char *getLongOption(int); 71*fcf3ce44SJohn Forte static char *getOptionArgDesc(int); 72*fcf3ce44SJohn Forte 73*fcf3ce44SJohn Forte /* global data */ 74*fcf3ce44SJohn Forte static struct option *_longOptions; 75*fcf3ce44SJohn Forte static subCommandProps_t *_subCommandProps; 76*fcf3ce44SJohn Forte static optionTbl_t *_clientOptionTbl; 77*fcf3ce44SJohn Forte static char *commandName; 78*fcf3ce44SJohn Forte 79*fcf3ce44SJohn Forte 80*fcf3ce44SJohn Forte /* 81*fcf3ce44SJohn Forte * input: 82*fcf3ce44SJohn Forte * subCommand - subcommand value 83*fcf3ce44SJohn Forte * output: 84*fcf3ce44SJohn Forte * subCommandProps - pointer to subCommandProps_t structure allocated by caller 85*fcf3ce44SJohn Forte * 86*fcf3ce44SJohn Forte * On successful return, subCommandProps contains the properties for the value 87*fcf3ce44SJohn Forte * in subCommand. On failure, the contents of subCommandProps is unspecified. 88*fcf3ce44SJohn Forte * 89*fcf3ce44SJohn Forte * Returns: 90*fcf3ce44SJohn Forte * zero on success 91*fcf3ce44SJohn Forte * non-zero on failure 92*fcf3ce44SJohn Forte * 93*fcf3ce44SJohn Forte */ 94*fcf3ce44SJohn Forte static int 95*fcf3ce44SJohn Forte getSubcommandProps(char *subCommand, subCommandProps_t **subCommandProps) 96*fcf3ce44SJohn Forte { 97*fcf3ce44SJohn Forte subCommandProps_t *sp; 98*fcf3ce44SJohn Forte int len; 99*fcf3ce44SJohn Forte 100*fcf3ce44SJohn Forte for (sp = _subCommandProps; sp->name; sp++) { 101*fcf3ce44SJohn Forte len = strlen(subCommand); 102*fcf3ce44SJohn Forte if (len == strlen(sp->name) && 103*fcf3ce44SJohn Forte strncasecmp(subCommand, sp->name, len) == 0) { 104*fcf3ce44SJohn Forte *subCommandProps = sp; 105*fcf3ce44SJohn Forte return (0); 106*fcf3ce44SJohn Forte } 107*fcf3ce44SJohn Forte } 108*fcf3ce44SJohn Forte return (1); 109*fcf3ce44SJohn Forte } 110*fcf3ce44SJohn Forte 111*fcf3ce44SJohn Forte /* 112*fcf3ce44SJohn Forte * input: 113*fcf3ce44SJohn Forte * shortOption - short option character for which to return the 114*fcf3ce44SJohn Forte * associated long option string 115*fcf3ce44SJohn Forte * 116*fcf3ce44SJohn Forte * Returns: 117*fcf3ce44SJohn Forte * on success, long option name 118*fcf3ce44SJohn Forte * on failure, NULL 119*fcf3ce44SJohn Forte */ 120*fcf3ce44SJohn Forte static char * 121*fcf3ce44SJohn Forte getLongOption(int shortOption) 122*fcf3ce44SJohn Forte { 123*fcf3ce44SJohn Forte struct option *op; 124*fcf3ce44SJohn Forte for (op = _longOptions; op->name; op++) { 125*fcf3ce44SJohn Forte if (shortOption == op->val) { 126*fcf3ce44SJohn Forte return (op->name); 127*fcf3ce44SJohn Forte } 128*fcf3ce44SJohn Forte } 129*fcf3ce44SJohn Forte return (NULL); 130*fcf3ce44SJohn Forte } 131*fcf3ce44SJohn Forte 132*fcf3ce44SJohn Forte /* 133*fcf3ce44SJohn Forte * input 134*fcf3ce44SJohn Forte * shortOption - short option character for which to return the 135*fcf3ce44SJohn Forte * option argument 136*fcf3ce44SJohn Forte * Returns: 137*fcf3ce44SJohn Forte * on success, argument string 138*fcf3ce44SJohn Forte * on failure, NULL 139*fcf3ce44SJohn Forte */ 140*fcf3ce44SJohn Forte static char * 141*fcf3ce44SJohn Forte getOptionArgDesc(int shortOption) 142*fcf3ce44SJohn Forte { 143*fcf3ce44SJohn Forte optionTbl_t *op; 144*fcf3ce44SJohn Forte for (op = _clientOptionTbl; op->name; op++) { 145*fcf3ce44SJohn Forte if (op->val == shortOption && 146*fcf3ce44SJohn Forte op->has_arg == required_argument) { 147*fcf3ce44SJohn Forte return (op->argDesc); 148*fcf3ce44SJohn Forte } 149*fcf3ce44SJohn Forte } 150*fcf3ce44SJohn Forte return (NULL); 151*fcf3ce44SJohn Forte } 152*fcf3ce44SJohn Forte 153*fcf3ce44SJohn Forte 154*fcf3ce44SJohn Forte /* 155*fcf3ce44SJohn Forte * Print usage for a subcommand. 156*fcf3ce44SJohn Forte * 157*fcf3ce44SJohn Forte * input: 158*fcf3ce44SJohn Forte * usage type - GENERAL_USAGE, DETAIL_USAGE 159*fcf3ce44SJohn Forte * subcommand - pointer to subCommandProps_t structure 160*fcf3ce44SJohn Forte * 161*fcf3ce44SJohn Forte * Returns: 162*fcf3ce44SJohn Forte * none 163*fcf3ce44SJohn Forte * 164*fcf3ce44SJohn Forte */ 165*fcf3ce44SJohn Forte static void 166*fcf3ce44SJohn Forte subUsage(uint_t usageType, subCommandProps_t *subcommand) 167*fcf3ce44SJohn Forte { 168*fcf3ce44SJohn Forte int i; 169*fcf3ce44SJohn Forte char *optionArgDesc; 170*fcf3ce44SJohn Forte char *longOpt; 171*fcf3ce44SJohn Forte 172*fcf3ce44SJohn Forte if (usageType == GENERAL_USAGE) { 173*fcf3ce44SJohn Forte (void) printf("%s:\t%s %s [", gettext("Usage"), commandName, 174*fcf3ce44SJohn Forte subcommand->name); 175*fcf3ce44SJohn Forte for (i = 0; standardSubCmdOptions[i].name; i++) { 176*fcf3ce44SJohn Forte (void) printf("-%c", standardSubCmdOptions[i].val); 177*fcf3ce44SJohn Forte if (standardSubCmdOptions[i+1].name) 178*fcf3ce44SJohn Forte (void) printf(","); 179*fcf3ce44SJohn Forte } 180*fcf3ce44SJohn Forte (void) fprintf(stdout, "]\n"); 181*fcf3ce44SJohn Forte return; 182*fcf3ce44SJohn Forte } 183*fcf3ce44SJohn Forte 184*fcf3ce44SJohn Forte /* print subcommand usage */ 185*fcf3ce44SJohn Forte (void) printf("\n%s:\t%s %s ", gettext("Usage"), commandName, 186*fcf3ce44SJohn Forte subcommand->name); 187*fcf3ce44SJohn Forte 188*fcf3ce44SJohn Forte /* print options if applicable */ 189*fcf3ce44SJohn Forte if (subcommand->optionString != NULL) { 190*fcf3ce44SJohn Forte if (subcommand->required) { 191*fcf3ce44SJohn Forte (void) printf("%s", gettext("<")); 192*fcf3ce44SJohn Forte } else { 193*fcf3ce44SJohn Forte (void) printf("%s", gettext("[")); 194*fcf3ce44SJohn Forte } 195*fcf3ce44SJohn Forte (void) printf("%s", gettext("OPTIONS")); 196*fcf3ce44SJohn Forte if (subcommand->required) { 197*fcf3ce44SJohn Forte (void) printf("%s ", gettext(">")); 198*fcf3ce44SJohn Forte } else { 199*fcf3ce44SJohn Forte (void) printf("%s ", gettext("]")); 200*fcf3ce44SJohn Forte } 201*fcf3ce44SJohn Forte } 202*fcf3ce44SJohn Forte 203*fcf3ce44SJohn Forte /* print operand requirements */ 204*fcf3ce44SJohn Forte if (!(subcommand->operand & OPERAND_NONE) && 205*fcf3ce44SJohn Forte !(subcommand->operand & OPERAND_MANDATORY)) { 206*fcf3ce44SJohn Forte (void) printf(gettext("[")); 207*fcf3ce44SJohn Forte } 208*fcf3ce44SJohn Forte 209*fcf3ce44SJohn Forte if (subcommand->operand & OPERAND_MANDATORY) { 210*fcf3ce44SJohn Forte (void) printf(gettext("<")); 211*fcf3ce44SJohn Forte } 212*fcf3ce44SJohn Forte 213*fcf3ce44SJohn Forte if (!(subcommand->operand & OPERAND_NONE)) { 214*fcf3ce44SJohn Forte assert(subcommand->operandDefinition); 215*fcf3ce44SJohn Forte (void) printf("%s", subcommand->operandDefinition); 216*fcf3ce44SJohn Forte } 217*fcf3ce44SJohn Forte 218*fcf3ce44SJohn Forte if (subcommand->operand & OPERAND_MULTIPLE) { 219*fcf3ce44SJohn Forte (void) printf(gettext(" ...")); 220*fcf3ce44SJohn Forte } 221*fcf3ce44SJohn Forte 222*fcf3ce44SJohn Forte if (subcommand->operand & OPERAND_MANDATORY) { 223*fcf3ce44SJohn Forte (void) printf(gettext(">")); 224*fcf3ce44SJohn Forte } 225*fcf3ce44SJohn Forte 226*fcf3ce44SJohn Forte if (!(subcommand->operand & OPERAND_NONE) && 227*fcf3ce44SJohn Forte !(subcommand->operand & OPERAND_MANDATORY)) { 228*fcf3ce44SJohn Forte (void) printf(gettext("]")); 229*fcf3ce44SJohn Forte } 230*fcf3ce44SJohn Forte 231*fcf3ce44SJohn Forte /* print options for subcommand */ 232*fcf3ce44SJohn Forte if (subcommand->optionString != NULL) { 233*fcf3ce44SJohn Forte (void) printf("\n\t%s:", gettext("OPTIONS")); 234*fcf3ce44SJohn Forte for (i = 0; i < strlen(subcommand->optionString); i++) { 235*fcf3ce44SJohn Forte assert((longOpt = getLongOption( 236*fcf3ce44SJohn Forte subcommand->optionString[i])) != NULL); 237*fcf3ce44SJohn Forte (void) printf("\n\t\t-%c, --%s ", 238*fcf3ce44SJohn Forte subcommand->optionString[i], 239*fcf3ce44SJohn Forte longOpt); 240*fcf3ce44SJohn Forte optionArgDesc = 241*fcf3ce44SJohn Forte getOptionArgDesc(subcommand->optionString[i]); 242*fcf3ce44SJohn Forte if (optionArgDesc != NULL) { 243*fcf3ce44SJohn Forte (void) printf("<%s>", optionArgDesc); 244*fcf3ce44SJohn Forte } 245*fcf3ce44SJohn Forte if (subcommand->exclusive && 246*fcf3ce44SJohn Forte strchr(subcommand->exclusive, 247*fcf3ce44SJohn Forte subcommand->optionString[i])) { 248*fcf3ce44SJohn Forte (void) printf(" (%s)", gettext("exclusive")); 249*fcf3ce44SJohn Forte } 250*fcf3ce44SJohn Forte } 251*fcf3ce44SJohn Forte } 252*fcf3ce44SJohn Forte (void) fprintf(stdout, "\n"); 253*fcf3ce44SJohn Forte } 254*fcf3ce44SJohn Forte 255*fcf3ce44SJohn Forte /* 256*fcf3ce44SJohn Forte * input: 257*fcf3ce44SJohn Forte * type of usage statement to print 258*fcf3ce44SJohn Forte * 259*fcf3ce44SJohn Forte * Returns: 260*fcf3ce44SJohn Forte * return value of subUsage 261*fcf3ce44SJohn Forte */ 262*fcf3ce44SJohn Forte static void 263*fcf3ce44SJohn Forte usage(uint_t usageType) 264*fcf3ce44SJohn Forte { 265*fcf3ce44SJohn Forte int i; 266*fcf3ce44SJohn Forte subCommandProps_t *sp; 267*fcf3ce44SJohn Forte 268*fcf3ce44SJohn Forte /* print general command usage */ 269*fcf3ce44SJohn Forte (void) printf("%s:\t%s ", gettext("Usage"), commandName); 270*fcf3ce44SJohn Forte 271*fcf3ce44SJohn Forte for (i = 0; standardCmdOptions[i].name; i++) { 272*fcf3ce44SJohn Forte (void) printf("-%c", standardCmdOptions[i].val); 273*fcf3ce44SJohn Forte if (standardCmdOptions[i+1].name) 274*fcf3ce44SJohn Forte (void) printf(","); 275*fcf3ce44SJohn Forte } 276*fcf3ce44SJohn Forte 277*fcf3ce44SJohn Forte if (usageType == GENERAL_USAGE) { 278*fcf3ce44SJohn Forte for (i = 0; standardSubCmdOptions[i].name; i++) { 279*fcf3ce44SJohn Forte (void) printf(",--%s", standardSubCmdOptions[i].name); 280*fcf3ce44SJohn Forte if (standardSubCmdOptions[i+1].name) 281*fcf3ce44SJohn Forte (void) printf(","); 282*fcf3ce44SJohn Forte } 283*fcf3ce44SJohn Forte } 284*fcf3ce44SJohn Forte 285*fcf3ce44SJohn Forte (void) fprintf(stdout, "\n"); 286*fcf3ce44SJohn Forte 287*fcf3ce44SJohn Forte 288*fcf3ce44SJohn Forte /* print all subcommand usage */ 289*fcf3ce44SJohn Forte for (sp = _subCommandProps; sp->name; sp++) { 290*fcf3ce44SJohn Forte subUsage(usageType, sp); 291*fcf3ce44SJohn Forte } 292*fcf3ce44SJohn Forte } 293*fcf3ce44SJohn Forte 294*fcf3ce44SJohn Forte /* 295*fcf3ce44SJohn Forte * input: 296*fcf3ce44SJohn Forte * execFullName - exec name of program (argv[0]) 297*fcf3ce44SJohn Forte * 298*fcf3ce44SJohn Forte * Returns: 299*fcf3ce44SJohn Forte * command name portion of execFullName 300*fcf3ce44SJohn Forte */ 301*fcf3ce44SJohn Forte static char * 302*fcf3ce44SJohn Forte getExecBasename(char *execFullname) 303*fcf3ce44SJohn Forte { 304*fcf3ce44SJohn Forte char *lastSlash, *execBasename; 305*fcf3ce44SJohn Forte 306*fcf3ce44SJohn Forte /* guard against '/' at end of command invocation */ 307*fcf3ce44SJohn Forte for (;;) { 308*fcf3ce44SJohn Forte lastSlash = strrchr(execFullname, '/'); 309*fcf3ce44SJohn Forte if (lastSlash == NULL) { 310*fcf3ce44SJohn Forte execBasename = execFullname; 311*fcf3ce44SJohn Forte break; 312*fcf3ce44SJohn Forte } else { 313*fcf3ce44SJohn Forte execBasename = lastSlash + 1; 314*fcf3ce44SJohn Forte if (*execBasename == '\0') { 315*fcf3ce44SJohn Forte *lastSlash = '\0'; 316*fcf3ce44SJohn Forte continue; 317*fcf3ce44SJohn Forte } 318*fcf3ce44SJohn Forte break; 319*fcf3ce44SJohn Forte } 320*fcf3ce44SJohn Forte } 321*fcf3ce44SJohn Forte return (execBasename); 322*fcf3ce44SJohn Forte } 323*fcf3ce44SJohn Forte 324*fcf3ce44SJohn Forte /* 325*fcf3ce44SJohn Forte * cmdParse is a parser that checks syntax of the input command against 326*fcf3ce44SJohn Forte * various rules tables. 327*fcf3ce44SJohn Forte * 328*fcf3ce44SJohn Forte * It provides usage feedback based upon the passed rules tables by calling 329*fcf3ce44SJohn Forte * two usage functions, usage, subUsage 330*fcf3ce44SJohn Forte * 331*fcf3ce44SJohn Forte * When syntax is successfully validated, the associated function is called 332*fcf3ce44SJohn Forte * using the subcommands table functions. 333*fcf3ce44SJohn Forte * 334*fcf3ce44SJohn Forte * Syntax is as follows: 335*fcf3ce44SJohn Forte * command subcommand [<options>] [<operand>] 336*fcf3ce44SJohn Forte * 337*fcf3ce44SJohn Forte * There are two standard short and long options assumed: 338*fcf3ce44SJohn Forte * -?, --help Provides usage on a command or subcommand 339*fcf3ce44SJohn Forte * and stops further processing of the arguments 340*fcf3ce44SJohn Forte * 341*fcf3ce44SJohn Forte * -V, --version Provides version information on the command 342*fcf3ce44SJohn Forte * and stops further processing of the arguments 343*fcf3ce44SJohn Forte * 344*fcf3ce44SJohn Forte * These options are loaded by this function. 345*fcf3ce44SJohn Forte * 346*fcf3ce44SJohn Forte * input: 347*fcf3ce44SJohn Forte * argc, argv from main 348*fcf3ce44SJohn Forte * syntax rules tables (synTables_t structure) 349*fcf3ce44SJohn Forte * callArgs - void * passed by caller to be passed to subcommand function 350*fcf3ce44SJohn Forte * 351*fcf3ce44SJohn Forte * output: 352*fcf3ce44SJohn Forte * funcRet - pointer to int that holds subcommand function return value 353*fcf3ce44SJohn Forte * 354*fcf3ce44SJohn Forte * Returns: 355*fcf3ce44SJohn Forte * 356*fcf3ce44SJohn Forte * zero on successful syntax parse and function call 357*fcf3ce44SJohn Forte * 358*fcf3ce44SJohn Forte * 1 on unsuccessful syntax parse (no function has been called) 359*fcf3ce44SJohn Forte * This could be due to a version or help call or simply a 360*fcf3ce44SJohn Forte * general usage call. 361*fcf3ce44SJohn Forte * 362*fcf3ce44SJohn Forte * -1 check errno, call failed 363*fcf3ce44SJohn Forte * 364*fcf3ce44SJohn Forte * This module is not MT-safe. 365*fcf3ce44SJohn Forte * 366*fcf3ce44SJohn Forte */ 367*fcf3ce44SJohn Forte int 368*fcf3ce44SJohn Forte cmdParse(int argc, char *argv[], synTables_t synTable, void *callArgs, 369*fcf3ce44SJohn Forte int *funcRet) 370*fcf3ce44SJohn Forte { 371*fcf3ce44SJohn Forte int getoptargc; 372*fcf3ce44SJohn Forte char **getoptargv; 373*fcf3ce44SJohn Forte int opt; 374*fcf3ce44SJohn Forte int operInd; 375*fcf3ce44SJohn Forte int i, j; 376*fcf3ce44SJohn Forte int len; 377*fcf3ce44SJohn Forte int requiredOptionCnt = 0, requiredOptionEntered = 0; 378*fcf3ce44SJohn Forte char *availOptions; 379*fcf3ce44SJohn Forte char *versionString; 380*fcf3ce44SJohn Forte char optionStringAll[MAXOPTIONSTRING + 1]; 381*fcf3ce44SJohn Forte subCommandProps_t *subcommand; 382*fcf3ce44SJohn Forte cmdOptions_t cmdOptions[MAXOPTIONS + 1]; 383*fcf3ce44SJohn Forte optionTbl_t *optionTbl; 384*fcf3ce44SJohn Forte struct option *lp; 385*fcf3ce44SJohn Forte struct option intLongOpt[MAXOPTIONS + 1]; 386*fcf3ce44SJohn Forte 387*fcf3ce44SJohn Forte /* 388*fcf3ce44SJohn Forte * Check for NULLs on mandatory input arguments 389*fcf3ce44SJohn Forte * 390*fcf3ce44SJohn Forte * Note: longOptionTbl can be NULL in the case 391*fcf3ce44SJohn Forte * where there is no caller defined options 392*fcf3ce44SJohn Forte * 393*fcf3ce44SJohn Forte */ 394*fcf3ce44SJohn Forte assert(synTable.versionString); 395*fcf3ce44SJohn Forte assert(synTable.subCommandPropsTbl); 396*fcf3ce44SJohn Forte assert(funcRet); 397*fcf3ce44SJohn Forte 398*fcf3ce44SJohn Forte versionString = synTable.versionString; 399*fcf3ce44SJohn Forte 400*fcf3ce44SJohn Forte /* set global command name */ 401*fcf3ce44SJohn Forte commandName = getExecBasename(argv[0]); 402*fcf3ce44SJohn Forte 403*fcf3ce44SJohn Forte /* Set unbuffered output */ 404*fcf3ce44SJohn Forte setbuf(stdout, NULL); 405*fcf3ce44SJohn Forte 406*fcf3ce44SJohn Forte /* load globals */ 407*fcf3ce44SJohn Forte _subCommandProps = synTable.subCommandPropsTbl; 408*fcf3ce44SJohn Forte _clientOptionTbl = synTable.longOptionTbl; 409*fcf3ce44SJohn Forte 410*fcf3ce44SJohn Forte /* There must be at least two arguments */ 411*fcf3ce44SJohn Forte if (argc < 2) { 412*fcf3ce44SJohn Forte usage(GENERAL_USAGE); 413*fcf3ce44SJohn Forte return (1); 414*fcf3ce44SJohn Forte } 415*fcf3ce44SJohn Forte 416*fcf3ce44SJohn Forte (void) memset(&intLongOpt[0], 0, sizeof (intLongOpt)); 417*fcf3ce44SJohn Forte 418*fcf3ce44SJohn Forte /* 419*fcf3ce44SJohn Forte * load standard subcommand options to internal long options table 420*fcf3ce44SJohn Forte * Two separate getopt_long(3C) tables are used. 421*fcf3ce44SJohn Forte */ 422*fcf3ce44SJohn Forte for (i = 0; standardSubCmdOptions[i].name; i++) { 423*fcf3ce44SJohn Forte intLongOpt[i].name = standardSubCmdOptions[i].name; 424*fcf3ce44SJohn Forte intLongOpt[i].has_arg = standardSubCmdOptions[i].has_arg; 425*fcf3ce44SJohn Forte intLongOpt[i].flag = standardSubCmdOptions[i].flag; 426*fcf3ce44SJohn Forte intLongOpt[i].val = standardSubCmdOptions[i].val; 427*fcf3ce44SJohn Forte } 428*fcf3ce44SJohn Forte 429*fcf3ce44SJohn Forte /* 430*fcf3ce44SJohn Forte * copy caller's long options into internal long options table 431*fcf3ce44SJohn Forte * We do this for two reasons: 432*fcf3ce44SJohn Forte * 1) We need to use the getopt_long option structure internally 433*fcf3ce44SJohn Forte * 2) We need to prepend the table with the standard option 434*fcf3ce44SJohn Forte * for all subcommands (currently -?) 435*fcf3ce44SJohn Forte */ 436*fcf3ce44SJohn Forte for (optionTbl = synTable.longOptionTbl; 437*fcf3ce44SJohn Forte optionTbl && optionTbl->name; optionTbl++, i++) { 438*fcf3ce44SJohn Forte if (i > MAXOPTIONS - 1) { 439*fcf3ce44SJohn Forte /* option table too long */ 440*fcf3ce44SJohn Forte assert(0); 441*fcf3ce44SJohn Forte } 442*fcf3ce44SJohn Forte intLongOpt[i].name = optionTbl->name; 443*fcf3ce44SJohn Forte intLongOpt[i].has_arg = optionTbl->has_arg; 444*fcf3ce44SJohn Forte intLongOpt[i].flag = NULL; 445*fcf3ce44SJohn Forte intLongOpt[i].val = optionTbl->val; 446*fcf3ce44SJohn Forte } 447*fcf3ce44SJohn Forte 448*fcf3ce44SJohn Forte /* set option table global */ 449*fcf3ce44SJohn Forte _longOptions = &intLongOpt[0]; 450*fcf3ce44SJohn Forte 451*fcf3ce44SJohn Forte 452*fcf3ce44SJohn Forte /* 453*fcf3ce44SJohn Forte * Check for help/version request immediately following command 454*fcf3ce44SJohn Forte * '+' in option string ensures POSIX compliance in getopt_long() 455*fcf3ce44SJohn Forte * which means that processing will stop at first non-option 456*fcf3ce44SJohn Forte * argument. 457*fcf3ce44SJohn Forte */ 458*fcf3ce44SJohn Forte while ((opt = getopt_long(argc, argv, "+?V", standardCmdOptions, 459*fcf3ce44SJohn Forte NULL)) != EOF) { 460*fcf3ce44SJohn Forte switch (opt) { 461*fcf3ce44SJohn Forte case '?': 462*fcf3ce44SJohn Forte /* 463*fcf3ce44SJohn Forte * getopt can return a '?' when no 464*fcf3ce44SJohn Forte * option letters match string. Check for 465*fcf3ce44SJohn Forte * the 'real' '?' in optopt. 466*fcf3ce44SJohn Forte */ 467*fcf3ce44SJohn Forte if (optopt == '?') { 468*fcf3ce44SJohn Forte usage(DETAIL_USAGE); 469*fcf3ce44SJohn Forte exit(0); 470*fcf3ce44SJohn Forte } else { 471*fcf3ce44SJohn Forte usage(GENERAL_USAGE); 472*fcf3ce44SJohn Forte return (1); 473*fcf3ce44SJohn Forte } 474*fcf3ce44SJohn Forte break; 475*fcf3ce44SJohn Forte case 'V': 476*fcf3ce44SJohn Forte (void) fprintf(stdout, "%s: %s %s\n", 477*fcf3ce44SJohn Forte commandName, gettext("Version"), 478*fcf3ce44SJohn Forte versionString); 479*fcf3ce44SJohn Forte exit(0); 480*fcf3ce44SJohn Forte break; 481*fcf3ce44SJohn Forte default: 482*fcf3ce44SJohn Forte break; 483*fcf3ce44SJohn Forte } 484*fcf3ce44SJohn Forte } 485*fcf3ce44SJohn Forte 486*fcf3ce44SJohn Forte /* 487*fcf3ce44SJohn Forte * subcommand is always in the second argument. If there is no 488*fcf3ce44SJohn Forte * recognized subcommand in the second argument, print error, 489*fcf3ce44SJohn Forte * general usage and then return. 490*fcf3ce44SJohn Forte */ 491*fcf3ce44SJohn Forte if (getSubcommandProps(argv[1], &subcommand) != 0) { 492*fcf3ce44SJohn Forte (void) printf("%s: %s\n", commandName, 493*fcf3ce44SJohn Forte gettext("invalid subcommand")); 494*fcf3ce44SJohn Forte usage(GENERAL_USAGE); 495*fcf3ce44SJohn Forte return (1); 496*fcf3ce44SJohn Forte } 497*fcf3ce44SJohn Forte 498*fcf3ce44SJohn Forte getoptargv = argv; 499*fcf3ce44SJohn Forte getoptargv++; 500*fcf3ce44SJohn Forte getoptargc = argc; 501*fcf3ce44SJohn Forte getoptargc -= 1; 502*fcf3ce44SJohn Forte 503*fcf3ce44SJohn Forte (void) memset(optionStringAll, 0, sizeof (optionStringAll)); 504*fcf3ce44SJohn Forte (void) memset(&cmdOptions[0], 0, sizeof (cmdOptions)); 505*fcf3ce44SJohn Forte 506*fcf3ce44SJohn Forte j = 0; 507*fcf3ce44SJohn Forte /* 508*fcf3ce44SJohn Forte * Build optionStringAll from long options table 509*fcf3ce44SJohn Forte */ 510*fcf3ce44SJohn Forte for (lp = _longOptions; lp->name; lp++, j++) { 511*fcf3ce44SJohn Forte /* sanity check on string length */ 512*fcf3ce44SJohn Forte if (j + 1 >= sizeof (optionStringAll)) { 513*fcf3ce44SJohn Forte /* option table too long */ 514*fcf3ce44SJohn Forte assert(0); 515*fcf3ce44SJohn Forte } 516*fcf3ce44SJohn Forte optionStringAll[j] = lp->val; 517*fcf3ce44SJohn Forte if (lp->has_arg == required_argument) { 518*fcf3ce44SJohn Forte optionStringAll[++j] = ':'; 519*fcf3ce44SJohn Forte } 520*fcf3ce44SJohn Forte } 521*fcf3ce44SJohn Forte 522*fcf3ce44SJohn Forte i = 0; 523*fcf3ce44SJohn Forte /* 524*fcf3ce44SJohn Forte * Run getopt for all arguments against all possible options 525*fcf3ce44SJohn Forte * Store all options/option arguments in an array for retrieval 526*fcf3ce44SJohn Forte * later. 527*fcf3ce44SJohn Forte * 528*fcf3ce44SJohn Forte * Once all options are retrieved, a validity check against 529*fcf3ce44SJohn Forte * subcommand table is performed. 530*fcf3ce44SJohn Forte */ 531*fcf3ce44SJohn Forte while ((opt = getopt_long(getoptargc, getoptargv, optionStringAll, 532*fcf3ce44SJohn Forte _longOptions, NULL)) != EOF) { 533*fcf3ce44SJohn Forte switch (opt) { 534*fcf3ce44SJohn Forte case '?': 535*fcf3ce44SJohn Forte subUsage(DETAIL_USAGE, subcommand); 536*fcf3ce44SJohn Forte exit(0); 537*fcf3ce44SJohn Forte default: 538*fcf3ce44SJohn Forte cmdOptions[i].optval = opt; 539*fcf3ce44SJohn Forte if (optarg) { 540*fcf3ce44SJohn Forte len = strlen(optarg); 541*fcf3ce44SJohn Forte if (len > sizeof (cmdOptions[i].optarg) 542*fcf3ce44SJohn Forte - 1) { 543*fcf3ce44SJohn Forte (void) printf("%s: %s\n", 544*fcf3ce44SJohn Forte commandName, 545*fcf3ce44SJohn Forte gettext("option too long")); 546*fcf3ce44SJohn Forte errno = EINVAL; 547*fcf3ce44SJohn Forte return (-1); 548*fcf3ce44SJohn Forte } 549*fcf3ce44SJohn Forte (void) strncpy(cmdOptions[i].optarg, 550*fcf3ce44SJohn Forte optarg, len); 551*fcf3ce44SJohn Forte } 552*fcf3ce44SJohn Forte i++; 553*fcf3ce44SJohn Forte break; 554*fcf3ce44SJohn Forte } 555*fcf3ce44SJohn Forte } 556*fcf3ce44SJohn Forte 557*fcf3ce44SJohn Forte /* 558*fcf3ce44SJohn Forte * increment past last option 559*fcf3ce44SJohn Forte */ 560*fcf3ce44SJohn Forte operInd = optind + 1; 561*fcf3ce44SJohn Forte 562*fcf3ce44SJohn Forte /* 563*fcf3ce44SJohn Forte * Check validity of given options, if any were given 564*fcf3ce44SJohn Forte */ 565*fcf3ce44SJohn Forte 566*fcf3ce44SJohn Forte /* get option string for this subcommand */ 567*fcf3ce44SJohn Forte availOptions = subcommand->optionString; 568*fcf3ce44SJohn Forte 569*fcf3ce44SJohn Forte /* Get count of required options */ 570*fcf3ce44SJohn Forte if (subcommand->required) { 571*fcf3ce44SJohn Forte requiredOptionCnt = strlen(subcommand->required); 572*fcf3ce44SJohn Forte } 573*fcf3ce44SJohn Forte 574*fcf3ce44SJohn Forte if (cmdOptions[0].optval != 0) { /* options were input */ 575*fcf3ce44SJohn Forte if (availOptions == NULL) { /* no options permitted */ 576*fcf3ce44SJohn Forte (void) printf("%s: %s\n", commandName, 577*fcf3ce44SJohn Forte gettext("no options permitted")); 578*fcf3ce44SJohn Forte subUsage(DETAIL_USAGE, subcommand); 579*fcf3ce44SJohn Forte return (1); 580*fcf3ce44SJohn Forte } 581*fcf3ce44SJohn Forte for (i = 0; cmdOptions[i].optval; i++) { 582*fcf3ce44SJohn Forte /* is the option in the available option string? */ 583*fcf3ce44SJohn Forte if (!(strchr(availOptions, cmdOptions[i].optval))) { 584*fcf3ce44SJohn Forte (void) printf("%s: '-%c': %s\n", commandName, 585*fcf3ce44SJohn Forte cmdOptions[i].optval, 586*fcf3ce44SJohn Forte gettext("invalid option")); 587*fcf3ce44SJohn Forte subUsage(DETAIL_USAGE, subcommand); 588*fcf3ce44SJohn Forte return (1); 589*fcf3ce44SJohn Forte /* increment required options entered */ 590*fcf3ce44SJohn Forte } else if (subcommand->required && 591*fcf3ce44SJohn Forte (strchr(subcommand->required, 592*fcf3ce44SJohn Forte cmdOptions[i].optval))) { 593*fcf3ce44SJohn Forte requiredOptionEntered++; 594*fcf3ce44SJohn Forte /* Check for exclusive options */ 595*fcf3ce44SJohn Forte } else if (cmdOptions[1].optval != 0 && 596*fcf3ce44SJohn Forte subcommand->exclusive && 597*fcf3ce44SJohn Forte strchr(subcommand->exclusive, 598*fcf3ce44SJohn Forte cmdOptions[i].optval)) { 599*fcf3ce44SJohn Forte (void) printf("%s: '-%c': %s\n", 600*fcf3ce44SJohn Forte commandName, cmdOptions[i].optval, 601*fcf3ce44SJohn Forte gettext("is an exclusive option")); 602*fcf3ce44SJohn Forte subUsage(DETAIL_USAGE, subcommand); 603*fcf3ce44SJohn Forte return (1); 604*fcf3ce44SJohn Forte } 605*fcf3ce44SJohn Forte } 606*fcf3ce44SJohn Forte } else { /* no options were input */ 607*fcf3ce44SJohn Forte if (availOptions != NULL && subcommand->required) { 608*fcf3ce44SJohn Forte (void) printf("%s: %s\n", commandName, 609*fcf3ce44SJohn Forte gettext("at least one option required")); 610*fcf3ce44SJohn Forte subUsage(DETAIL_USAGE, subcommand); 611*fcf3ce44SJohn Forte return (1); 612*fcf3ce44SJohn Forte } 613*fcf3ce44SJohn Forte } 614*fcf3ce44SJohn Forte 615*fcf3ce44SJohn Forte /* Were all required options entered? */ 616*fcf3ce44SJohn Forte if (requiredOptionEntered != requiredOptionCnt) { 617*fcf3ce44SJohn Forte (void) printf("%s: %s: %s\n", commandName, 618*fcf3ce44SJohn Forte gettext("Following option(s) required"), 619*fcf3ce44SJohn Forte subcommand->required); 620*fcf3ce44SJohn Forte subUsage(DETAIL_USAGE, subcommand); 621*fcf3ce44SJohn Forte return (1); 622*fcf3ce44SJohn Forte } 623*fcf3ce44SJohn Forte 624*fcf3ce44SJohn Forte 625*fcf3ce44SJohn Forte /* 626*fcf3ce44SJohn Forte * If there are no operands, 627*fcf3ce44SJohn Forte * check to see if this is okay 628*fcf3ce44SJohn Forte */ 629*fcf3ce44SJohn Forte if ((operInd == argc) && 630*fcf3ce44SJohn Forte (subcommand->operand & OPERAND_MANDATORY)) { 631*fcf3ce44SJohn Forte (void) printf("%s: %s %s\n", commandName, subcommand->name, 632*fcf3ce44SJohn Forte gettext("requires an operand")); 633*fcf3ce44SJohn Forte subUsage(DETAIL_USAGE, subcommand); 634*fcf3ce44SJohn Forte return (1); 635*fcf3ce44SJohn Forte } 636*fcf3ce44SJohn Forte 637*fcf3ce44SJohn Forte /* 638*fcf3ce44SJohn Forte * If there are more operands, 639*fcf3ce44SJohn Forte * check to see if this is okay 640*fcf3ce44SJohn Forte */ 641*fcf3ce44SJohn Forte if ((argc > operInd) && 642*fcf3ce44SJohn Forte (subcommand->operand & OPERAND_NONE)) { 643*fcf3ce44SJohn Forte (void) fprintf(stderr, "%s: %s %s\n", commandName, 644*fcf3ce44SJohn Forte subcommand->name, gettext("takes no operands")); 645*fcf3ce44SJohn Forte subUsage(DETAIL_USAGE, subcommand); 646*fcf3ce44SJohn Forte return (1); 647*fcf3ce44SJohn Forte } 648*fcf3ce44SJohn Forte 649*fcf3ce44SJohn Forte /* 650*fcf3ce44SJohn Forte * If there is more than one more operand, 651*fcf3ce44SJohn Forte * check to see if this is okay 652*fcf3ce44SJohn Forte */ 653*fcf3ce44SJohn Forte if ((argc > operInd) && ((argc - operInd) != 1) && 654*fcf3ce44SJohn Forte (subcommand->operand & OPERAND_SINGLE)) { 655*fcf3ce44SJohn Forte (void) printf("%s: %s %s\n", commandName, 656*fcf3ce44SJohn Forte subcommand->name, gettext("accepts only a single operand")); 657*fcf3ce44SJohn Forte subUsage(DETAIL_USAGE, subcommand); 658*fcf3ce44SJohn Forte return (1); 659*fcf3ce44SJohn Forte } 660*fcf3ce44SJohn Forte 661*fcf3ce44SJohn Forte /* Finished syntax checks */ 662*fcf3ce44SJohn Forte 663*fcf3ce44SJohn Forte 664*fcf3ce44SJohn Forte /* Call appropriate function */ 665*fcf3ce44SJohn Forte *funcRet = subcommand->handler(argc - operInd, &argv[operInd], 666*fcf3ce44SJohn Forte &cmdOptions[0], callArgs); 667*fcf3ce44SJohn Forte 668*fcf3ce44SJohn Forte return (0); 669*fcf3ce44SJohn Forte } 670