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