1/*
2 Author: Marcus Boerger <helly@users.sourceforge.net>
3*/
4
5#include <stdio.h>
6#include <string.h>
7#include <assert.h>
8#include <stdlib.h>
9#include "mbo_getopt.h"
10#define OPTERRCOLON (1)
11#define OPTERRNF (2)
12#define OPTERRARG (3)
13
14static int mbo_opt_error(int argc, char * const *argv, int oint, int optchr, int err, int show_err)
15{
16	if (show_err)
17	{
18		fprintf(stderr, "Error in argument %d, char %d: ", oint, optchr + 1);
19
20		switch (err)
21		{
22
23			case OPTERRCOLON:
24			fprintf(stderr, ": in flags\n");
25			break;
26
27			case OPTERRNF:
28			fprintf(stderr, "option not found %c\n", argv[oint][optchr]);
29			break;
30
31			case OPTERRARG:
32			fprintf(stderr, "no argument for option %c\n", argv[oint][optchr]);
33			break;
34
35			default:
36			fprintf(stderr, "unknown\n");
37			break;
38		}
39	}
40
41	return ('?');
42}
43
44int mbo_getopt(int argc, char* const *argv, const mbo_opt_struct opts[], char **optarg, int *optind, int show_err)
45{
46	static int optchr = 0;
47	static int dash = 0; /* have already seen the - */
48	int arg_start = 2;
49
50	int opts_idx = -1;
51
52	if (*optind >= argc)
53	{
54		return (EOF);
55	}
56
57	if (!dash)
58	{
59		if ((argv[*optind][0] != '-'))
60		{
61			return (EOF);
62		}
63		else
64		{
65			if (!argv[*optind][1])
66			{
67				/*
68				* use to specify stdin. Need to let pgm process this and
69				* the following args
70				*/
71				return (EOF);
72			}
73		}
74	}
75
76	if ((argv[*optind][0] == '-') && (argv[*optind][1] == '-'))
77	{
78		/* '--' indicates end of args if not followed by a known long option name */
79
80		while (1)
81		{
82			opts_idx++;
83
84			if (opts[opts_idx].opt_char == '-')
85			{
86				(*optind)++;
87				return (EOF);
88			}
89			else if (opts[opts_idx].opt_name && !strcmp(&argv[*optind][2], opts[opts_idx].opt_name))
90			{
91				break;
92			}
93		}
94
95		optchr = 0;
96		dash = 1;
97		arg_start = 2 + strlen(opts[opts_idx].opt_name);
98	}
99
100	if (!dash)
101	{
102		dash = 1;
103		optchr = 1;
104	}
105
106	/* Check if the guy tries to do a -: kind of flag */
107	if (argv[*optind][optchr] == ':')
108	{
109		dash = 0;
110		(*optind)++;
111		return (mbo_opt_error(argc, argv, *optind - 1, optchr, OPTERRCOLON, show_err));
112	}
113
114	if (opts_idx < 0)
115	{
116		while (1)
117		{
118			opts_idx++;
119
120			if (opts[opts_idx].opt_char == '-')
121			{
122				int errind = *optind;
123				int errchr = optchr;
124
125				if (!argv[*optind][optchr + 1])
126				{
127					dash = 0;
128					(*optind)++;
129				}
130				else
131				{
132					optchr++;
133				}
134
135				return (mbo_opt_error(argc, argv, errind, errchr, OPTERRNF, show_err));
136			}
137			else if (argv[*optind][optchr] == opts[opts_idx].opt_char)
138			{
139				break;
140			}
141		}
142	}
143
144	if (opts[opts_idx].need_param)
145	{
146		/* Check for cases where the value of the argument
147		is in the form -<arg> <val> or in the form -<arg><val> */
148		dash = 0;
149
150		if (!argv[*optind][arg_start])
151		{
152			(*optind)++;
153
154			if (*optind == argc)
155			{
156				return (mbo_opt_error(argc, argv, *optind - 1, optchr, OPTERRARG, show_err));
157			}
158
159			*optarg = argv[(*optind)++];
160		}
161		else
162		{
163			*optarg = &argv[*optind][arg_start];
164			(*optind)++;
165		}
166
167		return opts[opts_idx].opt_char;
168	}
169	else
170	{
171		if (arg_start == 2)
172		{
173			if (!argv[*optind][optchr + 1])
174			{
175				dash = 0;
176				(*optind)++;
177			}
178			else
179			{
180				optchr++;
181			}
182		}
183		else
184		{
185			(*optind)++;
186		}
187
188		return opts[opts_idx].opt_char;
189	}
190
191	assert(0);
192	return (0);	/* never reached */
193}
194
195