Skip to content

Commit 025a935

Browse files
committed
examples: move "args" to its own header
1 parent 745ccc8 commit 025a935

File tree

4 files changed

+251
-239
lines changed

4 files changed

+251
-239
lines changed

examples/args.c

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#include "common.h"
2+
#include "args.h"
3+
4+
size_t is_prefixed(const char *str, const char *pfx)
5+
{
6+
size_t len = strlen(pfx);
7+
return strncmp(str, pfx, len) ? 0 : len;
8+
}
9+
10+
int optional_str_arg(
11+
const char **out, struct args_info *args, const char *opt, const char *def)
12+
{
13+
const char *found = args->argv[args->pos];
14+
size_t len = is_prefixed(found, opt);
15+
16+
if (!len)
17+
return 0;
18+
19+
if (!found[len]) {
20+
if (args->pos + 1 == args->argc) {
21+
*out = def;
22+
return 1;
23+
}
24+
args->pos += 1;
25+
*out = args->argv[args->pos];
26+
return 1;
27+
}
28+
29+
if (found[len] == '=') {
30+
*out = found + len + 1;
31+
return 1;
32+
}
33+
34+
return 0;
35+
}
36+
37+
int match_str_arg(
38+
const char **out, struct args_info *args, const char *opt)
39+
{
40+
const char *found = args->argv[args->pos];
41+
size_t len = is_prefixed(found, opt);
42+
43+
if (!len)
44+
return 0;
45+
46+
if (!found[len]) {
47+
if (args->pos + 1 == args->argc)
48+
fatal("expected value following argument", opt);
49+
args->pos += 1;
50+
*out = args->argv[args->pos];
51+
return 1;
52+
}
53+
54+
if (found[len] == '=') {
55+
*out = found + len + 1;
56+
return 1;
57+
}
58+
59+
return 0;
60+
}
61+
62+
static const char *match_numeric_arg(struct args_info *args, const char *opt)
63+
{
64+
const char *found = args->argv[args->pos];
65+
size_t len = is_prefixed(found, opt);
66+
67+
if (!len)
68+
return NULL;
69+
70+
if (!found[len]) {
71+
if (args->pos + 1 == args->argc)
72+
fatal("expected numeric value following argument", opt);
73+
args->pos += 1;
74+
found = args->argv[args->pos];
75+
} else {
76+
found = found + len;
77+
if (*found == '=')
78+
found++;
79+
}
80+
81+
return found;
82+
}
83+
84+
int match_uint16_arg(
85+
uint16_t *out, struct args_info *args, const char *opt)
86+
{
87+
const char *found = match_numeric_arg(args, opt);
88+
uint16_t val;
89+
char *endptr = NULL;
90+
91+
if (!found)
92+
return 0;
93+
94+
val = (uint16_t)strtoul(found, &endptr, 0);
95+
if (!endptr || *endptr != '\0')
96+
fatal("expected number after argument", opt);
97+
98+
if (out)
99+
*out = val;
100+
return 1;
101+
}
102+
103+
int match_uint32_arg(
104+
uint32_t *out, struct args_info *args, const char *opt)
105+
{
106+
const char *found = match_numeric_arg(args, opt);
107+
uint16_t val;
108+
char *endptr = NULL;
109+
110+
if (!found)
111+
return 0;
112+
113+
val = (uint32_t)strtoul(found, &endptr, 0);
114+
if (!endptr || *endptr != '\0')
115+
fatal("expected number after argument", opt);
116+
117+
if (out)
118+
*out = val;
119+
return 1;
120+
}
121+
122+
static int match_int_internal(
123+
int *out, const char *str, int allow_negative, const char *opt)
124+
{
125+
char *endptr = NULL;
126+
int val = (int)strtol(str, &endptr, 10);
127+
128+
if (!endptr || *endptr != '\0')
129+
fatal("expected number", opt);
130+
else if (val < 0 && !allow_negative)
131+
fatal("negative values are not allowed", opt);
132+
133+
if (out)
134+
*out = val;
135+
136+
return 1;
137+
}
138+
139+
int match_bool_arg(int *out, struct args_info *args, const char *opt)
140+
{
141+
const char *found = args->argv[args->pos];
142+
143+
if (!strcmp(found, opt)) {
144+
*out = 1;
145+
return 1;
146+
}
147+
148+
if (!strncmp(found, "--no-", strlen("--no-")) &&
149+
!strcmp(found + strlen("--no-"), opt + 2)) {
150+
*out = 0;
151+
return 1;
152+
}
153+
154+
*out = -1;
155+
return 0;
156+
}
157+
158+
int is_integer(int *out, const char *str, int allow_negative)
159+
{
160+
return match_int_internal(out, str, allow_negative, NULL);
161+
}
162+
163+
int match_int_arg(
164+
int *out, struct args_info *args, const char *opt, int allow_negative)
165+
{
166+
const char *found = match_numeric_arg(args, opt);
167+
if (!found)
168+
return 0;
169+
return match_int_internal(out, found, allow_negative, opt);
170+
}

examples/args.h

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#ifndef INCLUDE_examples_args_h__
2+
#define INCLUDE_examples_args_h__
3+
4+
/**
5+
* Argument-processing helper structure
6+
*/
7+
struct args_info {
8+
int argc;
9+
char **argv;
10+
int pos;
11+
};
12+
#define ARGS_INFO_INIT { argc, argv, 0, 0 }
13+
#define ARGS_CURRENT(args) args->argv[args->pos]
14+
15+
/**
16+
* Check if a string has the given prefix. Returns 0 if not prefixed
17+
* or the length of the prefix if it is.
18+
*/
19+
extern size_t is_prefixed(const char *str, const char *pfx);
20+
21+
/**
22+
* Match an integer string, returning 1 if matched, 0 if not.
23+
*/
24+
extern int is_integer(int *out, const char *str, int allow_negative);
25+
26+
/**
27+
* Check current `args` entry against `opt` string. If it matches
28+
* exactly, take the next arg as a string; if it matches as a prefix with
29+
* an equal sign, take the remainder as a string; if value not supplied,
30+
* default value `def` will be given. otherwise return 0.
31+
*/
32+
extern int optional_str_arg(
33+
const char **out, struct args_info *args, const char *opt, const char *def);
34+
35+
/**
36+
* Check current `args` entry against `opt` string. If it matches
37+
* exactly, take the next arg as a string; if it matches as a prefix with
38+
* an equal sign, take the remainder as a string; otherwise return 0.
39+
*/
40+
extern int match_str_arg(
41+
const char **out, struct args_info *args, const char *opt);
42+
43+
/**
44+
* Check current `args` entry against `opt` string parsing as uint16. If
45+
* `opt` matches exactly, take the next arg as a uint16_t value; if `opt`
46+
* is a prefix (equal sign optional), take the remainder of the arg as a
47+
* uint16_t value; otherwise return 0.
48+
*/
49+
extern int match_uint16_arg(
50+
uint16_t *out, struct args_info *args, const char *opt);
51+
52+
/**
53+
* Check current `args` entry against `opt` string parsing as uint32. If
54+
* `opt` matches exactly, take the next arg as a uint16_t value; if `opt`
55+
* is a prefix (equal sign optional), take the remainder of the arg as a
56+
* uint32_t value; otherwise return 0.
57+
*/
58+
extern int match_uint32_arg(
59+
uint32_t *out, struct args_info *args, const char *opt);
60+
61+
/**
62+
* Check current `args` entry against `opt` string parsing as int. If
63+
* `opt` matches exactly, take the next arg as an int value; if it matches
64+
* as a prefix (equal sign optional), take the remainder of the arg as a
65+
* int value; otherwise return 0.
66+
*/
67+
extern int match_int_arg(
68+
int *out, struct args_info *args, const char *opt, int allow_negative);
69+
70+
/**
71+
* Check current `args` entry against a "bool" `opt` (ie. --[no-]progress).
72+
* If `opt` matches positively, out will be set to 1, or if `opt` matches
73+
* negatively, out will be set to 0, and in both cases 1 will be returned.
74+
* If neither the positive or the negative form of opt matched, out will be -1,
75+
* and 0 will be returned.
76+
*/
77+
extern int match_bool_arg(int *out, struct args_info *args, const char *opt);
78+
79+
#endif

0 commit comments

Comments
 (0)