1
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
50
51
53
54
55
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
124
125
126
127
128
129
135
136
137
138
139
140
141
142
143
144
145
159
160
161
164
165
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
210
211
212
213
/* ... */
/* ... */
#include "argtable3.h"
#ifndef ARG_AMALGAMATION
#include "argtable3_private.h"
#endif
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#define FILESEPARATOR1 '\\'
#define FILESEPARATOR2 '/'/* ... */
#else
#define FILESEPARATOR1 '/'
#define FILESEPARATOR2 '/'/* ... */
#endif
static void arg_file_resetfn(struct arg_file* parent) {
ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
parent->count = 0;
}{ ... }
static const char* arg_basename(const char* filename) {
const char *result = NULL, *result1, *result2;
result1 = (filename ? strrchr(filename, FILESEPARATOR1) : NULL);
result2 = (filename ? strrchr(filename, FILESEPARATOR2) : NULL);
if (result2)
result = result2 + 1;
if (result1)
result = result1 + 1;
if (!result)
result = filename;
if (result && (strcmp(".", result) == 0 || strcmp("..", result) == 0))
result = filename + strlen(filename);
return result;
}{ ... }
static const char* arg_extension(const char* basename) {
const char* result = (basename ? strrchr(basename, '.') : NULL);
if (basename && !result)
result = basename + strlen(basename);
if (basename && result == basename)
result = basename + strlen(basename);
if (basename && result && strlen(result) == 1)
result = basename + strlen(basename);
return result;
}{ ... }
static int arg_file_scanfn(struct arg_file* parent, const char* argval) {
int errorcode = 0;
if (parent->count == parent->hdr.maxcount) {
errorcode = ARG_ERR_MAXCOUNT;
}{...} else if (!argval) {
parent->count++;
}{...} else {
parent->filename[parent->count] = argval;
parent->basename[parent->count] = arg_basename(argval);
parent->extension[parent->count] =
arg_extension(parent->basename[parent->count]);
parent->count++;
}{...}
ARG_TRACE(("%s4:scanfn(%p) returns %d\n", __FILE__, parent, errorcode));
return errorcode;
}{ ... }
static int arg_file_checkfn(struct arg_file* parent) {
int errorcode = (parent->count < parent->hdr.mincount) ? ARG_ERR_MINCOUNT : 0;
ARG_TRACE(("%s:checkfn(%p) returns %d\n", __FILE__, parent, errorcode));
return errorcode;
}{ ... }
static void arg_file_errorfn(struct arg_file* parent, arg_dstr_t ds, int errorcode, const char* argval, const char* progname) {
const char* shortopts = parent->hdr.shortopts;
const char* longopts = parent->hdr.longopts;
const char* datatype = parent->hdr.datatype;
argval = argval ? argval : "";
arg_dstr_catf(ds, "%s: ", progname);
switch (errorcode) {
case ARG_ERR_MINCOUNT:
arg_dstr_cat(ds, "missing option ");
arg_print_option_ds(ds, shortopts, longopts, datatype, "\n");
break;
...
case ARG_ERR_MAXCOUNT:
arg_dstr_cat(ds, "excess option ");
arg_print_option_ds(ds, shortopts, longopts, argval, "\n");
break;
...
default:
arg_dstr_catf(ds, "unknown error at \"%s\"\n", argval);...
}{...}
}{ ... }
struct arg_file* arg_file0(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
return arg_filen(shortopts, longopts, datatype, 0, 1, glossary);
}{ ... }
struct arg_file* arg_file1(const char* shortopts, const char* longopts, const char* datatype, const char* glossary) {
return arg_filen(shortopts, longopts, datatype, 1, 1, glossary);
}{ ... }
struct arg_file* arg_filen(const char* shortopts, const char* longopts, const char* datatype, int mincount, int maxcount, const char* glossary) {
size_t nbytes;
struct arg_file* result;
int i;
maxcount = (maxcount < mincount) ? mincount : maxcount;
nbytes = sizeof(struct arg_file)
+ sizeof(char*) * (size_t)maxcount
+ sizeof(char*) * (size_t)maxcount
+ sizeof(char*) * (size_t)maxcount;
result = (struct arg_file*)xmalloc(nbytes);
result->hdr.flag = ARG_HASVALUE;
result->hdr.shortopts = shortopts;
result->hdr.longopts = longopts;
result->hdr.glossary = glossary;
result->hdr.datatype = datatype ? datatype : "<file>";
result->hdr.mincount = mincount;
result->hdr.maxcount = maxcount;
result->hdr.parent = result;
result->hdr.resetfn = (arg_resetfn*)arg_file_resetfn;
result->hdr.scanfn = (arg_scanfn*)arg_file_scanfn;
result->hdr.checkfn = (arg_checkfn*)arg_file_checkfn;
result->hdr.errorfn = (arg_errorfn*)arg_file_errorfn;
result->filename = (const char**)(result + 1);
result->basename = result->filename + maxcount;
result->extension = result->basename + maxcount;
result->count = 0;
for (i = 0; i < maxcount; i++) {
result->filename[i] = "";
result->basename[i] = "";
result->extension[i] = "";
}{...}
ARG_TRACE(("arg_filen() returns %p\n", result));
return result;
}{ ... }