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