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