With a little bit of Google searching, one can find a public domain implementation of getopt() by AT&T which was originally presented at the 1985 UNIFORUM conference in Dallas, Texas. Here it is, warts and all, in all its crummy pre-ANSI glory:
/*
Note the ERR macro: it takes two arguments, a string, s which explains what is wrong with the the option given (basically, it's either an invalid option, or an option without a mandatory argument) and a single character, c, which is the option at which the error occurred. It then outputs an error message to stderr using the write() stdio function in a way equivalent to 'printf("%s%s%c\n", argv[0], s, c);'.
Four global variables are used to keep track of the state of the option processing, but only two are actually needed. opterr is not really used for anything; it's always set to 1, and is just used by the ERR macro to determine if it's worthwhile to display an error message. It may as well be a constant, or a #define'd entity, since it's just used for turning error messages on or off, which few programs do any more. Next comes optind, which keeps track of which argument we're currently scanning. It's initialised to 1, meaning that argv[1] is the first argument checked. After each argument is taken, it's incremented to shift to the next one. When optind is greater than argc, getopt() returns EOF. optopt is simply set to the value of c each time getopt() is called but does not appear to be used for anything else. Finally there is optarg, which is simply a pointer to an option's argument if an option requires one (and said option-argument is provided).
*/
/*LINTLIBRARY*/
#define NULL 0
#define EOF (-1)
#define ERR(s, c) if(opterr){\
extern int strlen(), write();\
char errbuf[2];\
errbuf[0] = c; errbuf[1] = '\n';\
(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
(void) write(2, s, (unsigned)strlen(s));\
(void) write(2, errbuf, 2);}
extern int strcmp();
extern char *strchr();
int opterr = 1;
int optind = 1;
int optopt;
char *optarg;
int
getopt(argc, argv, opts)
int argc;
char **argv, *opts;
{
static int sp = 1;
register int c;
register char *cp;
if(sp == 1)
if(optind >= argc ||
argv[optind][0] != '-' || argv[optind][1] == '\0')
return(EOF);
else if(strcmp(argv[optind], "--") == NULL) {
optind++;
return(EOF);
}
optopt = c = argv[optind][sp];
if(c == ':' || (cp=strchr(opts, c)) == NULL) {
ERR(": illegal option -- ", c);
if(argv[optind][++sp] == '\0') {
optind++;
sp = 1;
} return('?');
}
if(*++cp == ':') {
if(argv[optind][sp+1] != '\0')
optarg = &argv[optind++][sp+1];
else if(++optind >= argc) {
ERR(": option requires an argument -- ", c);
sp = 1;
return('?');
} else
optarg = argv[optind++];
sp = 1;
} else {
if(argv[optind][++sp] == '\0') {
sp = 1;
optind++;
} optarg = NULL;
} return(c);
}
Here's the somewhat nicer version which I bundle in a subdirectory for my own small programs so I don't have to rely on it being in <unistd.h> or <getopt.h> on non
SUS systems. It's useful if you want to make a program that's
ANSI C compliant.
/* getopt.c:
* a public domain implementation of getopt()
*
* The following source code is an adaptation of the public domain getopt()
* implementation presented at the 1985 UNIFORUM conference in Dallas,
* Texas. Slight edits have been made to improve readability and the result
* is released into the public domain like that from which it was derived.
*/
#include <stdio.h>
#include <string.h>
int optind = 1;
int optopt;
char *optarg;
int
getopt(int argc, char **argv, char *opts)
{
static int sp = 1;
register int c;
register char *cp;
if (sp == 1) {
/* If all args are processed, finish */
if (optind >= argc) {
return EOF;
}
if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
return EOF;
}
} else if (!strcmp(argv[optind], "--")) {
/* No more options to be processed after this one */
optind++;
return EOF;
}
optopt = c = argv[optind][sp];
/* Check for invalid option */
if (c == ':' || (cp = strchr(opts, c)) == NULL) {
fprintf(stderr,
"%s: illegal option -- %c\n",
argv[0],
c);
if (argv[optind][++sp] == '\0') {
optind++;
sp = 1;
}
return '?';
}
/* Does this option require an argument? */
if (*++cp == ':') {
/* If so, get argument; if none provided output error */
if (argv[optind][sp+1] != '\0') {
optarg = &argv[optind++][sp+1];
} else if (++optind >= argc) {
fprintf(stderr,
"%s: option requires an argument -- %c\n",
argv[0],
c);
sp = 1;
return '?';
} else {
optarg = argv[optind++];
}
sp = 1;
} else {
if (argv[optind][++sp] == '\0') {
sp = 1;
optind++;
}
optarg = NULL;
}
return c;
}