1
/*****************************************************************************
2
* getopt.c - competent and free getopt library.
3
* $Header: /cvsroot/freegetopt/freegetopt/getopt.c,v 1.2 2003/10/26 03:10:20 vindaci Exp $
4
*
5
* Copyright (c)2002-2003 Mark K. Kim
6
* All rights reserved.
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
10
* are met:
11
*
12
*   * Redistributions of source code must retain the above copyright
13
*     notice, this list of conditions and the following disclaimer.
14
*
15
*   * Redistributions in binary form must reproduce the above copyright
16
*     notice, this list of conditions and the following disclaimer in
17
*     the documentation and/or other materials provided with the
18
*     distribution.
19
*
20
*   * Neither the original author of this software nor the names of its
21
*     contributors may be used to endorse or promote products derived
22
*     from this software without specific prior written permission.
23
*
24
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
31
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
34
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
35
* DAMAGE.
36
*/
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include "cairo-boilerplate-getopt.h"
41

            
42

            
43
char* optarg = NULL;
44
int optind = 0;
45
int opterr = 1;
46
int optopt = '?';
47

            
48

            
49
static char** prev_argv = NULL;        /* Keep a copy of argv and argc to */
50
static int prev_argc = 0;	       /*    tell if getopt params change */
51
static int argv_index = 0;	       /* Option we're checking */
52
static int argv_index2 = 0;	       /* Option argument we're checking */
53
static int opt_offset = 0;	       /* Index into compounded "-option" */
54
static int dashdash = 0;	       /* True if "--" option reached */
55
static int nonopt = 0;		       /* How many nonopts we've found */
56

            
57
static void increment_index(void)
58
{
59
	/* Move onto the next option */
60
	if(argv_index < argv_index2)
61
	{
62
		while(prev_argv[++argv_index] && prev_argv[argv_index][0] != '-'
63
				&& argv_index < argv_index2+1);
64
	}
65
	else argv_index++;
66
	opt_offset = 1;
67
}
68

            
69

            
70
/*
71
* Permutes argv[] so that the argument currently being processed is moved
72
* to the end.
73
*/
74
static int permute_argv_once(void)
75
{
76
	/* Movability check */
77
	if(argv_index + nonopt >= prev_argc) return 1;
78
	/* Move the current option to the end, bring the others to front */
79
	else
80
	{
81
		char* tmp = prev_argv[argv_index];
82

            
83
		/* Move the data */
84
		memmove(&prev_argv[argv_index], &prev_argv[argv_index+1],
85
				sizeof(char**) * (prev_argc - argv_index - 1));
86
		prev_argv[prev_argc - 1] = tmp;
87

            
88
		nonopt++;
89
		return 0;
90
	}
91
}
92

            
93

            
94
1
int _cairo_getopt(int argc, char** argv, const char* optstr)
95
{
96
1
	int c = 0;
97

            
98
	/* If we have new argv, reinitialize */
99
1
	if(prev_argv != argv || prev_argc != argc)
100
	{
101
		/* Initialize variables */
102
1
		prev_argv = argv;
103
1
		prev_argc = argc;
104
1
		argv_index = 1;
105
1
		argv_index2 = 1;
106
1
		opt_offset = 1;
107
1
		dashdash = 0;
108
1
		nonopt = 0;
109
	}
110

            
111
	/* Jump point in case we want to ignore the current argv_index */
112
1
	getopt_top:
113

            
114
	/* Misc. initializations */
115
1
	optarg = NULL;
116

            
117
	/* Dash-dash check */
118
1
	if(argv[argv_index] && !strcmp(argv[argv_index], "--"))
119
	{
120
		dashdash = 1;
121
		increment_index();
122
	}
123

            
124
	/* If we're at the end of argv, that's it. */
125
1
	if(argv[argv_index] == NULL)
126
	{
127
1
		c = -1;
128
	}
129
	/* Are we looking at a string? Single dash is also a string */
130
	else if(dashdash || argv[argv_index][0] != '-' || !strcmp(argv[argv_index], "-"))
131
	{
132
		/* If we want a string... */
133
		if(optstr[0] == '-')
134
		{
135
			c = 1;
136
			optarg = argv[argv_index];
137
			increment_index();
138
		}
139
		/* If we really don't want it (we're in POSIX mode), we're done */
140
		else if(optstr[0] == '+' || getenv("POSIXLY_CORRECT"))
141
		{
142
			c = -1;
143

            
144
			/* Everything else is a non-opt argument */
145
			nonopt = argc - argv_index;
146
		}
147
		/* If we mildly don't want it, then move it back */
148
		else
149
		{
150
			if(!permute_argv_once()) goto getopt_top;
151
			else c = -1;
152
		}
153
	}
154
	/* Otherwise we're looking at an option */
155
	else
156
	{
157
		char* opt_ptr = NULL;
158

            
159
		/* Grab the option */
160
		c = argv[argv_index][opt_offset++];
161

            
162
		/* Is the option in the optstr? */
163
		if(optstr[0] == '-') opt_ptr = strchr(optstr+1, c);
164
		else opt_ptr = strchr(optstr, c);
165
		/* Invalid argument */
166
		if(!opt_ptr)
167
		{
168
			if(opterr)
169
			{
170
				fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c);
171
			}
172

            
173
			optopt = c;
174
			c = '?';
175

            
176
			/* Move onto the next option */
177
			increment_index();
178
		}
179
		/* Option takes argument */
180
		else if(opt_ptr[1] == ':')
181
		{
182
			/* ie, -oARGUMENT, -xxxoARGUMENT, etc. */
183
			if(argv[argv_index][opt_offset] != '\0')
184
			{
185
				optarg = &argv[argv_index][opt_offset];
186
				increment_index();
187
			}
188
			/* ie, -o ARGUMENT (only if it's a required argument) */
189
			else if(opt_ptr[2] != ':')
190
			{
191
				/* One of those "you're not expected to understand this" moment */
192
				if(argv_index2 < argv_index) argv_index2 = argv_index;
193
				while(argv[++argv_index2] && argv[argv_index2][0] == '-');
194
				optarg = argv[argv_index2];
195

            
196
				/* Don't cross into the non-option argument list */
197
				if(argv_index2 + nonopt >= prev_argc) optarg = NULL;
198

            
199
				/* Move onto the next option */
200
				increment_index();
201
			}
202
			else
203
			{
204
				/* Move onto the next option */
205
				increment_index();
206
			}
207

            
208
			/* In case we got no argument for an option with required argument */
209
			if(optarg == NULL && opt_ptr[2] != ':')
210
			{
211
				optopt = c;
212
				c = '?';
213

            
214
				if(opterr)
215
				{
216
					fprintf(stderr,"%s: option requires an argument -- %c\n",
217
							argv[0], optopt);
218
				}
219
			}
220
		}
221
		/* Option does not take argument */
222
		else
223
		{
224
			/* Next argv_index */
225
			if(argv[argv_index][opt_offset] == '\0')
226
			{
227
				increment_index();
228
			}
229
		}
230
	}
231

            
232
	/* Calculate optind */
233
1
	if(c == -1)
234
	{
235
1
		optind = argc - nonopt;
236
	}
237
	else
238
	{
239
		optind = argv_index;
240
	}
241

            
242
1
	return c;
243
}
244

            
245

            
246
/* vim:ts=3
247
*/