/***************************************************************** * SQUID - a library of functions for biological sequence analysis * Copyright (C) 1992-2002 Washington University School of Medicine * * This source code is freely distributed under the terms of the * GNU General Public License. See the files COPYRIGHT and LICENSE * for details. *****************************************************************/ /* RCS $Id: getopt.c 217 2011-03-19 10:27:10Z andreas $ (Original squid RCS Id: getopt.c,v 1.7 2001/02/21 21:09:10 eddy Exp) */ #include #include #include #include "squid.h" /* Function: Getopt() * * Purpose: Portable command line option parsing with abbreviated * option switches. Replaces UNIX getopt(). Using UNIX getopt() * hinders portability to non-UNIX platforms, and getopt() * is also limited to single letter options. * * Getopt() implements a superset of UNIX getopt(). * All of getopt()'s single-character switch behavior * is emulated, and "--" by itself terminates the options. * Additionally, Getopt() provides extended switches * like "--youroptionhere", and Getopt() type checks * arguments. * * Extended options must start with "--", as in "--option1". * Normal options must start with "-", as in "-o". * Normal options may be concatenated, as in "-a -b" == "-ab". * * See bottom of this .c file after #fdef GETOPT_TESTDRIVER * for an example of calling Getopt(). * * Args: argc - from main(). number of elems in argv. * argv - from main(). argv[0] is the name of the command. * opt - array of opt_s structures, defining option switches * nopts - number of switches in opt * usage - a (possibly long) string to print if usage error. * ret_optind - RETURN: the index in argv[] of the next * valid command-line token. * ret_optname- RETURN: ptr to the name of option switch * seen, or NULL if no option was seen. * ret_optarg - RETURN: ptr to the optional argument, if any; * NULL if option takes no argument. * * Return: 1 if a valid option was parsed. * 0 if no option was found, and command-line parsing is complete. * Die()'s here if an error is detected. */ int Getopt(int argc, char **argv, struct opt_s *opt, int nopts, char *usage, int *ret_optind, char **ret_optname, char **ret_optarg) { int i; int arglen; int nmatch; static int optind = 1; /* init to 1 on first call */ static char *optptr = NULL; /* ptr to next valid switch */ int opti = 0; /* init only to silence gcc uninit warnings */ /* Check to see if we've run out of options. * A '-' by itself is an argument (e.g. "read from stdin") * not an option. */ if (optind >= argc || argv[optind][0] != '-' || strcmp(argv[optind], "-") == 0) { *ret_optind = optind; *ret_optarg = NULL; *ret_optname = NULL; return 0; } /* Check to see if we're being told that this is the end * of the options with the special "--" flag. */ if (strcmp(argv[optind], "--") == 0) { optind++; *ret_optind = optind; *ret_optname = NULL; *ret_optarg = NULL; return 0; } /* We have a real option. Find which one it is. * We handle single letter switches "-o" separately * from full switches "--option", based on the "-" vs. "--" * prefix -- single letter switches can be concatenated * as long as they don't have arguments. */ /* full option */ if (optptr == NULL && strncmp(argv[optind], "--", 2) == 0) { /* Use optptr to parse argument in options of form "--foo=666" */ if ((optptr = strchr(argv[optind], '=')) != NULL) { *optptr = '\0'; optptr++; } arglen = strlen(argv[optind]); nmatch = 0; for (i = 0; i < nopts; i++) if (opt[i].single == FALSE && strncmp(opt[i].name, argv[optind], arglen) == 0) { nmatch++; opti = i; if (arglen == strlen(opt[i].name)) break; /* exact match, stop now */ } if (nmatch > 1 && arglen != strlen(opt[i].name)) Die("Option \"%s\" is ambiguous; please be more specific.\n%s", argv[optind], usage); if (nmatch == 0) Die("No such option \"%s\".\n%s", argv[optind], usage); *ret_optname = opt[opti].name; /* Set the argument, if there is one */ if (opt[opti].argtype != sqdARG_NONE) { if (optptr != NULL) { /* --foo=666 style */ *ret_optarg = optptr; optptr = NULL; optind++; } else if (optind+1 >= argc) Die("Option %s requires an argument\n%s", opt[opti].name, usage); else /* "--foo 666" style */ { *ret_optarg = argv[optind+1]; optind+=2; } } else /* sqdARG_NONE */ { if (optptr != NULL) Die("Option %s does not take an argument\n%s", opt[opti].name, usage); *ret_optarg = NULL; optind++; } } else /* else, a single letter option "-o" */ { /* find the option */ if (optptr == NULL) optptr = argv[optind]+1; for (opti = -1, i = 0; i < nopts; i++) if (opt[i].single == TRUE && *optptr == opt[i].name[1]) { opti = i; break; } if (opti == -1) Die("No such option \"%c\".\n%s", *optptr, usage); *ret_optname = opt[opti].name; /* set the argument, if there is one */ if (opt[opti].argtype != sqdARG_NONE) { if (*(optptr+1) != '\0') /* attached argument */ { *ret_optarg = optptr+1; optind++; } else if (optind+1 < argc) /* unattached argument */ { *ret_optarg = argv[optind+1]; optind+=2; } else Die("Option %s requires an argument\n%s", opt[opti].name, usage); optptr = NULL; /* can't concatenate after an argument */ } else /* sqdARG_NONE */ { *ret_optarg = NULL; if (*(optptr+1) != '\0') /* concatenation */ optptr++; else { optind++; /* move to next field */ optptr = NULL; } } } /* Type check the argument, if there is one */ if (opt[opti].argtype != sqdARG_NONE) { if (opt[opti].argtype == sqdARG_INT && ! IsInt(*ret_optarg)) Die("Option %s requires an integer argument\n%s", opt[opti].name, usage); else if (opt[opti].argtype == sqdARG_FLOAT && ! IsReal(*ret_optarg)) Die("Option %s requires a numerical argument\n%s", opt[opti].name, usage); else if (opt[opti].argtype == sqdARG_CHAR && strlen(*ret_optarg) != 1) Die("Option %s requires a single-character argument\n%s", opt[opti].name, usage); /* sqdARG_STRING is always ok, no type check necessary */ } *ret_optind = optind; return 1; } #ifdef GETOPT_TESTDRIVER /* cc -DGETOPT_TESTDRIVER -L ~/lib/squid.linux/ getopt.c -lsquid */ struct opt_s OPTIONS[] = { { "--test1", FALSE, sqdARG_INT }, { "--test2", FALSE, sqdARG_FLOAT }, { "--test3", FALSE, sqdARG_STRING }, { "--test4", FALSE, sqdARG_CHAR }, { "-a", TRUE, sqdARG_NONE }, { "-b", TRUE, sqdARG_INT }, }; #define NOPTIONS (sizeof(OPTIONS) / sizeof(struct opt_s)) int main(int argc, char **argv) { int optind; char *optarg; char *optname; while (Getopt(argc, argv, OPTIONS, NOPTIONS, "Usage/help here", &optind, &optname, &optarg)) { printf("Option: index: %d name: %s argument: %s\n", optind, optname, optarg); } while (optind < argc) { printf("Argument: index: %d name: %s\n", optind, argv[optind]); optind++; } } #endif /*GETOPT_TESTDRIVER*/