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