~ubuntu-branches/debian/stretch/opentyrian/stretch

« back to all changes in this revision

Viewing changes to src/arg_parse.c

  • Committer: Package Import Robot
  • Author(s): Etienne Millon
  • Date: 2015-03-31 08:48:54 UTC
  • Revision ID: package-import@ubuntu.com-20150331084854-f5a4uoz7uv3vopk6
Tags: upstream-2.1.20130907+dfsg
ImportĀ upstreamĀ versionĀ 2.1.20130907+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * OpenTyrian: A modern cross-platform port of Tyrian
 
3
 * Copyright (C) 2007-2009  The OpenTyrian Development Team
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * as published by the Free Software Foundation; either version 2
 
8
 * of the License, or (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
18
 */
 
19
#include "arg_parse.h"
 
20
#include "mingw_fixes.h"
 
21
 
 
22
#ifndef _GNU_SOURCE
 
23
#define _GNU_SOURCE
 
24
#endif
 
25
 
 
26
#include <stdio.h>
 
27
#include <stdlib.h>
 
28
#include <string.h>
 
29
 
 
30
static void permute( const char *argv[], int *first_nonopt, int *first_opt, int after_opt );
 
31
 
 
32
static int parse_short_opt( int argc, const char *const argv[], const Options *options, Option *option );
 
33
static int parse_long_opt( int argc, const char *const argv[], const Options *options, Option *option );
 
34
 
 
35
Option parse_args( int argc, const char *argv[], const Options *options )
 
36
{
 
37
        static int argn = 1;
 
38
        static bool no_more_options = false;
 
39
        
 
40
        static int first_nonopt = 1;
 
41
        
 
42
        Option option = { NOT_OPTION, NULL, 0 };
 
43
        option.argn = first_nonopt;
 
44
        
 
45
        while (argn < argc)
 
46
        {
 
47
                size_t arg_len = strlen(argv[argn]);
 
48
                
 
49
                if (!no_more_options &&
 
50
                    argv[argn][0] == '-' &&  // first char is '-'
 
51
                    arg_len > 1)             // option is not "-"
 
52
                {
 
53
                        option.argn = argn;
 
54
                        
 
55
                        if (argv[argn][1] == '-')  // string begins with "--"
 
56
                        {
 
57
                                if (arg_len == 2)  // "--" alone indicates end of options
 
58
                                {
 
59
                                        ++argn;
 
60
                                        no_more_options = true;
 
61
                                }
 
62
                                else
 
63
                                {
 
64
                                        argn = parse_long_opt(argc, argv, options, &option);
 
65
                                }
 
66
                        }
 
67
                        else
 
68
                        {
 
69
                                argn = parse_short_opt(argc, argv, options, &option);
 
70
                        }
 
71
                        
 
72
                        // shift option in front of non-options
 
73
                        permute(argv, &first_nonopt, &option.argn, argn);
 
74
                        
 
75
                        // don't include "--" in non-options
 
76
                        if (no_more_options)
 
77
                                ++option.argn;
 
78
                        break;
 
79
                }
 
80
                else
 
81
                {
 
82
                        // skip non-options, permute later when option encountered
 
83
                        ++argn;
 
84
                }
 
85
        }
 
86
        
 
87
        return option;
 
88
}
 
89
 
 
90
static void permute( const char *argv[], int *first_nonopt, int *first_opt, int after_opt )
 
91
{
 
92
        const int nonopts = *first_opt - *first_nonopt;
 
93
        
 
94
        // slide each of the options in front of the non-options
 
95
        for (int i = *first_opt; i < after_opt; ++i)
 
96
        {
 
97
                for (int j = i; j > *first_nonopt; --j)
 
98
                {
 
99
                        // swap argv[j] and argv[j - 1]
 
100
                        const char *temp = argv[j];
 
101
                        argv[j] = argv[j - 1];
 
102
                        argv[j - 1] = temp;
 
103
                }
 
104
                
 
105
                // position of first non-option shifts right once for each option
 
106
                ++(*first_nonopt);
 
107
        }
 
108
        
 
109
        // position of first option is initial position of first non-option
 
110
        *first_opt -= nonopts;
 
111
}
 
112
 
 
113
static int parse_short_opt( int argc, const char *const argv[], const Options *options, Option *option )
 
114
{
 
115
        static size_t offset = 1;  // ignore the "-"
 
116
        
 
117
        int argn = option->argn;
 
118
        
 
119
        const char *arg = argv[argn];
 
120
        
 
121
        const size_t arg_len = strlen(arg);
 
122
        
 
123
        const bool arg_attached = (offset + 1 < arg_len),  // possible argument attached?
 
124
                   last_in_argv = (argn == argc - 1);
 
125
        
 
126
        option->value = INVALID_OPTION;
 
127
        
 
128
        for (; !(options->short_opt == 0 &&
 
129
                 options->long_opt == NULL); ++options)
 
130
        {
 
131
                if (options->short_opt != 0 &&
 
132
                    options->short_opt == arg[offset])
 
133
                {
 
134
                        option->value = options->value;
 
135
                        
 
136
                        if (options->has_arg)
 
137
                        {
 
138
                                if (arg_attached)  // arg direclty follows option
 
139
                                {
 
140
                                        option->arg = arg + offset + 1;
 
141
                                        
 
142
                                        offset = arg_len;
 
143
                                }
 
144
                                else if (!last_in_argv)  // arg is next in argv
 
145
                                {
 
146
                                        option->arg = argv[++argn];
 
147
                                        
 
148
                                        offset = arg_len;
 
149
                                }
 
150
                                else
 
151
                                {
 
152
                                        option->value = OPTION_MISSING_ARG;
 
153
                                        break;
 
154
                                }
 
155
                        }
 
156
                        
 
157
                        break;
 
158
                }
 
159
        }
 
160
        
 
161
        switch (option->value)
 
162
        {
 
163
        case INVALID_OPTION:
 
164
                fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], argv[option->argn][offset]);
 
165
                break;
 
166
        case OPTION_MISSING_ARG:
 
167
                fprintf(stderr, "%s: option requires an argument -- '%c'\n", argv[0], argv[option->argn][offset]);
 
168
                break;
 
169
        }
 
170
        
 
171
        if (++offset >= arg_len)
 
172
        {
 
173
                ++argn;
 
174
                offset = 1;
 
175
        }
 
176
        
 
177
        return argn;  // which arg in argv that parse_args() should examine when called again
 
178
}
 
179
 
 
180
static int parse_long_opt( int argc, const char *const argv[], const Options *options, Option *option )
 
181
{
 
182
        int argn = option->argn;
 
183
        
 
184
        const char *arg = argv[argn] + 2;  // ignore the "--"
 
185
        
 
186
        const size_t arg_len = strlen(arg),
 
187
                     arg_opt_len = strchrnul(arg, '=') - arg;  // length before "="
 
188
        
 
189
        const bool arg_attached = (arg_opt_len < arg_len),  // argument attached using "="?
 
190
                   last_in_argv = (argn == argc - 1);
 
191
        
 
192
        option->value = INVALID_OPTION;
 
193
        
 
194
        for (; !(options->short_opt == 0 &&
 
195
                 options->long_opt == NULL); ++options)
 
196
        {
 
197
                if (options->long_opt != NULL &&
 
198
                    strncmp(options->long_opt, arg, arg_opt_len) == 0)  // matches (partially, at least)
 
199
                {
 
200
                        if (option->value != INVALID_OPTION)  // other match already found
 
201
                        {
 
202
                                option->value = AMBIGUOUS_OPTION;
 
203
                                break;
 
204
                        }
 
205
                        
 
206
                        option->value = options->value;
 
207
                        
 
208
                        if (options->has_arg)
 
209
                        {
 
210
                                if (arg_attached)  // arg is after "="
 
211
                                {
 
212
                                        option->arg = arg + arg_opt_len + 1;
 
213
                                }
 
214
                                else if (!last_in_argv)  // arg is next in argv
 
215
                                {
 
216
                                        option->arg = argv[++argn];
 
217
                                }
 
218
                                else  // arg is missing
 
219
                                {
 
220
                                        option->value = OPTION_MISSING_ARG;
 
221
                                        // can't break, gotta check for ambiguity
 
222
                                }
 
223
                        }
 
224
                        
 
225
                        if (arg_opt_len == strlen(options->long_opt)) // exact match
 
226
                                break;
 
227
                        // can't break for partial match, gotta check for ambiguity
 
228
                }
 
229
        }
 
230
        
 
231
        switch (option->value)
 
232
        {
 
233
        case INVALID_OPTION:
 
234
                fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], argv[option->argn]);
 
235
                break;
 
236
        case AMBIGUOUS_OPTION:
 
237
                fprintf(stderr, "%s: option '%s' is ambiguous\n", argv[0], argv[option->argn]);
 
238
                break;
 
239
        case OPTION_MISSING_ARG:
 
240
                fprintf(stderr, "%s: option '%s' requires an argument\n", argv[0], argv[option->argn]);
 
241
                break;
 
242
        }
 
243
        
 
244
        ++argn;
 
245
        
 
246
        return argn;  // which arg in argv that parse_args() should examine when called again
 
247
}