9813 isainfo should learn about SHA Instrs
[unleashed.git] / usr / src / common / cmdparse / cmdparse.c
blob7a9e575d716dd85245178169496d11dcc48a4bda
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <libintl.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <assert.h>
34 #include <getopt.h>
35 #include <cmdparse.h>
38 /* Usage types */
39 #define GENERAL_USAGE 1
40 #define DETAIL_USAGE 2
42 /* printable ascii character set len */
43 #define MAXOPTIONS (uint_t)('~' - '!' + 1)
46 * MAXOPTIONSTRING is the max length of the options string used in getopt and
47 * will be the printable character set + ':' for each character,
48 * providing for options with arguments. e.g. "t:Cs:hglr:"
50 #define MAXOPTIONSTRING MAXOPTIONS * 2
52 /* standard command options table to support -?, -V */
53 struct option standardCmdOptions[] = {
54 {"help", no_argument, NULL, '?'},
55 {"version", no_argument, NULL, 'V'},
56 {NULL, 0, NULL, 0}
59 /* standard subcommand options table to support -? */
60 struct option standardSubCmdOptions[] = {
61 {"help", no_argument, NULL, '?'},
62 {NULL, 0, NULL, 0}
65 /* forward declarations */
66 static int getSubcommandProps(char *, subCommandProps_t **);
67 static char *getExecBasename(char *);
68 static void usage(uint_t);
69 static void subUsage(uint_t, subCommandProps_t *);
70 static char *getLongOption(int);
71 static char *getOptionArgDesc(int);
73 /* global data */
74 static struct option *_longOptions;
75 static subCommandProps_t *_subCommandProps;
76 static optionTbl_t *_clientOptionTbl;
77 static char *commandName;
81 * input:
82 * subCommand - subcommand value
83 * output:
84 * subCommandProps - pointer to subCommandProps_t structure allocated by caller
86 * On successful return, subCommandProps contains the properties for the value
87 * in subCommand. On failure, the contents of subCommandProps is unspecified.
89 * Returns:
90 * zero on success
91 * non-zero on failure
94 static int
95 getSubcommandProps(char *subCommand, subCommandProps_t **subCommandProps)
97 subCommandProps_t *sp;
98 int len;
100 for (sp = _subCommandProps; sp->name; sp++) {
101 len = strlen(subCommand);
102 if (len == strlen(sp->name) &&
103 strncasecmp(subCommand, sp->name, len) == 0) {
104 *subCommandProps = sp;
105 return (0);
108 return (1);
112 * input:
113 * shortOption - short option character for which to return the
114 * associated long option string
116 * Returns:
117 * on success, long option name
118 * on failure, NULL
120 static char *
121 getLongOption(int shortOption)
123 struct option *op;
124 for (op = _longOptions; op->name; op++) {
125 if (shortOption == op->val) {
126 return (op->name);
129 return (NULL);
133 * input
134 * shortOption - short option character for which to return the
135 * option argument
136 * Returns:
137 * on success, argument string
138 * on failure, NULL
140 static char *
141 getOptionArgDesc(int shortOption)
143 optionTbl_t *op;
144 for (op = _clientOptionTbl; op->name; op++) {
145 if (op->val == shortOption &&
146 op->has_arg == required_argument) {
147 return (op->argDesc);
150 return (NULL);
155 * Print usage for a subcommand.
157 * input:
158 * usage type - GENERAL_USAGE, DETAIL_USAGE
159 * subcommand - pointer to subCommandProps_t structure
161 * Returns:
162 * none
165 static void
166 subUsage(uint_t usageType, subCommandProps_t *subcommand)
168 int i;
169 char *optionArgDesc;
170 char *longOpt;
172 if (usageType == GENERAL_USAGE) {
173 (void) printf("%s:\t%s %s [", gettext("Usage"), commandName,
174 subcommand->name);
175 for (i = 0; standardSubCmdOptions[i].name; i++) {
176 (void) printf("-%c", standardSubCmdOptions[i].val);
177 if (standardSubCmdOptions[i+1].name)
178 (void) printf(",");
180 (void) fprintf(stdout, "]\n");
181 return;
184 /* print subcommand usage */
185 (void) printf("\n%s:\t%s %s ", gettext("Usage"), commandName,
186 subcommand->name);
188 /* print options if applicable */
189 if (subcommand->optionString != NULL) {
190 if (subcommand->required) {
191 (void) printf("%s", gettext("<"));
192 } else {
193 (void) printf("%s", gettext("["));
195 (void) printf("%s", gettext("OPTIONS"));
196 if (subcommand->required) {
197 (void) printf("%s ", gettext(">"));
198 } else {
199 (void) printf("%s ", gettext("]"));
203 /* print operand requirements */
204 if (!(subcommand->operand & OPERAND_NONE) &&
205 !(subcommand->operand & OPERAND_MANDATORY)) {
206 (void) printf(gettext("["));
209 if (subcommand->operand & OPERAND_MANDATORY) {
210 (void) printf(gettext("<"));
213 if (!(subcommand->operand & OPERAND_NONE)) {
214 assert(subcommand->operandDefinition);
215 (void) printf("%s", subcommand->operandDefinition);
218 if (subcommand->operand & OPERAND_MULTIPLE) {
219 (void) printf(gettext(" ..."));
222 if (subcommand->operand & OPERAND_MANDATORY) {
223 (void) printf(gettext(">"));
226 if (!(subcommand->operand & OPERAND_NONE) &&
227 !(subcommand->operand & OPERAND_MANDATORY)) {
228 (void) printf(gettext("]"));
231 /* print options for subcommand */
232 if (subcommand->optionString != NULL) {
233 (void) printf("\n\t%s:", gettext("OPTIONS"));
234 for (i = 0; i < strlen(subcommand->optionString); i++) {
235 assert((longOpt = getLongOption(
236 subcommand->optionString[i])) != NULL);
237 (void) printf("\n\t\t-%c, --%s ",
238 subcommand->optionString[i],
239 longOpt);
240 optionArgDesc =
241 getOptionArgDesc(subcommand->optionString[i]);
242 if (optionArgDesc != NULL) {
243 (void) printf("<%s>", optionArgDesc);
245 if (subcommand->exclusive &&
246 strchr(subcommand->exclusive,
247 subcommand->optionString[i])) {
248 (void) printf(" (%s)", gettext("exclusive"));
252 (void) fprintf(stdout, "\n");
253 if (subcommand->helpText) {
254 (void) printf("%s\n", subcommand->helpText);
259 * input:
260 * type of usage statement to print
262 * Returns:
263 * return value of subUsage
265 static void
266 usage(uint_t usageType)
268 int i;
269 subCommandProps_t *sp;
271 /* print general command usage */
272 (void) printf("%s:\t%s ", gettext("Usage"), commandName);
274 for (i = 0; standardCmdOptions[i].name; i++) {
275 (void) printf("-%c", standardCmdOptions[i].val);
276 if (standardCmdOptions[i+1].name)
277 (void) printf(",");
280 if (usageType == GENERAL_USAGE) {
281 for (i = 0; standardSubCmdOptions[i].name; i++) {
282 (void) printf(",--%s", standardSubCmdOptions[i].name);
283 if (standardSubCmdOptions[i+1].name)
284 (void) printf(",");
288 (void) fprintf(stdout, "\n");
291 /* print all subcommand usage */
292 for (sp = _subCommandProps; sp->name; sp++) {
293 subUsage(usageType, sp);
298 * input:
299 * execFullName - exec name of program (argv[0])
301 * Returns:
302 * command name portion of execFullName
304 static char *
305 getExecBasename(char *execFullname)
307 char *lastSlash, *execBasename;
309 /* guard against '/' at end of command invocation */
310 for (;;) {
311 lastSlash = strrchr(execFullname, '/');
312 if (lastSlash == NULL) {
313 execBasename = execFullname;
314 break;
315 } else {
316 execBasename = lastSlash + 1;
317 if (*execBasename == '\0') {
318 *lastSlash = '\0';
319 continue;
321 break;
324 return (execBasename);
328 * cmdParse is a parser that checks syntax of the input command against
329 * various rules tables.
331 * It provides usage feedback based upon the passed rules tables by calling
332 * two usage functions, usage, subUsage
334 * When syntax is successfully validated, the associated function is called
335 * using the subcommands table functions.
337 * Syntax is as follows:
338 * command subcommand [<options>] [<operand>]
340 * There are two standard short and long options assumed:
341 * -?, --help Provides usage on a command or subcommand
342 * and stops further processing of the arguments
344 * -V, --version Provides version information on the command
345 * and stops further processing of the arguments
347 * These options are loaded by this function.
349 * input:
350 * argc, argv from main
351 * syntax rules tables (synTables_t structure)
352 * callArgs - void * passed by caller to be passed to subcommand function
354 * output:
355 * funcRet - pointer to int that holds subcommand function return value
357 * Returns:
359 * zero on successful syntax parse and function call
361 * 1 on unsuccessful syntax parse (no function has been called)
362 * This could be due to a version or help call or simply a
363 * general usage call.
365 * -1 check errno, call failed
367 * This module is not MT-safe.
371 cmdParse(int argc, char *argv[], synTables_t synTable, void *callArgs,
372 int *funcRet)
374 int getoptargc;
375 char **getoptargv;
376 int opt;
377 int operInd;
378 int i, j;
379 int len;
380 int requiredOptionCnt = 0, requiredOptionEntered = 0;
381 char *availOptions;
382 char *versionString;
383 char optionStringAll[MAXOPTIONSTRING + 1];
384 subCommandProps_t *subcommand;
385 cmdOptions_t cmdOptions[MAXOPTIONS + 1];
386 optionTbl_t *optionTbl;
387 struct option *lp;
388 struct option intLongOpt[MAXOPTIONS + 1];
391 * Check for NULLs on mandatory input arguments
393 * Note: longOptionTbl can be NULL in the case
394 * where there is no caller defined options
397 assert(synTable.versionString);
398 assert(synTable.subCommandPropsTbl);
399 assert(funcRet);
401 versionString = synTable.versionString;
403 /* set global command name */
404 commandName = getExecBasename(argv[0]);
406 /* Set unbuffered output */
407 setbuf(stdout, NULL);
409 /* load globals */
410 _subCommandProps = synTable.subCommandPropsTbl;
411 _clientOptionTbl = synTable.longOptionTbl;
413 /* There must be at least two arguments */
414 if (argc < 2) {
415 usage(GENERAL_USAGE);
416 return (1);
419 (void) memset(&intLongOpt[0], 0, sizeof (intLongOpt));
422 * load standard subcommand options to internal long options table
423 * Two separate getopt_long(3C) tables are used.
425 for (i = 0; standardSubCmdOptions[i].name; i++) {
426 intLongOpt[i].name = standardSubCmdOptions[i].name;
427 intLongOpt[i].has_arg = standardSubCmdOptions[i].has_arg;
428 intLongOpt[i].flag = standardSubCmdOptions[i].flag;
429 intLongOpt[i].val = standardSubCmdOptions[i].val;
433 * copy caller's long options into internal long options table
434 * We do this for two reasons:
435 * 1) We need to use the getopt_long option structure internally
436 * 2) We need to prepend the table with the standard option
437 * for all subcommands (currently -?)
439 for (optionTbl = synTable.longOptionTbl;
440 optionTbl && optionTbl->name; optionTbl++, i++) {
441 if (i > MAXOPTIONS - 1) {
442 /* option table too long */
443 assert(0);
445 intLongOpt[i].name = optionTbl->name;
446 intLongOpt[i].has_arg = optionTbl->has_arg;
447 intLongOpt[i].flag = NULL;
448 intLongOpt[i].val = optionTbl->val;
451 /* set option table global */
452 _longOptions = &intLongOpt[0];
456 * Check for help/version request immediately following command
457 * '+' in option string ensures POSIX compliance in getopt_long()
458 * which means that processing will stop at first non-option
459 * argument.
461 while ((opt = getopt_long(argc, argv, "+?V", standardCmdOptions,
462 NULL)) != EOF) {
463 switch (opt) {
464 case '?':
466 * getopt can return a '?' when no
467 * option letters match string. Check for
468 * the 'real' '?' in optopt.
470 if (optopt == '?') {
471 usage(DETAIL_USAGE);
472 exit(0);
473 } else {
474 usage(GENERAL_USAGE);
475 return (1);
477 break;
478 case 'V':
479 (void) fprintf(stdout, "%s: %s %s\n",
480 commandName, gettext("Version"),
481 versionString);
482 exit(0);
483 break;
484 default:
485 break;
490 * subcommand is always in the second argument. If there is no
491 * recognized subcommand in the second argument, print error,
492 * general usage and then return.
494 if (getSubcommandProps(argv[1], &subcommand) != 0) {
495 (void) printf("%s: %s\n", commandName,
496 gettext("invalid subcommand"));
497 usage(GENERAL_USAGE);
498 return (1);
501 getoptargv = argv;
502 getoptargv++;
503 getoptargc = argc;
504 getoptargc -= 1;
506 (void) memset(optionStringAll, 0, sizeof (optionStringAll));
507 (void) memset(&cmdOptions[0], 0, sizeof (cmdOptions));
509 j = 0;
511 * Build optionStringAll from long options table
513 for (lp = _longOptions; lp->name; lp++, j++) {
514 /* sanity check on string length */
515 if (j + 1 >= sizeof (optionStringAll)) {
516 /* option table too long */
517 assert(0);
519 optionStringAll[j] = lp->val;
520 if (lp->has_arg == required_argument) {
521 optionStringAll[++j] = ':';
525 i = 0;
527 * Run getopt for all arguments against all possible options
528 * Store all options/option arguments in an array for retrieval
529 * later.
531 * Once all options are retrieved, a validity check against
532 * subcommand table is performed.
534 while ((opt = getopt_long(getoptargc, getoptargv, optionStringAll,
535 _longOptions, NULL)) != EOF) {
536 switch (opt) {
537 case '?':
538 subUsage(DETAIL_USAGE, subcommand);
540 * getopt can return a '?' when no
541 * option letters match string. Check for
542 * the 'real' '?' in optopt.
544 if (optopt == '?') {
545 exit(0);
546 } else {
547 exit(1);
549 default:
550 cmdOptions[i].optval = opt;
551 if (optarg) {
552 len = strlen(optarg);
553 if (len > sizeof (cmdOptions[i].optarg)
554 - 1) {
555 (void) printf("%s: %s\n",
556 commandName,
557 gettext("option too long"));
558 errno = EINVAL;
559 return (-1);
561 (void) strncpy(cmdOptions[i].optarg,
562 optarg, len);
564 i++;
565 break;
570 * increment past last option
572 operInd = optind + 1;
575 * Check validity of given options, if any were given
578 /* get option string for this subcommand */
579 availOptions = subcommand->optionString;
581 /* Get count of required options */
582 if (subcommand->required) {
583 requiredOptionCnt = strlen(subcommand->required);
586 if (cmdOptions[0].optval != 0) { /* options were input */
587 if (availOptions == NULL) { /* no options permitted */
588 (void) printf("%s: %s\n", commandName,
589 gettext("no options permitted"));
590 subUsage(DETAIL_USAGE, subcommand);
591 return (1);
593 for (i = 0; cmdOptions[i].optval; i++) {
594 /* is the option in the available option string? */
595 if (!(strchr(availOptions, cmdOptions[i].optval))) {
596 (void) printf("%s: '-%c': %s\n", commandName,
597 cmdOptions[i].optval,
598 gettext("invalid option"));
599 subUsage(DETAIL_USAGE, subcommand);
600 return (1);
601 /* increment required options entered */
602 } else if (subcommand->required &&
603 (strchr(subcommand->required,
604 cmdOptions[i].optval))) {
605 requiredOptionEntered++;
606 /* Check for exclusive options */
607 } else if (cmdOptions[1].optval != 0 &&
608 subcommand->exclusive &&
609 strchr(subcommand->exclusive,
610 cmdOptions[i].optval)) {
611 (void) printf("%s: '-%c': %s\n",
612 commandName, cmdOptions[i].optval,
613 gettext("is an exclusive option"));
614 subUsage(DETAIL_USAGE, subcommand);
615 return (1);
618 } else { /* no options were input */
619 if (availOptions != NULL && subcommand->required) {
620 (void) printf("%s: %s\n", commandName,
621 gettext("at least one option required"));
622 subUsage(DETAIL_USAGE, subcommand);
623 return (1);
627 /* Were all required options entered? */
628 if (requiredOptionEntered != requiredOptionCnt) {
629 (void) printf("%s: %s: %s\n", commandName,
630 gettext("Following option(s) required"),
631 subcommand->required);
632 subUsage(DETAIL_USAGE, subcommand);
633 return (1);
638 * If there are no operands,
639 * check to see if this is okay
641 if ((operInd == argc) &&
642 (subcommand->operand & OPERAND_MANDATORY)) {
643 (void) printf("%s: %s %s\n", commandName, subcommand->name,
644 gettext("requires an operand"));
645 subUsage(DETAIL_USAGE, subcommand);
646 return (1);
650 * If there are more operands,
651 * check to see if this is okay
653 if ((argc > operInd) &&
654 (subcommand->operand & OPERAND_NONE)) {
655 (void) fprintf(stderr, "%s: %s %s\n", commandName,
656 subcommand->name, gettext("takes no operands"));
657 subUsage(DETAIL_USAGE, subcommand);
658 return (1);
662 * If there is more than one more operand,
663 * check to see if this is okay
665 if ((argc > operInd) && ((argc - operInd) != 1) &&
666 (subcommand->operand & OPERAND_SINGLE)) {
667 (void) printf("%s: %s %s\n", commandName,
668 subcommand->name, gettext("accepts only a single operand"));
669 subUsage(DETAIL_USAGE, subcommand);
670 return (1);
673 /* Finished syntax checks */
676 /* Call appropriate function */
677 *funcRet = subcommand->handler(argc - operInd, &argv[operInd],
678 &cmdOptions[0], callArgs);
680 return (0);