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