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
getSubcommandProps(char * subCommand,subCommandProps_t ** subCommandProps)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 *
getLongOption(int shortOption)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 *
getOptionArgDesc(int shortOption)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
subUsage(uint_t usageType,subCommandProps_t * subcommand)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
usage(uint_t usageType)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 *
getExecBasename(char * execFullname)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
cmdParse(int argc,char * argv[],synTables_t synTable,void * callArgs,int * funcRet)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