ref: bf7a16e59b193714cece221765b046845acb1696
dir: /win/getopt.c/
/* * pgetopt.c - Portable implementation of getopt() command line args parser, * originally made available by IBM and the authors listed below. * * Created on 8/8/08. * Portions of this document are Copyright (C) 2008, PlexFX, * All Rights Reserved. * * History: * Original Date Unknown * This code is quite old, but it was originally called GETOPT.C * in the comments, along with a GETOPT.H thin header, and used the * same namespace as the getopt() implementation on my UNIX variant * platforms. The original date has been lost. It may date back * to even pre-ANSI C. The development team at PlexFX has been * using it (primarily for Windows command line tools, but also on * other platforms for many years. A search for historical dates * via web search engines found it widely used, but no date stamps * on its original form seem to have been preserved. * It can be found in various forms in open source packages, such * as using a search engine on one or both of the author strings * shown in the original comment block below. For example, as of * the creation date on this file, a slightly modified verion of * it was used in library code found in the CVS tree for * OpenSolaris. * * It was also included on at least some of the MSDN Library discs * Around the early 2001-2003 time frame. * * 2008-08-08 This version is a modified version of the original IBM code, but * the filename and namespace used has been altered along with some * calling convention changes. As such, it can be used as a drop- * in replacement for getopt() even on UNIX or Linux systems that * have their own getopt() implementations in libc without naming * collisions. This means it can be used portably on any OS with * a conforming C compiler. It does *not* attempt to implement the * more long-winded getopt_long() interface. Naming of APIs, * headers and the optarg/optind externs have been prefixed with * 'p' to accomplish this. Examples: pgetopt(), poptarg, poptind, * pgetopt.c, pgetopt.h. * Note: This interface keeps external state (to match original * calling conventions). As such, it is not thread safe, * and should be called in only one thread (use from main() * before additional threads are started). As the command * line should never change, this should not be an issue. * */ /* Original IBM "AS IS" license follows */ /***************************************************************************** * * MODULE NAME : GETOPT.C * * COPYRIGHTS: * This module contains code made available by IBM * Corporation on an AS IS basis. Any one receiving the * module is considered to be licensed under IBM copyrights * to use the IBM-provided source code in any way he or she * deems fit, including copying it, compiling it, modifying * it, and redistributing it, with or without * modifications. No license under any IBM patents or * patent applications is to be implied from this copyright * license. * * A user of the module should understand that IBM cannot * provide technical support for the module and will not be * responsible for any consequences of use of the program. * * Any notices, including this one, are not to be removed * from the module without the prior written consent of * IBM. * * AUTHOR: Original author: * G. R. Blair (BOBBLAIR at AUSVM1) * Internet: bobblair@bobblair.austin.ibm.com * * Extensively revised by: * John Q. Walker II, Ph.D. (JOHHQ at RALVM6) * Internet: johnq@ralvm6.vnet.ibm.com * *****************************************************************************/ /****************************************************************************** * pgetopt() * * The pgetopt() function is a command line parser. It returns the next * option character in argv that matches an option character in optstring. * * The argv argument points to an array of argc+1 elements containing argc * pointers to character strings followed by a null pointer. * * The optstring argument points to a string of option characters; if an * option character is followed by a colon, the option is expected to have * an argument that may or may not be separated from it by white space. * The external variable poptarg is set to point to the start of the option * argument on return from pgetopt(). * * The pgetopt() function places in poptind the argv index of the next argument * to be processed. The system initializes the external variable poptind to * 1 before the first call to pgetopt(). * * When all options have been processed (that is, up to the first nonoption * argument), pgetopt() returns EOF. The special option "--" may be used to * delimit the end of the options; EOF will be returned, and "--" will be * skipped. * * The pgetopt() function returns a question mark (?) when it encounters an * option character not included in optstring. This error message can be * disabled by setting popterr to zero. Otherwise, it returns the option * character that was detected. * * If the special option "--" is detected, or all options have been * processed, EOF is returned. * * Options are marked by either a minus sign (-) or a slash (/). * * No other errors are defined. *****************************************************************************/ #include <stdio.h> /* for EOF */ #include <string.h> /* for strchr() */ #include "getopt.h" /* getopt() interface and example code */ /* global variables that are specified as exported by getopt() */ char *optarg = NULL; /* pointer to the start of the option argument */ int optind = 1; /* number of the next argv[] to be evaluated */ int opterr = 1; /* non-zero if a question mark should be returned * when a non-valid option character is detected */ /* handle possible future character set concerns by putting this in a macro */ #define _next_char(string) (char)(*(string+1)) int getopt(int argc, char *argv[], char *optstring) { static char *IndexPosition = NULL; /* place inside current argv string */ char *ArgString = NULL; /* where to start from next */ char *OptString; /* the string in our program */ if (IndexPosition != NULL) { /* we last left off inside an argv string */ if (*(++IndexPosition)) { /* there is more to come in the most recent argv */ ArgString = IndexPosition; } } if (ArgString == NULL) { /* we didn't leave off in the middle of an argv string */ if (optind >= argc) { /* more command-line arguments than the argument count */ IndexPosition = NULL; /* not in the middle of anything */ return EOF; /* used up all command-line arguments */ } /*--------------------------------------------------------------------- * If the next argv[] is not an option, there can be no more options. *-------------------------------------------------------------------*/ ArgString = argv[optind++]; /* set this to the next argument ptr */ if (('/' != *ArgString) && /* doesn't start with a slash or a dash? */ ('-' != *ArgString)) { --optind; /* point to current arg once we're done */ optarg = NULL; /* no argument follows the option */ IndexPosition = NULL; /* not in the middle of anything */ return EOF; /* used up all the command-line flags */ } /* check for special end-of-flags markers */ if ((strcmp(ArgString, "-") == 0) || (strcmp(ArgString, "--") == 0)) { optarg = NULL; /* no argument follows the option */ IndexPosition = NULL; /* not in the middle of anything */ return EOF; /* encountered the special flag */ } ArgString++; /* look past the / or - */ } if (':' == *ArgString) { /* is it a colon? */ /*--------------------------------------------------------------------- * Rare case: if opterr is non-zero, return a question mark; * otherwise, just return the colon we're on. *-------------------------------------------------------------------*/ return (opterr ? (int)'?' : (int)':'); } else if ((OptString = strchr(optstring, *ArgString)) == 0) { /*--------------------------------------------------------------------- * The letter on the command-line wasn't any good. *-------------------------------------------------------------------*/ optarg = NULL; /* no argument follows the option */ IndexPosition = NULL; /* not in the middle of anything */ return (opterr ? (int)'?' : (int)*ArgString); } else { /*--------------------------------------------------------------------- * The letter on the command-line matches one we expect to see *-------------------------------------------------------------------*/ if (':' == _next_char(OptString)) { /* is the next letter a colon? */ /* It is a colon. Look for an argument string. */ if ('\0' != _next_char(ArgString)) { /* argument in this argv? */ optarg = &ArgString[1]; /* Yes, it is */ } else { /*------------------------------------------------------------- * The argument string must be in the next argv. * But, what if there is none (bad input from the user)? * In that case, return the letter, and optarg as NULL. *-----------------------------------------------------------*/ if (optind < argc) optarg = argv[optind++]; else { optarg = NULL; return (opterr ? (int)'?' : (int)*ArgString); } } IndexPosition = NULL; /* not in the middle of anything */ } else { /* it's not a colon, so just return the letter */ optarg = NULL; /* no argument follows the option */ IndexPosition = ArgString; /* point to the letter we're on */ } return (int)*ArgString; /* return the letter that matched */ } }