summaryrefslogtreecommitdiff
path: root/libc/misc/getopt.c
blob: d9512147fceaeeef245a345cf7fc4fcf37c4c4a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

/*
 * From: gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) Newsgroups: net.sources
 * Subject: getopt library routine Date: 30 Mar 85 04:45:33 GMT
 */
/*
 * getopt -- public domain version of standard System V routine
 * 
 * Strictly enforces the System V Command Syntax Standard; provided by D A
 * Gwyn of BRL for generic ANSI C implementations
 * 
 * #define STRICT to prevent acceptance of clustered options with arguments
 * and ommision of whitespace between option and arg.
 */

#include <stdio.h>
#include <string.h>

int   opterr = 1;		/* error => print message */
int   optind = 1;		/* next argv[] index */
char *optarg = NULL;		/* option parameter if any */

static int
Err(name, mess, c)		/* returns '?' */
char *name;			/* program name argv[0] */
char *mess;			/* specific message */
int   c;			/* defective option letter */
{
   if (opterr)
   {
      (void) fprintf(stderr,
		     "%s: %s -- %c\n",
		     name, mess, c
	  );
   }

   return '?';			/* erroneous-option marker */
}

int
getopt(argc, argv, optstring)	/* returns letter, '?', EOF */
int   argc;			/* argument count from main */
char *argv[];			/* argument vector from main */
char *optstring;		/* allowed args, e.g. "ab:c" */
{
   static int sp = 1;		/* position within argument */
   register int osp;		/* saved `sp' for param test */
#ifndef STRICT
   register int oind;		/* saved `optind' for param test */
#endif
   register int c;		/* option letter */
   register char *cp;		/* -> option in `optstring' */

   optarg = NULL;

   if (sp == 1)			/* fresh argument */
      if (optind >= argc	/* no more arguments */
	  || argv[optind][0] != '-'	/* no more options */
	  || argv[optind][1] == '\0'	/* not option; stdin */
	  )
	 return EOF;
      else if (strcmp(argv[optind], "--") == 0)
      {
	 ++optind;		/* skip over "--" */
	 return EOF;		/* "--" marks end of options */
      }

   c = argv[optind][sp];	/* option letter */
   osp = sp++;			/* get ready for next letter */

#ifndef STRICT
   oind = optind;		/* save optind for param test */
#endif
   if (argv[optind][sp] == '\0')/* end of argument */
   {
      ++optind;			/* get ready for next try */
      sp = 1;			/* beginning of next argument */
   }

   if (c == ':' || c == '?'	/* optstring syntax conflict */
       || (cp = strchr(optstring, c)) == NULL	/* not found */
       )
      return Err(argv[0], "illegal option", c);

   if (cp[1] == ':')		/* option takes parameter */
   {
#ifdef STRICT
      if (osp != 1)
	 return Err(argv[0],
		    "option must not be clustered",
		    c
	     );

      if (sp != 1)		/* reset by end of argument */
	 return Err(argv[0],
		    "option must be followed by white space",
		    c
	     );

#else
      if (oind == optind)	/* argument w/o whitespace */
      {
	 optarg = &argv[optind][sp];
	 sp = 1;		/* beginning of next argument */
      }

      else
#endif
      if (optind >= argc)
	 return Err(argv[0],
		    "option requires an argument",
		    c
	     );

      else			/* argument w/ whitespace */
	 optarg = argv[optind];

      ++optind;			/* skip over parameter */
   }

   return c;
}