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 /* Usage types */ 38*fcf3ce44SJohn Forte #define GENERAL_USAGE 1 39*fcf3ce44SJohn Forte #define HELP_USAGE 2 40*fcf3ce44SJohn Forte #define DETAIL_USAGE 3 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 getSubcommand(char *, subcommand_t **); 67*fcf3ce44SJohn Forte static char *getExecBasename(char *); 68*fcf3ce44SJohn Forte static void usage(uint_t); 69*fcf3ce44SJohn Forte static void subUsage(uint_t, subcommand_t *); 70*fcf3ce44SJohn Forte static void subUsageObject(uint_t, subcommand_t *, object_t *); 71*fcf3ce44SJohn Forte static int getObject(char *, object_t **); 72*fcf3ce44SJohn Forte static int getObjectRules(uint_t, objectRules_t **); 73*fcf3ce44SJohn Forte static char *getLongOption(int); 74*fcf3ce44SJohn Forte static optionProp_t *getOptions(uint_t, uint_t); 75*fcf3ce44SJohn Forte static char *getOptionArgDesc(int); 76*fcf3ce44SJohn Forte extern void seeMan(void); 77*fcf3ce44SJohn Forte 78*fcf3ce44SJohn Forte /* global data */ 79*fcf3ce44SJohn Forte static struct option *_longOptions; 80*fcf3ce44SJohn Forte static subcommand_t *_subcommands; 81*fcf3ce44SJohn Forte static object_t *_objects; 82*fcf3ce44SJohn Forte static objectRules_t *_objectRules; 83*fcf3ce44SJohn Forte static optionRules_t *_optionRules; 84*fcf3ce44SJohn Forte static optionTbl_t *_clientOptionTbl; 85*fcf3ce44SJohn Forte static char *commandName; 86*fcf3ce44SJohn Forte 87*fcf3ce44SJohn Forte 88*fcf3ce44SJohn Forte /* 89*fcf3ce44SJohn Forte * input: 90*fcf3ce44SJohn Forte * object - object value 91*fcf3ce44SJohn Forte * output: 92*fcf3ce44SJohn Forte * opCmd - pointer to opCmd_t structure allocated by caller 93*fcf3ce44SJohn Forte * 94*fcf3ce44SJohn Forte * On successful return, opCmd contains the rules for the value in 95*fcf3ce44SJohn Forte * object. On failure, the contents of opCmd is unspecified. 96*fcf3ce44SJohn Forte * 97*fcf3ce44SJohn Forte * Returns: 98*fcf3ce44SJohn Forte * zero on success 99*fcf3ce44SJohn Forte * non-zero on failure 100*fcf3ce44SJohn Forte * 101*fcf3ce44SJohn Forte */ 102*fcf3ce44SJohn Forte static int 103*fcf3ce44SJohn Forte getObjectRules(uint_t object, objectRules_t **objectRules) 104*fcf3ce44SJohn Forte { 105*fcf3ce44SJohn Forte objectRules_t *sp; 106*fcf3ce44SJohn Forte 107*fcf3ce44SJohn Forte for (sp = _objectRules; sp->value; sp++) { 108*fcf3ce44SJohn Forte if (sp->value == object) { 109*fcf3ce44SJohn Forte *objectRules = sp; 110*fcf3ce44SJohn Forte return (0); 111*fcf3ce44SJohn Forte } 112*fcf3ce44SJohn Forte } 113*fcf3ce44SJohn Forte return (1); 114*fcf3ce44SJohn Forte } 115*fcf3ce44SJohn Forte 116*fcf3ce44SJohn Forte /* 117*fcf3ce44SJohn Forte * input: 118*fcf3ce44SJohn Forte * arg - pointer to array of char containing object string 119*fcf3ce44SJohn Forte * 120*fcf3ce44SJohn Forte * output: 121*fcf3ce44SJohn Forte * object - pointer to object_t structure pointer 122*fcf3ce44SJohn Forte * on success, contains the matching object structure based on 123*fcf3ce44SJohn Forte * input object name 124*fcf3ce44SJohn Forte * 125*fcf3ce44SJohn Forte * Returns: 126*fcf3ce44SJohn Forte * zero on success 127*fcf3ce44SJohn Forte * non-zero otherwise 128*fcf3ce44SJohn Forte * 129*fcf3ce44SJohn Forte */ 130*fcf3ce44SJohn Forte static int 131*fcf3ce44SJohn Forte getObject(char *arg, object_t **object) 132*fcf3ce44SJohn Forte { 133*fcf3ce44SJohn Forte 134*fcf3ce44SJohn Forte object_t *op; 135*fcf3ce44SJohn Forte int len; 136*fcf3ce44SJohn Forte 137*fcf3ce44SJohn Forte for (op = _objects; op->name; op++) { 138*fcf3ce44SJohn Forte len = strlen(arg); 139*fcf3ce44SJohn Forte if (len == strlen(op->name) && 140*fcf3ce44SJohn Forte strncasecmp(arg, op->name, len) == 0) { 141*fcf3ce44SJohn Forte *object = op; 142*fcf3ce44SJohn Forte return (0); 143*fcf3ce44SJohn Forte } 144*fcf3ce44SJohn Forte } 145*fcf3ce44SJohn Forte return (1); 146*fcf3ce44SJohn Forte } 147*fcf3ce44SJohn Forte 148*fcf3ce44SJohn Forte /* 149*fcf3ce44SJohn Forte * input: 150*fcf3ce44SJohn Forte * arg - pointer to array of char containing subcommand string 151*fcf3ce44SJohn Forte * output: 152*fcf3ce44SJohn Forte * subcommand - pointer to subcommand_t pointer 153*fcf3ce44SJohn Forte * on success, contains the matching subcommand structure based on 154*fcf3ce44SJohn Forte * input subcommand name 155*fcf3ce44SJohn Forte * 156*fcf3ce44SJohn Forte * Returns: 157*fcf3ce44SJohn Forte * zero on success 158*fcf3ce44SJohn Forte * non-zero on failure 159*fcf3ce44SJohn Forte */ 160*fcf3ce44SJohn Forte static int 161*fcf3ce44SJohn Forte getSubcommand(char *arg, subcommand_t **subcommand) 162*fcf3ce44SJohn Forte { 163*fcf3ce44SJohn Forte subcommand_t *sp; 164*fcf3ce44SJohn Forte int len; 165*fcf3ce44SJohn Forte 166*fcf3ce44SJohn Forte for (sp = _subcommands; sp->name; sp++) { 167*fcf3ce44SJohn Forte len = strlen(arg); 168*fcf3ce44SJohn Forte if (len == strlen(sp->name) && 169*fcf3ce44SJohn Forte strncasecmp(arg, sp->name, len) == 0) { 170*fcf3ce44SJohn Forte *subcommand = sp; 171*fcf3ce44SJohn Forte return (0); 172*fcf3ce44SJohn Forte } 173*fcf3ce44SJohn Forte } 174*fcf3ce44SJohn Forte return (1); 175*fcf3ce44SJohn Forte } 176*fcf3ce44SJohn Forte 177*fcf3ce44SJohn Forte /* 178*fcf3ce44SJohn Forte * input: 179*fcf3ce44SJohn Forte * object - object for which to get options 180*fcf3ce44SJohn Forte * subcommand - subcommand for which to get options 181*fcf3ce44SJohn Forte * 182*fcf3ce44SJohn Forte * Returns: 183*fcf3ce44SJohn Forte * on success, optionsProp_t pointer to structure matching input object 184*fcf3ce44SJohn Forte * value 185*fcf3ce44SJohn Forte * on failure, NULL is returned 186*fcf3ce44SJohn Forte */ 187*fcf3ce44SJohn Forte static optionProp_t * 188*fcf3ce44SJohn Forte getOptions(uint_t object, uint_t subcommand) 189*fcf3ce44SJohn Forte { 190*fcf3ce44SJohn Forte uint_t currObject; 191*fcf3ce44SJohn Forte optionRules_t *op = _optionRules; 192*fcf3ce44SJohn Forte while (op && ((currObject = op->objectValue) != 0)) { 193*fcf3ce44SJohn Forte if ((currObject == object) && 194*fcf3ce44SJohn Forte (op->subcommandValue == subcommand)) { 195*fcf3ce44SJohn Forte return (&(op->optionProp)); 196*fcf3ce44SJohn Forte } 197*fcf3ce44SJohn Forte op++; 198*fcf3ce44SJohn Forte } 199*fcf3ce44SJohn Forte return (NULL); 200*fcf3ce44SJohn Forte } 201*fcf3ce44SJohn Forte 202*fcf3ce44SJohn Forte /* 203*fcf3ce44SJohn Forte * input: 204*fcf3ce44SJohn Forte * shortOption - short option character for which to return the 205*fcf3ce44SJohn Forte * associated long option string 206*fcf3ce44SJohn Forte * 207*fcf3ce44SJohn Forte * Returns: 208*fcf3ce44SJohn Forte * on success, long option name 209*fcf3ce44SJohn Forte * on failure, NULL 210*fcf3ce44SJohn Forte */ 211*fcf3ce44SJohn Forte static char * 212*fcf3ce44SJohn Forte getLongOption(int shortOption) 213*fcf3ce44SJohn Forte { 214*fcf3ce44SJohn Forte struct option *op; 215*fcf3ce44SJohn Forte for (op = _longOptions; op->name; op++) { 216*fcf3ce44SJohn Forte if (shortOption == op->val) { 217*fcf3ce44SJohn Forte return (op->name); 218*fcf3ce44SJohn Forte } 219*fcf3ce44SJohn Forte } 220*fcf3ce44SJohn Forte return (NULL); 221*fcf3ce44SJohn Forte } 222*fcf3ce44SJohn Forte 223*fcf3ce44SJohn Forte /* 224*fcf3ce44SJohn Forte * input 225*fcf3ce44SJohn Forte * shortOption - short option character for which to return the 226*fcf3ce44SJohn Forte * option argument 227*fcf3ce44SJohn Forte * Returns: 228*fcf3ce44SJohn Forte * on success, argument string 229*fcf3ce44SJohn Forte * on failure, NULL 230*fcf3ce44SJohn Forte */ 231*fcf3ce44SJohn Forte static char * 232*fcf3ce44SJohn Forte getOptionArgDesc(int shortOption) 233*fcf3ce44SJohn Forte { 234*fcf3ce44SJohn Forte optionTbl_t *op; 235*fcf3ce44SJohn Forte for (op = _clientOptionTbl; op->name; op++) { 236*fcf3ce44SJohn Forte if (op->val == shortOption && 237*fcf3ce44SJohn Forte op->has_arg == required_argument) { 238*fcf3ce44SJohn Forte return (op->argDesc); 239*fcf3ce44SJohn Forte } 240*fcf3ce44SJohn Forte } 241*fcf3ce44SJohn Forte return (NULL); 242*fcf3ce44SJohn Forte } 243*fcf3ce44SJohn Forte 244*fcf3ce44SJohn Forte 245*fcf3ce44SJohn Forte /* 246*fcf3ce44SJohn Forte * Print usage for a subcommand. 247*fcf3ce44SJohn Forte * 248*fcf3ce44SJohn Forte * input: 249*fcf3ce44SJohn Forte * usage type - GENERAL_USAGE, HELP_USAGE, DETAIL_USAGE 250*fcf3ce44SJohn Forte * subcommand - pointer to subcommand_t structure 251*fcf3ce44SJohn Forte * 252*fcf3ce44SJohn Forte * Returns: 253*fcf3ce44SJohn Forte * none 254*fcf3ce44SJohn Forte * 255*fcf3ce44SJohn Forte */ 256*fcf3ce44SJohn Forte static void 257*fcf3ce44SJohn Forte subUsage(uint_t usageType, subcommand_t *subcommand) 258*fcf3ce44SJohn Forte { 259*fcf3ce44SJohn Forte int i; 260*fcf3ce44SJohn Forte object_t *objp; 261*fcf3ce44SJohn Forte 262*fcf3ce44SJohn Forte 263*fcf3ce44SJohn Forte (void) fprintf(stdout, "%s:\t%s %s [", 264*fcf3ce44SJohn Forte gettext("Usage"), commandName, subcommand->name); 265*fcf3ce44SJohn Forte 266*fcf3ce44SJohn Forte for (i = 0; standardSubCmdOptions[i].name; i++) { 267*fcf3ce44SJohn Forte (void) fprintf(stdout, "-%c", 268*fcf3ce44SJohn Forte standardSubCmdOptions[i].val); 269*fcf3ce44SJohn Forte if (standardSubCmdOptions[i+1].name) 270*fcf3ce44SJohn Forte (void) fprintf(stdout, ","); 271*fcf3ce44SJohn Forte } 272*fcf3ce44SJohn Forte 273*fcf3ce44SJohn Forte (void) fprintf(stdout, "] %s [", "<OBJECT>"); 274*fcf3ce44SJohn Forte 275*fcf3ce44SJohn Forte for (i = 0; standardSubCmdOptions[i].name; i++) { 276*fcf3ce44SJohn Forte (void) fprintf(stdout, "-%c", 277*fcf3ce44SJohn Forte standardSubCmdOptions[i].val); 278*fcf3ce44SJohn Forte if (standardSubCmdOptions[i+1].name) 279*fcf3ce44SJohn Forte (void) fprintf(stdout, ","); 280*fcf3ce44SJohn Forte } 281*fcf3ce44SJohn Forte 282*fcf3ce44SJohn Forte (void) fprintf(stdout, "] %s", "[<OPERAND>]"); 283*fcf3ce44SJohn Forte (void) fprintf(stdout, "\n"); 284*fcf3ce44SJohn Forte 285*fcf3ce44SJohn Forte if (usageType == GENERAL_USAGE) { 286*fcf3ce44SJohn Forte return; 287*fcf3ce44SJohn Forte } 288*fcf3ce44SJohn Forte 289*fcf3ce44SJohn Forte (void) fprintf(stdout, "%s:\n", gettext("Usage by OBJECT")); 290*fcf3ce44SJohn Forte 291*fcf3ce44SJohn Forte /* 292*fcf3ce44SJohn Forte * iterate through object table 293*fcf3ce44SJohn Forte * For each object, print appropriate usage 294*fcf3ce44SJohn Forte * based on rules tables 295*fcf3ce44SJohn Forte */ 296*fcf3ce44SJohn Forte for (objp = _objects; objp->value; objp++) { 297*fcf3ce44SJohn Forte subUsageObject(usageType, subcommand, objp); 298*fcf3ce44SJohn Forte } 299*fcf3ce44SJohn Forte (void) atexit(seeMan); 300*fcf3ce44SJohn Forte } 301*fcf3ce44SJohn Forte 302*fcf3ce44SJohn Forte /* 303*fcf3ce44SJohn Forte * Print usage for a subcommand and object. 304*fcf3ce44SJohn Forte * 305*fcf3ce44SJohn Forte * input: 306*fcf3ce44SJohn Forte * usage type - GENERAL_USAGE, HELP_USAGE, DETAIL_USAGE 307*fcf3ce44SJohn Forte * subcommand - pointer to subcommand_t structure 308*fcf3ce44SJohn Forte * objp - pointer to a object_t structure 309*fcf3ce44SJohn Forte * 310*fcf3ce44SJohn Forte * Returns: 311*fcf3ce44SJohn Forte * none 312*fcf3ce44SJohn Forte * 313*fcf3ce44SJohn Forte */ 314*fcf3ce44SJohn Forte static void 315*fcf3ce44SJohn Forte subUsageObject(uint_t usageType, subcommand_t *subcommand, object_t *objp) 316*fcf3ce44SJohn Forte { 317*fcf3ce44SJohn Forte int i; 318*fcf3ce44SJohn Forte objectRules_t *objRules = NULL; 319*fcf3ce44SJohn Forte opCmd_t *opCmd = NULL; 320*fcf3ce44SJohn Forte optionProp_t *options; 321*fcf3ce44SJohn Forte char *optionArgDesc; 322*fcf3ce44SJohn Forte char *longOpt; 323*fcf3ce44SJohn Forte 324*fcf3ce44SJohn Forte 325*fcf3ce44SJohn Forte if (getObjectRules(objp->value, &objRules) != 0) { 326*fcf3ce44SJohn Forte /* 327*fcf3ce44SJohn Forte * internal subcommand rules table error 328*fcf3ce44SJohn Forte * no object entry in object 329*fcf3ce44SJohn Forte */ 330*fcf3ce44SJohn Forte assert(0); 331*fcf3ce44SJohn Forte } 332*fcf3ce44SJohn Forte 333*fcf3ce44SJohn Forte opCmd = &(objRules->opCmd); 334*fcf3ce44SJohn Forte 335*fcf3ce44SJohn Forte if (opCmd->invOpCmd & subcommand->value) { 336*fcf3ce44SJohn Forte return; 337*fcf3ce44SJohn Forte } 338*fcf3ce44SJohn Forte 339*fcf3ce44SJohn Forte options = getOptions(objp->value, subcommand->value); 340*fcf3ce44SJohn Forte 341*fcf3ce44SJohn Forte /* print generic subcommand usage */ 342*fcf3ce44SJohn Forte (void) fprintf(stdout, "\t%s %s ", commandName, subcommand->name); 343*fcf3ce44SJohn Forte 344*fcf3ce44SJohn Forte /* print object */ 345*fcf3ce44SJohn Forte (void) fprintf(stdout, "%s ", objp->name); 346*fcf3ce44SJohn Forte 347*fcf3ce44SJohn Forte /* print options if applicable */ 348*fcf3ce44SJohn Forte if (options != NULL) { 349*fcf3ce44SJohn Forte if (options->required) { 350*fcf3ce44SJohn Forte (void) fprintf(stdout, "%s", gettext("<")); 351*fcf3ce44SJohn Forte } else { 352*fcf3ce44SJohn Forte (void) fprintf(stdout, "%s", gettext("[")); 353*fcf3ce44SJohn Forte } 354*fcf3ce44SJohn Forte (void) fprintf(stdout, "%s", gettext("OPTIONS")); 355*fcf3ce44SJohn Forte if (options->required) { 356*fcf3ce44SJohn Forte (void) fprintf(stdout, "%s ", gettext(">")); 357*fcf3ce44SJohn Forte } else { 358*fcf3ce44SJohn Forte (void) fprintf(stdout, "%s ", gettext("]")); 359*fcf3ce44SJohn Forte } 360*fcf3ce44SJohn Forte } 361*fcf3ce44SJohn Forte 362*fcf3ce44SJohn Forte /* print operand requirements */ 363*fcf3ce44SJohn Forte if (opCmd->optOpCmd & subcommand->value) { 364*fcf3ce44SJohn Forte (void) fprintf(stdout, gettext("[")); 365*fcf3ce44SJohn Forte } 366*fcf3ce44SJohn Forte if (!(opCmd->noOpCmd & subcommand->value)) { 367*fcf3ce44SJohn Forte (void) fprintf(stdout, gettext("<")); 368*fcf3ce44SJohn Forte if (objRules->operandDefinition) { 369*fcf3ce44SJohn Forte (void) fprintf(stdout, "%s", 370*fcf3ce44SJohn Forte objRules->operandDefinition); 371*fcf3ce44SJohn Forte } else { 372*fcf3ce44SJohn Forte /* 373*fcf3ce44SJohn Forte * Missing operand description 374*fcf3ce44SJohn Forte * from table 375*fcf3ce44SJohn Forte */ 376*fcf3ce44SJohn Forte assert(0); 377*fcf3ce44SJohn Forte } 378*fcf3ce44SJohn Forte } 379*fcf3ce44SJohn Forte if (opCmd->multOpCmd & subcommand->value) { 380*fcf3ce44SJohn Forte (void) fprintf(stdout, gettext(" ...")); 381*fcf3ce44SJohn Forte } 382*fcf3ce44SJohn Forte if (!(opCmd->noOpCmd & subcommand->value)) { 383*fcf3ce44SJohn Forte (void) fprintf(stdout, gettext(">")); 384*fcf3ce44SJohn Forte } 385*fcf3ce44SJohn Forte if (opCmd->optOpCmd & subcommand->value) { 386*fcf3ce44SJohn Forte (void) fprintf(stdout, gettext("]")); 387*fcf3ce44SJohn Forte } 388*fcf3ce44SJohn Forte 389*fcf3ce44SJohn Forte if (usageType == HELP_USAGE) { 390*fcf3ce44SJohn Forte (void) fprintf(stdout, "\n"); 391*fcf3ce44SJohn Forte return; 392*fcf3ce44SJohn Forte } 393*fcf3ce44SJohn Forte 394*fcf3ce44SJohn Forte /* print options for subcommand, object */ 395*fcf3ce44SJohn Forte if (options != NULL && options->optionString != NULL) { 396*fcf3ce44SJohn Forte (void) fprintf(stdout, "\n\t%s:", gettext("OPTIONS")); 397*fcf3ce44SJohn Forte for (i = 0; i < strlen(options->optionString); i++) { 398*fcf3ce44SJohn Forte if ((longOpt = getLongOption( 399*fcf3ce44SJohn Forte options->optionString[i])) 400*fcf3ce44SJohn Forte == NULL) { 401*fcf3ce44SJohn Forte /* no long option exists for short option */ 402*fcf3ce44SJohn Forte assert(0); 403*fcf3ce44SJohn Forte } 404*fcf3ce44SJohn Forte (void) fprintf(stdout, "\n\t\t-%c, --%s ", 405*fcf3ce44SJohn Forte options->optionString[i], longOpt); 406*fcf3ce44SJohn Forte optionArgDesc = 407*fcf3ce44SJohn Forte getOptionArgDesc(options->optionString[i]); 408*fcf3ce44SJohn Forte if (optionArgDesc != NULL) { 409*fcf3ce44SJohn Forte (void) fprintf(stdout, "<%s>", optionArgDesc); 410*fcf3ce44SJohn Forte } 411*fcf3ce44SJohn Forte if (options->exclusive && 412*fcf3ce44SJohn Forte strchr(options->exclusive, 413*fcf3ce44SJohn Forte options->optionString[i])) { 414*fcf3ce44SJohn Forte (void) fprintf(stdout, " (%s)", 415*fcf3ce44SJohn Forte gettext("exclusive")); 416*fcf3ce44SJohn Forte } 417*fcf3ce44SJohn Forte } 418*fcf3ce44SJohn Forte } 419*fcf3ce44SJohn Forte (void) fprintf(stdout, "\n"); 420*fcf3ce44SJohn Forte (void) atexit(seeMan); 421*fcf3ce44SJohn Forte } 422*fcf3ce44SJohn Forte 423*fcf3ce44SJohn Forte /* 424*fcf3ce44SJohn Forte * input: 425*fcf3ce44SJohn Forte * type of usage statement to print 426*fcf3ce44SJohn Forte * 427*fcf3ce44SJohn Forte * Returns: 428*fcf3ce44SJohn Forte * return value of subUsage 429*fcf3ce44SJohn Forte */ 430*fcf3ce44SJohn Forte static void 431*fcf3ce44SJohn Forte usage(uint_t usageType) 432*fcf3ce44SJohn Forte { 433*fcf3ce44SJohn Forte int i; 434*fcf3ce44SJohn Forte subcommand_t subcommand; 435*fcf3ce44SJohn Forte subcommand_t *sp; 436*fcf3ce44SJohn Forte 437*fcf3ce44SJohn Forte /* print general command usage */ 438*fcf3ce44SJohn Forte (void) fprintf(stdout, "%s:\t%s ", 439*fcf3ce44SJohn Forte gettext("Usage"), commandName); 440*fcf3ce44SJohn Forte 441*fcf3ce44SJohn Forte for (i = 0; standardCmdOptions[i].name; i++) { 442*fcf3ce44SJohn Forte (void) fprintf(stdout, "-%c", 443*fcf3ce44SJohn Forte standardCmdOptions[i].val); 444*fcf3ce44SJohn Forte if (standardCmdOptions[i+1].name) 445*fcf3ce44SJohn Forte (void) fprintf(stdout, ","); 446*fcf3ce44SJohn Forte } 447*fcf3ce44SJohn Forte 448*fcf3ce44SJohn Forte if (usageType == HELP_USAGE || usageType == GENERAL_USAGE) { 449*fcf3ce44SJohn Forte for (i = 0; standardCmdOptions[i].name; i++) { 450*fcf3ce44SJohn Forte 451*fcf3ce44SJohn Forte 452*fcf3ce44SJohn Forte } 453*fcf3ce44SJohn Forte } 454*fcf3ce44SJohn Forte 455*fcf3ce44SJohn Forte (void) fprintf(stdout, "\n"); 456*fcf3ce44SJohn Forte 457*fcf3ce44SJohn Forte 458*fcf3ce44SJohn Forte /* print all subcommand usage */ 459*fcf3ce44SJohn Forte for (sp = _subcommands; sp->name; sp++) { 460*fcf3ce44SJohn Forte subcommand.name = sp->name; 461*fcf3ce44SJohn Forte subcommand.value = sp->value; 462*fcf3ce44SJohn Forte if (usageType == HELP_USAGE) { 463*fcf3ce44SJohn Forte (void) fprintf(stdout, "\n"); 464*fcf3ce44SJohn Forte } 465*fcf3ce44SJohn Forte subUsage(usageType, &subcommand); 466*fcf3ce44SJohn Forte } 467*fcf3ce44SJohn Forte (void) atexit(seeMan); 468*fcf3ce44SJohn Forte } 469*fcf3ce44SJohn Forte 470*fcf3ce44SJohn Forte /* 471*fcf3ce44SJohn Forte * input: 472*fcf3ce44SJohn Forte * execFullName - exec name of program (argv[0]) 473*fcf3ce44SJohn Forte * 474*fcf3ce44SJohn Forte * Returns: 475*fcf3ce44SJohn Forte * command name portion of execFullName 476*fcf3ce44SJohn Forte */ 477*fcf3ce44SJohn Forte static char * 478*fcf3ce44SJohn Forte getExecBasename(char *execFullname) 479*fcf3ce44SJohn Forte { 480*fcf3ce44SJohn Forte char *lastSlash, *execBasename; 481*fcf3ce44SJohn Forte 482*fcf3ce44SJohn Forte /* guard against '/' at end of command invocation */ 483*fcf3ce44SJohn Forte for (;;) { 484*fcf3ce44SJohn Forte lastSlash = strrchr(execFullname, '/'); 485*fcf3ce44SJohn Forte if (lastSlash == NULL) { 486*fcf3ce44SJohn Forte execBasename = execFullname; 487*fcf3ce44SJohn Forte break; 488*fcf3ce44SJohn Forte } else { 489*fcf3ce44SJohn Forte execBasename = lastSlash + 1; 490*fcf3ce44SJohn Forte if (*execBasename == '\0') { 491*fcf3ce44SJohn Forte *lastSlash = '\0'; 492*fcf3ce44SJohn Forte continue; 493*fcf3ce44SJohn Forte } 494*fcf3ce44SJohn Forte break; 495*fcf3ce44SJohn Forte } 496*fcf3ce44SJohn Forte } 497*fcf3ce44SJohn Forte return (execBasename); 498*fcf3ce44SJohn Forte } 499*fcf3ce44SJohn Forte 500*fcf3ce44SJohn Forte /* 501*fcf3ce44SJohn Forte * cmdParse is a parser that checks syntax of the input command against 502*fcf3ce44SJohn Forte * various rules tables. 503*fcf3ce44SJohn Forte * 504*fcf3ce44SJohn Forte * It provides usage feedback based upon the passed rules tables by calling 505*fcf3ce44SJohn Forte * two usage functions, usage, subUsage, and subUsageObject handling command, 506*fcf3ce44SJohn Forte * subcommand and object usage respectively. 507*fcf3ce44SJohn Forte * 508*fcf3ce44SJohn Forte * When syntax is successfully validated, the associated function is called 509*fcf3ce44SJohn Forte * using the subcommands table functions. 510*fcf3ce44SJohn Forte * 511*fcf3ce44SJohn Forte * Syntax is as follows: 512*fcf3ce44SJohn Forte * command subcommand object [<options>] [<operand>] 513*fcf3ce44SJohn Forte * 514*fcf3ce44SJohn Forte * There are two standard short and long options assumed: 515*fcf3ce44SJohn Forte * -?, --help Provides usage on a command or subcommand 516*fcf3ce44SJohn Forte * and stops further processing of the arguments 517*fcf3ce44SJohn Forte * 518*fcf3ce44SJohn Forte * -V, --version Provides version information on the command 519*fcf3ce44SJohn Forte * and stops further processing of the arguments 520*fcf3ce44SJohn Forte * 521*fcf3ce44SJohn Forte * These options are loaded by this function. 522*fcf3ce44SJohn Forte * 523*fcf3ce44SJohn Forte * input: 524*fcf3ce44SJohn Forte * argc, argv from main 525*fcf3ce44SJohn Forte * syntax rules tables (synTables_t structure) 526*fcf3ce44SJohn Forte * callArgs - void * passed by caller to be passed to subcommand function 527*fcf3ce44SJohn Forte * 528*fcf3ce44SJohn Forte * output: 529*fcf3ce44SJohn Forte * funcRet - pointer to int that holds subcommand function return value 530*fcf3ce44SJohn Forte * 531*fcf3ce44SJohn Forte * Returns: 532*fcf3ce44SJohn Forte * 533*fcf3ce44SJohn Forte * zero on successful syntax parse and function call 534*fcf3ce44SJohn Forte * 535*fcf3ce44SJohn Forte * 1 on unsuccessful syntax parse (no function has been called) 536*fcf3ce44SJohn Forte * This could be due to a version or help call or simply a 537*fcf3ce44SJohn Forte * general usage call. 538*fcf3ce44SJohn Forte * 539*fcf3ce44SJohn Forte * -1 check errno, call failed 540*fcf3ce44SJohn Forte * 541*fcf3ce44SJohn Forte * This module is not MT-safe. 542*fcf3ce44SJohn Forte * 543*fcf3ce44SJohn Forte */ 544*fcf3ce44SJohn Forte int 545*fcf3ce44SJohn Forte cmdParse(int argc, char *argv[], synTables_t synTable, void *callArgs, 546*fcf3ce44SJohn Forte int *funcRet) 547*fcf3ce44SJohn Forte { 548*fcf3ce44SJohn Forte int getoptargc; 549*fcf3ce44SJohn Forte char **getoptargv; 550*fcf3ce44SJohn Forte int opt; 551*fcf3ce44SJohn Forte int operInd; 552*fcf3ce44SJohn Forte int i, j; 553*fcf3ce44SJohn Forte int len; 554*fcf3ce44SJohn Forte char *versionString; 555*fcf3ce44SJohn Forte char optionStringAll[MAXOPTIONSTRING + 1]; 556*fcf3ce44SJohn Forte optionProp_t *availOptions; 557*fcf3ce44SJohn Forte objectRules_t *objRules = NULL; 558*fcf3ce44SJohn Forte opCmd_t *opCmd = NULL; 559*fcf3ce44SJohn Forte subcommand_t *subcommand; 560*fcf3ce44SJohn Forte object_t *object; 561*fcf3ce44SJohn Forte cmdOptions_t cmdOptions[MAXOPTIONS + 1]; 562*fcf3ce44SJohn Forte struct option *lp; 563*fcf3ce44SJohn Forte optionTbl_t *optionTbl; 564*fcf3ce44SJohn Forte struct option intLongOpt[MAXOPTIONS + 1]; 565*fcf3ce44SJohn Forte 566*fcf3ce44SJohn Forte /* 567*fcf3ce44SJohn Forte * Check for NULLs on mandatory input arguments 568*fcf3ce44SJohn Forte * 569*fcf3ce44SJohn Forte * Note: longOptionTbl and optionRulesTbl can be NULL in the case 570*fcf3ce44SJohn Forte * where there is no caller defined options 571*fcf3ce44SJohn Forte * 572*fcf3ce44SJohn Forte */ 573*fcf3ce44SJohn Forte if (synTable.versionString == NULL || 574*fcf3ce44SJohn Forte synTable.subcommandTbl == NULL || 575*fcf3ce44SJohn Forte synTable.objectRulesTbl == NULL || 576*fcf3ce44SJohn Forte synTable.objectTbl == NULL || 577*fcf3ce44SJohn Forte funcRet == NULL) { 578*fcf3ce44SJohn Forte assert(0); 579*fcf3ce44SJohn Forte } 580*fcf3ce44SJohn Forte 581*fcf3ce44SJohn Forte 582*fcf3ce44SJohn Forte versionString = synTable.versionString; 583*fcf3ce44SJohn Forte 584*fcf3ce44SJohn Forte /* set global command name */ 585*fcf3ce44SJohn Forte commandName = getExecBasename(argv[0]); 586*fcf3ce44SJohn Forte 587*fcf3ce44SJohn Forte /* Set unbuffered output */ 588*fcf3ce44SJohn Forte setbuf(stdout, NULL); 589*fcf3ce44SJohn Forte 590*fcf3ce44SJohn Forte /* load globals */ 591*fcf3ce44SJohn Forte _subcommands = synTable.subcommandTbl; 592*fcf3ce44SJohn Forte _objectRules = synTable.objectRulesTbl; 593*fcf3ce44SJohn Forte _optionRules = synTable.optionRulesTbl; 594*fcf3ce44SJohn Forte _objects = synTable.objectTbl; 595*fcf3ce44SJohn Forte _clientOptionTbl = synTable.longOptionTbl; 596*fcf3ce44SJohn Forte 597*fcf3ce44SJohn Forte /* There must be at least two arguments */ 598*fcf3ce44SJohn Forte if (argc < 2) { 599*fcf3ce44SJohn Forte usage(GENERAL_USAGE); 600*fcf3ce44SJohn Forte return (1); 601*fcf3ce44SJohn Forte } 602*fcf3ce44SJohn Forte 603*fcf3ce44SJohn Forte (void) memset(&intLongOpt[0], 0, sizeof (intLongOpt)); 604*fcf3ce44SJohn Forte 605*fcf3ce44SJohn Forte /* 606*fcf3ce44SJohn Forte * load standard subcommand options to internal long options table 607*fcf3ce44SJohn Forte * Two separate getopt_long(3C) tables are used. 608*fcf3ce44SJohn Forte */ 609*fcf3ce44SJohn Forte for (i = 0; standardSubCmdOptions[i].name; i++) { 610*fcf3ce44SJohn Forte intLongOpt[i].name = standardSubCmdOptions[i].name; 611*fcf3ce44SJohn Forte intLongOpt[i].has_arg = standardSubCmdOptions[i].has_arg; 612*fcf3ce44SJohn Forte intLongOpt[i].flag = standardSubCmdOptions[i].flag; 613*fcf3ce44SJohn Forte intLongOpt[i].val = standardSubCmdOptions[i].val; 614*fcf3ce44SJohn Forte } 615*fcf3ce44SJohn Forte 616*fcf3ce44SJohn Forte /* 617*fcf3ce44SJohn Forte * copy caller's long options into internal long options table 618*fcf3ce44SJohn Forte * We do this for two reasons: 619*fcf3ce44SJohn Forte * 1) We need to use the getopt_long option structure internally 620*fcf3ce44SJohn Forte * 2) We need to prepend the table with the standard option 621*fcf3ce44SJohn Forte * for all subcommands (currently -?) 622*fcf3ce44SJohn Forte */ 623*fcf3ce44SJohn Forte for (optionTbl = synTable.longOptionTbl; 624*fcf3ce44SJohn Forte optionTbl && optionTbl->name; optionTbl++, i++) { 625*fcf3ce44SJohn Forte if (i > MAXOPTIONS - 1) { 626*fcf3ce44SJohn Forte /* option table too long */ 627*fcf3ce44SJohn Forte assert(0); 628*fcf3ce44SJohn Forte } 629*fcf3ce44SJohn Forte intLongOpt[i].name = optionTbl->name; 630*fcf3ce44SJohn Forte intLongOpt[i].has_arg = optionTbl->has_arg; 631*fcf3ce44SJohn Forte intLongOpt[i].flag = NULL; 632*fcf3ce44SJohn Forte intLongOpt[i].val = optionTbl->val; 633*fcf3ce44SJohn Forte } 634*fcf3ce44SJohn Forte 635*fcf3ce44SJohn Forte /* set option table global */ 636*fcf3ce44SJohn Forte _longOptions = &intLongOpt[0]; 637*fcf3ce44SJohn Forte 638*fcf3ce44SJohn Forte 639*fcf3ce44SJohn Forte /* 640*fcf3ce44SJohn Forte * Check for help/version request immediately following command 641*fcf3ce44SJohn Forte * '+' in option string ensures POSIX compliance in getopt_long() 642*fcf3ce44SJohn Forte * which means that processing will stop at first non-option 643*fcf3ce44SJohn Forte * argument. 644*fcf3ce44SJohn Forte */ 645*fcf3ce44SJohn Forte while ((opt = getopt_long(argc, argv, "+?V", standardCmdOptions, 646*fcf3ce44SJohn Forte NULL)) != EOF) { 647*fcf3ce44SJohn Forte switch (opt) { 648*fcf3ce44SJohn Forte case '?': 649*fcf3ce44SJohn Forte /* 650*fcf3ce44SJohn Forte * getopt can return a '?' when no 651*fcf3ce44SJohn Forte * option letters match string. Check for 652*fcf3ce44SJohn Forte * the 'real' '?' in optopt. 653*fcf3ce44SJohn Forte */ 654*fcf3ce44SJohn Forte if (optopt == '?') { 655*fcf3ce44SJohn Forte usage(HELP_USAGE); 656*fcf3ce44SJohn Forte return (0); 657*fcf3ce44SJohn Forte } else { 658*fcf3ce44SJohn Forte usage(GENERAL_USAGE); 659*fcf3ce44SJohn Forte return (0); 660*fcf3ce44SJohn Forte } 661*fcf3ce44SJohn Forte case 'V': 662*fcf3ce44SJohn Forte (void) fprintf(stdout, "%s: %s %s\n", 663*fcf3ce44SJohn Forte commandName, gettext("Version"), 664*fcf3ce44SJohn Forte versionString); 665*fcf3ce44SJohn Forte (void) atexit(seeMan); 666*fcf3ce44SJohn Forte return (0); 667*fcf3ce44SJohn Forte default: 668*fcf3ce44SJohn Forte break; 669*fcf3ce44SJohn Forte } 670*fcf3ce44SJohn Forte } 671*fcf3ce44SJohn Forte 672*fcf3ce44SJohn Forte /* 673*fcf3ce44SJohn Forte * subcommand is always in the second argument. If there is no 674*fcf3ce44SJohn Forte * recognized subcommand in the second argument, print error, 675*fcf3ce44SJohn Forte * general usage and then return. 676*fcf3ce44SJohn Forte */ 677*fcf3ce44SJohn Forte if (getSubcommand(argv[1], &subcommand) != 0) { 678*fcf3ce44SJohn Forte (void) fprintf(stderr, "%s: %s\n", 679*fcf3ce44SJohn Forte commandName, gettext("invalid subcommand")); 680*fcf3ce44SJohn Forte usage(GENERAL_USAGE); 681*fcf3ce44SJohn Forte return (1); 682*fcf3ce44SJohn Forte } 683*fcf3ce44SJohn Forte 684*fcf3ce44SJohn Forte if (argc == 2) { 685*fcf3ce44SJohn Forte (void) fprintf(stderr, "%s: %s\n", 686*fcf3ce44SJohn Forte commandName, gettext("missing object")); 687*fcf3ce44SJohn Forte subUsage(GENERAL_USAGE, subcommand); 688*fcf3ce44SJohn Forte (void) atexit(seeMan); 689*fcf3ce44SJohn Forte return (1); 690*fcf3ce44SJohn Forte } 691*fcf3ce44SJohn Forte 692*fcf3ce44SJohn Forte getoptargv = argv; 693*fcf3ce44SJohn Forte getoptargv++; 694*fcf3ce44SJohn Forte getoptargc = argc; 695*fcf3ce44SJohn Forte getoptargc -= 1; 696*fcf3ce44SJohn Forte 697*fcf3ce44SJohn Forte while ((opt = getopt_long(getoptargc, getoptargv, "+?", 698*fcf3ce44SJohn Forte standardSubCmdOptions, NULL)) != EOF) { 699*fcf3ce44SJohn Forte switch (opt) { 700*fcf3ce44SJohn Forte case '?': 701*fcf3ce44SJohn Forte /* 702*fcf3ce44SJohn Forte * getopt can return a '?' when no 703*fcf3ce44SJohn Forte * option letters match string. Check for 704*fcf3ce44SJohn Forte * the 'real' '?' in optopt. 705*fcf3ce44SJohn Forte */ 706*fcf3ce44SJohn Forte if (optopt == '?') { 707*fcf3ce44SJohn Forte subUsage(HELP_USAGE, subcommand); 708*fcf3ce44SJohn Forte return (0); 709*fcf3ce44SJohn Forte } else { 710*fcf3ce44SJohn Forte subUsage(GENERAL_USAGE, subcommand); 711*fcf3ce44SJohn Forte return (0); 712*fcf3ce44SJohn Forte } 713*fcf3ce44SJohn Forte default: 714*fcf3ce44SJohn Forte break; 715*fcf3ce44SJohn Forte } 716*fcf3ce44SJohn Forte } 717*fcf3ce44SJohn Forte 718*fcf3ce44SJohn Forte 719*fcf3ce44SJohn Forte /* 720*fcf3ce44SJohn Forte * object is always in the third argument. If there is no 721*fcf3ce44SJohn Forte * recognized object in the third argument, print error, 722*fcf3ce44SJohn Forte * help usage for the subcommand and then return. 723*fcf3ce44SJohn Forte */ 724*fcf3ce44SJohn Forte if (getObject(argv[2], &object) != 0) { 725*fcf3ce44SJohn Forte (void) fprintf(stderr, "%s: %s\n", 726*fcf3ce44SJohn Forte commandName, gettext("invalid object")); 727*fcf3ce44SJohn Forte subUsage(HELP_USAGE, subcommand); 728*fcf3ce44SJohn Forte return (1); 729*fcf3ce44SJohn Forte 730*fcf3ce44SJohn Forte } 731*fcf3ce44SJohn Forte 732*fcf3ce44SJohn Forte if (getObjectRules(object->value, &objRules) != 0) { 733*fcf3ce44SJohn Forte /* 734*fcf3ce44SJohn Forte * internal subcommand rules table error 735*fcf3ce44SJohn Forte * no object entry in object table 736*fcf3ce44SJohn Forte */ 737*fcf3ce44SJohn Forte assert(0); 738*fcf3ce44SJohn Forte } 739*fcf3ce44SJohn Forte 740*fcf3ce44SJohn Forte opCmd = &(objRules->opCmd); 741*fcf3ce44SJohn Forte 742*fcf3ce44SJohn Forte /* 743*fcf3ce44SJohn Forte * Is command valid for this object? 744*fcf3ce44SJohn Forte */ 745*fcf3ce44SJohn Forte if (opCmd->invOpCmd & subcommand->value) { 746*fcf3ce44SJohn Forte (void) fprintf(stderr, "%s: %s %s\n", commandName, 747*fcf3ce44SJohn Forte gettext("invalid subcommand for"), object->name); 748*fcf3ce44SJohn Forte subUsage(HELP_USAGE, subcommand); 749*fcf3ce44SJohn Forte return (1); 750*fcf3ce44SJohn Forte } 751*fcf3ce44SJohn Forte 752*fcf3ce44SJohn Forte /* 753*fcf3ce44SJohn Forte * offset getopt arg begin since 754*fcf3ce44SJohn Forte * getopt(3C) assumes options 755*fcf3ce44SJohn Forte * follow first argument 756*fcf3ce44SJohn Forte */ 757*fcf3ce44SJohn Forte getoptargv = argv; 758*fcf3ce44SJohn Forte getoptargv++; 759*fcf3ce44SJohn Forte getoptargv++; 760*fcf3ce44SJohn Forte getoptargc = argc; 761*fcf3ce44SJohn Forte getoptargc -= 2; 762*fcf3ce44SJohn Forte 763*fcf3ce44SJohn Forte (void) memset(optionStringAll, 0, sizeof (optionStringAll)); 764*fcf3ce44SJohn Forte (void) memset(&cmdOptions[0], 0, sizeof (cmdOptions)); 765*fcf3ce44SJohn Forte 766*fcf3ce44SJohn Forte j = 0; 767*fcf3ce44SJohn Forte /* 768*fcf3ce44SJohn Forte * Build optionStringAll from long options table 769*fcf3ce44SJohn Forte */ 770*fcf3ce44SJohn Forte for (lp = _longOptions; lp->name; lp++, j++) { 771*fcf3ce44SJohn Forte /* sanity check on string length */ 772*fcf3ce44SJohn Forte if (j + 1 >= sizeof (optionStringAll)) { 773*fcf3ce44SJohn Forte /* option table too long */ 774*fcf3ce44SJohn Forte assert(0); 775*fcf3ce44SJohn Forte } 776*fcf3ce44SJohn Forte optionStringAll[j] = lp->val; 777*fcf3ce44SJohn Forte if (lp->has_arg == required_argument) { 778*fcf3ce44SJohn Forte optionStringAll[++j] = ':'; 779*fcf3ce44SJohn Forte } 780*fcf3ce44SJohn Forte } 781*fcf3ce44SJohn Forte 782*fcf3ce44SJohn Forte i = 0; 783*fcf3ce44SJohn Forte /* 784*fcf3ce44SJohn Forte * Run getopt for all arguments against all possible options 785*fcf3ce44SJohn Forte * Store all options/option arguments in an array for retrieval 786*fcf3ce44SJohn Forte * later. 787*fcf3ce44SJohn Forte * Once all options are retrieved, check against object 788*fcf3ce44SJohn Forte * and subcommand (option rules table) for validity. 789*fcf3ce44SJohn Forte * This is done later. 790*fcf3ce44SJohn Forte */ 791*fcf3ce44SJohn Forte while ((opt = getopt_long(getoptargc, getoptargv, optionStringAll, 792*fcf3ce44SJohn Forte _longOptions, NULL)) != EOF) { 793*fcf3ce44SJohn Forte switch (opt) { 794*fcf3ce44SJohn Forte case '?': 795*fcf3ce44SJohn Forte if (optopt == '?') { 796*fcf3ce44SJohn Forte subUsageObject(DETAIL_USAGE, 797*fcf3ce44SJohn Forte subcommand, object); 798*fcf3ce44SJohn Forte return (0); 799*fcf3ce44SJohn Forte } else { 800*fcf3ce44SJohn Forte subUsage(GENERAL_USAGE, subcommand); 801*fcf3ce44SJohn Forte return (0); 802*fcf3ce44SJohn Forte } 803*fcf3ce44SJohn Forte default: 804*fcf3ce44SJohn Forte cmdOptions[i].optval = opt; 805*fcf3ce44SJohn Forte if (optarg) { 806*fcf3ce44SJohn Forte len = strlen(optarg); 807*fcf3ce44SJohn Forte if (len > sizeof (cmdOptions[i].optarg) 808*fcf3ce44SJohn Forte - 1) { 809*fcf3ce44SJohn Forte (void) fprintf(stderr, 810*fcf3ce44SJohn Forte "%s: %s\n", 811*fcf3ce44SJohn Forte commandName, 812*fcf3ce44SJohn Forte gettext("option too long")); 813*fcf3ce44SJohn Forte errno = EINVAL; 814*fcf3ce44SJohn Forte return (-1); 815*fcf3ce44SJohn Forte } 816*fcf3ce44SJohn Forte (void) strncpy(cmdOptions[i].optarg, 817*fcf3ce44SJohn Forte optarg, len); 818*fcf3ce44SJohn Forte } 819*fcf3ce44SJohn Forte i++; 820*fcf3ce44SJohn Forte break; 821*fcf3ce44SJohn Forte } 822*fcf3ce44SJohn Forte } 823*fcf3ce44SJohn Forte 824*fcf3ce44SJohn Forte /* 825*fcf3ce44SJohn Forte * increment past last option 826*fcf3ce44SJohn Forte */ 827*fcf3ce44SJohn Forte operInd = optind + 2; 828*fcf3ce44SJohn Forte 829*fcf3ce44SJohn Forte /* 830*fcf3ce44SJohn Forte * Check validity of given options, if any were given 831*fcf3ce44SJohn Forte */ 832*fcf3ce44SJohn Forte 833*fcf3ce44SJohn Forte /* get option string for this object and subcommand */ 834*fcf3ce44SJohn Forte availOptions = getOptions(object->value, subcommand->value); 835*fcf3ce44SJohn Forte 836*fcf3ce44SJohn Forte if (cmdOptions[0].optval != 0) { /* options were input */ 837*fcf3ce44SJohn Forte if (availOptions == NULL) { /* no options permitted */ 838*fcf3ce44SJohn Forte (void) fprintf(stderr, "%s: %s\n", 839*fcf3ce44SJohn Forte commandName, gettext("no options permitted")); 840*fcf3ce44SJohn Forte subUsageObject(HELP_USAGE, subcommand, object); 841*fcf3ce44SJohn Forte return (1); 842*fcf3ce44SJohn Forte } 843*fcf3ce44SJohn Forte for (i = 0; cmdOptions[i].optval; i++) { 844*fcf3ce44SJohn Forte /* Check for invalid options */ 845*fcf3ce44SJohn Forte if (availOptions->optionString == NULL) { 846*fcf3ce44SJohn Forte /* 847*fcf3ce44SJohn Forte * internal option table error 848*fcf3ce44SJohn Forte * There must be an option string if 849*fcf3ce44SJohn Forte * there is an entry in the table 850*fcf3ce44SJohn Forte */ 851*fcf3ce44SJohn Forte assert(0); 852*fcf3ce44SJohn Forte } 853*fcf3ce44SJohn Forte /* is the option in the available option string? */ 854*fcf3ce44SJohn Forte 855*fcf3ce44SJohn Forte if (!(strchr(availOptions->optionString, 856*fcf3ce44SJohn Forte cmdOptions[i].optval))) { 857*fcf3ce44SJohn Forte (void) fprintf(stderr, 858*fcf3ce44SJohn Forte "%s: '-%c': %s\n", 859*fcf3ce44SJohn Forte commandName, cmdOptions[i].optval, 860*fcf3ce44SJohn Forte gettext("invalid option")); 861*fcf3ce44SJohn Forte subUsageObject(DETAIL_USAGE, subcommand, 862*fcf3ce44SJohn Forte object); 863*fcf3ce44SJohn Forte return (1); 864*fcf3ce44SJohn Forte 865*fcf3ce44SJohn Forte /* Check for exclusive options */ 866*fcf3ce44SJohn Forte } else if (cmdOptions[1].optval != 0 && 867*fcf3ce44SJohn Forte 868*fcf3ce44SJohn Forte availOptions->exclusive && 869*fcf3ce44SJohn Forte strchr(availOptions->exclusive, 870*fcf3ce44SJohn Forte cmdOptions[i].optval)) { 871*fcf3ce44SJohn Forte 872*fcf3ce44SJohn Forte (void) fprintf(stderr, 873*fcf3ce44SJohn Forte 874*fcf3ce44SJohn Forte "%s: '-%c': %s\n", 875*fcf3ce44SJohn Forte commandName, cmdOptions[i].optval, 876*fcf3ce44SJohn Forte gettext("is an exclusive option")); 877*fcf3ce44SJohn Forte 878*fcf3ce44SJohn Forte subUsageObject(DETAIL_USAGE, subcommand, 879*fcf3ce44SJohn Forte object); 880*fcf3ce44SJohn Forte return (1); 881*fcf3ce44SJohn Forte } 882*fcf3ce44SJohn Forte } 883*fcf3ce44SJohn Forte } else { /* no options were input */ 884*fcf3ce44SJohn Forte if (availOptions != NULL && 885*fcf3ce44SJohn Forte (availOptions->required)) { 886*fcf3ce44SJohn Forte (void) fprintf(stderr, "%s: %s\n", 887*fcf3ce44SJohn Forte commandName, 888*fcf3ce44SJohn Forte gettext("at least one option required")); 889*fcf3ce44SJohn Forte 890*fcf3ce44SJohn Forte subUsageObject(DETAIL_USAGE, subcommand, 891*fcf3ce44SJohn Forte object); 892*fcf3ce44SJohn Forte return (1); 893*fcf3ce44SJohn Forte } 894*fcf3ce44SJohn Forte } 895*fcf3ce44SJohn Forte 896*fcf3ce44SJohn Forte /* 897*fcf3ce44SJohn Forte * If there are no more arguments (operands), 898*fcf3ce44SJohn Forte * check to see if this is okay 899*fcf3ce44SJohn Forte */ 900*fcf3ce44SJohn Forte if ((operInd == argc) && 901*fcf3ce44SJohn Forte (opCmd->reqOpCmd & subcommand->value)) { 902*fcf3ce44SJohn Forte (void) fprintf(stderr, "%s: %s %s %s\n", 903*fcf3ce44SJohn Forte commandName, subcommand->name, 904*fcf3ce44SJohn Forte object->name, gettext("requires an operand")); 905*fcf3ce44SJohn Forte 906*fcf3ce44SJohn Forte subUsageObject(HELP_USAGE, subcommand, object); 907*fcf3ce44SJohn Forte (void) atexit(seeMan); 908*fcf3ce44SJohn Forte return (1); 909*fcf3ce44SJohn Forte } 910*fcf3ce44SJohn Forte 911*fcf3ce44SJohn Forte /* 912*fcf3ce44SJohn Forte * If there are more operands, 913*fcf3ce44SJohn Forte * check to see if this is okay 914*fcf3ce44SJohn Forte */ 915*fcf3ce44SJohn Forte if ((argc > operInd) && 916*fcf3ce44SJohn Forte (opCmd->noOpCmd & subcommand->value)) { 917*fcf3ce44SJohn Forte (void) fprintf(stderr, "%s: %s %s %s\n", 918*fcf3ce44SJohn Forte commandName, subcommand->name, 919*fcf3ce44SJohn Forte object->name, gettext("takes no operands")); 920*fcf3ce44SJohn Forte subUsageObject(HELP_USAGE, subcommand, object); 921*fcf3ce44SJohn Forte return (1); 922*fcf3ce44SJohn Forte } 923*fcf3ce44SJohn Forte 924*fcf3ce44SJohn Forte /* 925*fcf3ce44SJohn Forte * If there is more than one more operand, 926*fcf3ce44SJohn Forte * check to see if this is okay 927*fcf3ce44SJohn Forte */ 928*fcf3ce44SJohn Forte if ((argc > operInd) && ((argc - operInd) != 1) && 929*fcf3ce44SJohn Forte !(opCmd->multOpCmd & subcommand->value)) { 930*fcf3ce44SJohn Forte (void) fprintf(stderr, "%s: %s %s %s\n", 931*fcf3ce44SJohn Forte commandName, subcommand->name, object->name, 932*fcf3ce44SJohn Forte gettext("accepts only a single operand")); 933*fcf3ce44SJohn Forte subUsageObject(HELP_USAGE, subcommand, object); 934*fcf3ce44SJohn Forte return (1); 935*fcf3ce44SJohn Forte } 936*fcf3ce44SJohn Forte 937*fcf3ce44SJohn Forte /* Finished syntax checks */ 938*fcf3ce44SJohn Forte 939*fcf3ce44SJohn Forte 940*fcf3ce44SJohn Forte /* Call appropriate function */ 941*fcf3ce44SJohn Forte 942*fcf3ce44SJohn Forte return (subcommand->handler(argc - operInd, &argv[operInd], 943*fcf3ce44SJohn Forte object->value, &cmdOptions[0], callArgs, funcRet)); 944*fcf3ce44SJohn Forte } 945