iodine 0.6.5 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +4 -4
- data/SPEC-Websocket-Draft.md +3 -6
- data/bin/mustache.rb +128 -0
- data/examples/test_template.mustache +16 -0
- data/ext/iodine/fio.c +9397 -0
- data/ext/iodine/fio.h +4723 -0
- data/ext/iodine/fio_ary.h +353 -54
- data/ext/iodine/fio_cli.c +351 -361
- data/ext/iodine/fio_cli.h +84 -105
- data/ext/iodine/fio_hashmap.h +70 -16
- data/ext/iodine/fio_json_parser.h +35 -24
- data/ext/iodine/fio_siphash.c +104 -4
- data/ext/iodine/fio_siphash.h +18 -2
- data/ext/iodine/fio_str.h +1218 -0
- data/ext/iodine/fio_tmpfile.h +1 -1
- data/ext/iodine/fiobj.h +13 -8
- data/ext/iodine/fiobj4sock.h +6 -8
- data/ext/iodine/fiobj_ary.c +107 -17
- data/ext/iodine/fiobj_ary.h +36 -4
- data/ext/iodine/fiobj_data.c +146 -127
- data/ext/iodine/fiobj_data.h +25 -23
- data/ext/iodine/fiobj_hash.c +7 -7
- data/ext/iodine/fiobj_hash.h +6 -5
- data/ext/iodine/fiobj_json.c +20 -17
- data/ext/iodine/fiobj_json.h +5 -5
- data/ext/iodine/fiobj_mem.h +71 -0
- data/ext/iodine/fiobj_mustache.c +310 -0
- data/ext/iodine/fiobj_mustache.h +40 -0
- data/ext/iodine/fiobj_numbers.c +199 -94
- data/ext/iodine/fiobj_numbers.h +7 -7
- data/ext/iodine/fiobj_str.c +142 -333
- data/ext/iodine/fiobj_str.h +65 -55
- data/ext/iodine/fiobject.c +49 -11
- data/ext/iodine/fiobject.h +40 -39
- data/ext/iodine/http.c +382 -190
- data/ext/iodine/http.h +124 -80
- data/ext/iodine/http1.c +99 -127
- data/ext/iodine/http1.h +5 -5
- data/ext/iodine/http1_parser.c +3 -2
- data/ext/iodine/http1_parser.h +2 -2
- data/ext/iodine/http_internal.c +14 -12
- data/ext/iodine/http_internal.h +25 -19
- data/ext/iodine/iodine.c +37 -18
- data/ext/iodine/iodine.h +4 -0
- data/ext/iodine/iodine_caller.c +9 -2
- data/ext/iodine/iodine_caller.h +2 -0
- data/ext/iodine/iodine_connection.c +82 -117
- data/ext/iodine/iodine_defer.c +57 -50
- data/ext/iodine/iodine_defer.h +0 -1
- data/ext/iodine/iodine_fiobj2rb.h +4 -2
- data/ext/iodine/iodine_helpers.c +4 -4
- data/ext/iodine/iodine_http.c +25 -32
- data/ext/iodine/iodine_json.c +2 -1
- data/ext/iodine/iodine_mustache.c +423 -0
- data/ext/iodine/iodine_mustache.h +6 -0
- data/ext/iodine/iodine_pubsub.c +48 -153
- data/ext/iodine/iodine_pubsub.h +5 -4
- data/ext/iodine/iodine_rack_io.c +7 -5
- data/ext/iodine/iodine_store.c +16 -13
- data/ext/iodine/iodine_tcp.c +26 -34
- data/ext/iodine/mustache_parser.h +1085 -0
- data/ext/iodine/redis_engine.c +740 -646
- data/ext/iodine/redis_engine.h +13 -15
- data/ext/iodine/resp_parser.h +11 -5
- data/ext/iodine/websocket_parser.h +13 -13
- data/ext/iodine/websockets.c +240 -393
- data/ext/iodine/websockets.h +52 -113
- data/lib/iodine.rb +1 -1
- data/lib/iodine/mustache.rb +140 -0
- data/lib/iodine/version.rb +1 -1
- metadata +15 -28
- data/ext/iodine/defer.c +0 -566
- data/ext/iodine/defer.h +0 -148
- data/ext/iodine/evio.c +0 -26
- data/ext/iodine/evio.h +0 -161
- data/ext/iodine/evio_callbacks.c +0 -26
- data/ext/iodine/evio_epoll.c +0 -251
- data/ext/iodine/evio_kqueue.c +0 -194
- data/ext/iodine/facil.c +0 -2325
- data/ext/iodine/facil.h +0 -616
- data/ext/iodine/fio_base64.c +0 -277
- data/ext/iodine/fio_base64.h +0 -71
- data/ext/iodine/fio_llist.h +0 -257
- data/ext/iodine/fio_mem.c +0 -675
- data/ext/iodine/fio_mem.h +0 -143
- data/ext/iodine/fio_random.c +0 -248
- data/ext/iodine/fio_random.h +0 -45
- data/ext/iodine/fio_sha1.c +0 -362
- data/ext/iodine/fio_sha1.h +0 -107
- data/ext/iodine/fio_sha2.c +0 -842
- data/ext/iodine/fio_sha2.h +0 -169
- data/ext/iodine/pubsub.c +0 -867
- data/ext/iodine/pubsub.h +0 -221
- data/ext/iodine/sock.c +0 -1366
- data/ext/iodine/sock.h +0 -566
- data/ext/iodine/spnlock.inc +0 -111
data/ext/iodine/fio_cli.c
CHANGED
@@ -4,420 +4,410 @@ License: MIT
|
|
4
4
|
|
5
5
|
Feel free to copy, use and enjoy according to the license provided.
|
6
6
|
*/
|
7
|
-
#include
|
8
|
-
#include "fiobj.h"
|
7
|
+
#include <fio.h>
|
9
8
|
|
9
|
+
#include <fio_cli.h>
|
10
|
+
|
11
|
+
#include <stdint.h>
|
12
|
+
#include <stdio.h>
|
13
|
+
#include <stdlib.h>
|
10
14
|
#include <string.h>
|
11
|
-
|
12
|
-
State (static data)
|
13
|
-
***************************************************************************** */
|
15
|
+
#include <strings.h>
|
14
16
|
|
15
|
-
/* static variables are automatically initialized to 0, which is what we need.*/
|
16
|
-
static int FIO_CLI_ARGC;
|
17
|
-
static const char **FIO_CLI_ARGV;
|
18
|
-
static FIOBJ arg_aliases; /* a hash for translating aliases */
|
19
|
-
static FIOBJ arg_type; /* a with information about each argument */
|
20
|
-
static FIOBJ parsed; /* a with information about each argument */
|
21
|
-
static FIOBJ help_str; /* The CLI help string */
|
22
|
-
static FIOBJ info_str; /* The CLI information string */
|
23
|
-
static int is_parsed;
|
24
|
-
static int ignore_unknown;
|
25
|
-
|
26
|
-
const char DEFAULT_CLI_INFO[] =
|
27
|
-
"This application accepts any of the following possible arguments:";
|
28
17
|
/* *****************************************************************************
|
29
|
-
|
18
|
+
CLI Data Stores
|
30
19
|
***************************************************************************** */
|
31
20
|
|
32
|
-
|
33
|
-
|
21
|
+
typedef struct {
|
22
|
+
size_t len;
|
23
|
+
const char *data;
|
24
|
+
} cstr_s;
|
34
25
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
"%s\n"
|
43
|
-
"%s\n"
|
44
|
-
"Use any of the following input formats:\n"
|
45
|
-
"\t-arg <value>\t-arg=<value>\t-arg<value>\n"
|
46
|
-
"\n"
|
47
|
-
"Use the -h, -help or -? to get this information again.\n"
|
48
|
-
"\n",
|
49
|
-
info.data, args.data);
|
50
|
-
fio_cli_end();
|
51
|
-
exit(0);
|
52
|
-
}
|
26
|
+
#define FIO_SET_OBJ_TYPE const char *
|
27
|
+
#define FIO_SET_KEY_TYPE cstr_s
|
28
|
+
#define FIO_SET_KEY_COMPARE(o1, o2) \
|
29
|
+
(o1.len == o2.len && \
|
30
|
+
(o1.data == o2.data || !memcmp(o1.data, o2.data, o1.len)))
|
31
|
+
#define FIO_SET_NAME fio_hash
|
32
|
+
#include <fio.h>
|
53
33
|
|
54
|
-
|
55
|
-
|
56
|
-
|
34
|
+
static fio_hash_s fio_aliases = FIO_SET_INIT;
|
35
|
+
static fio_hash_s fio_values = FIO_SET_INIT;
|
36
|
+
static size_t fio_unknown_count = 0;
|
57
37
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
if (!info_str) /* might exist through `fio_cli_start` */
|
71
|
-
info_str = fiobj_str_new(DEFAULT_CLI_INFO, sizeof(DEFAULT_CLI_INFO) - 1);
|
72
|
-
}
|
38
|
+
typedef struct {
|
39
|
+
int allow_unknown;
|
40
|
+
int pos;
|
41
|
+
int unknown_count;
|
42
|
+
char const *description;
|
43
|
+
char const **names;
|
44
|
+
} fio_cli_parser_data_s;
|
45
|
+
|
46
|
+
/** this will allow the function definition fio_cli_start to avoid the MACRO */
|
47
|
+
#define AVOID_MACRO
|
48
|
+
|
49
|
+
#define FIO_CLI_HASH_VAL(s) fio_siphash13((s).data, (s).len)
|
73
50
|
|
74
51
|
/* *****************************************************************************
|
75
|
-
|
52
|
+
CLI Parsing
|
76
53
|
***************************************************************************** */
|
77
54
|
|
78
|
-
/* returns the primamry symbol for the argument, of NULL (if none) */
|
79
|
-
static inline FIOBJ fio_cli_get_name(const char *str, size_t len) {
|
80
|
-
const uint64_t key = fio_siphash(str, len);
|
81
|
-
return fiobj_hash_get2(arg_aliases, key);
|
82
|
-
}
|
83
|
-
|
84
55
|
/* *****************************************************************************
|
85
|
-
|
56
|
+
CLI Parsing
|
86
57
|
***************************************************************************** */
|
87
|
-
|
88
|
-
static void
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
while (1) {
|
94
|
-
/* get rid of any white space or commas */
|
95
|
-
while (start[0] == ' ' || start[0] == ',')
|
96
|
-
start++;
|
97
|
-
/* we're done */
|
98
|
-
if (!start[0])
|
99
|
-
return;
|
100
|
-
size_t len = 0;
|
101
|
-
/* find the length of the argument name */
|
102
|
-
while (start[len] != 0 && start[len] != ' ' && start[len] != ',')
|
103
|
-
len++;
|
104
|
-
|
105
|
-
if (!arg_name) {
|
106
|
-
/* this is the main identifier */
|
107
|
-
arg_name = fiobj_str_new(start, len);
|
108
|
-
/* add to aliases hash */
|
109
|
-
fiobj_hash_set(arg_aliases, arg_name, arg_name);
|
110
|
-
/* add the help section and set type*/
|
111
|
-
switch (type) {
|
112
|
-
case CLI_BOOL:
|
113
|
-
fiobj_str_write2(help_str, "\t\x1B[1m-%s\x1B[0m\t\t%s\n",
|
114
|
-
fiobj_obj2cstr(arg_name).data, desc);
|
115
|
-
fiobj_hash_set(arg_type, arg_name, fiobj_null());
|
116
|
-
break;
|
117
|
-
case CLI_NUM:
|
118
|
-
fiobj_str_write2(help_str,
|
119
|
-
"\t\x1B[1m-%s\x1B[0m\x1B[2m ###\x1B[0m\t%s\n",
|
120
|
-
fiobj_obj2cstr(arg_name).data, desc);
|
121
|
-
fiobj_hash_set(arg_type, arg_name, fiobj_true());
|
122
|
-
break;
|
123
|
-
case CLI_STR:
|
124
|
-
fiobj_str_write2(help_str,
|
125
|
-
"\t\x1B[1m-%s\x1B[0m\x1B[2m <val>\x1B[0m\t%s\n",
|
126
|
-
fiobj_obj2cstr(arg_name).data, desc);
|
127
|
-
fiobj_hash_set(arg_type, arg_name, fiobj_false());
|
128
|
-
break;
|
129
|
-
}
|
130
|
-
} else {
|
131
|
-
/* this is an alias */
|
132
|
-
FIOBJ tmp = fiobj_str_new(start, len);
|
133
|
-
/* add to aliases hash */
|
134
|
-
fiobj_hash_set(arg_aliases, tmp, fiobj_dup(arg_name));
|
135
|
-
/* add to description + free it*/
|
136
|
-
fiobj_str_write2(help_str, "\t\t\x1B[1m-%s\x1B[0m\tsame as -%s\n",
|
137
|
-
fiobj_obj2cstr(tmp).data, fiobj_obj2cstr(arg_name).data);
|
138
|
-
fiobj_free(tmp);
|
58
|
+
|
59
|
+
static void fio_cli_map_line2alias(char const *line) {
|
60
|
+
cstr_s n = {.data = line};
|
61
|
+
while (n.data[0] == '-') {
|
62
|
+
while (n.data[n.len] && n.data[n.len] != ' ' && n.data[n.len] != ',') {
|
63
|
+
++n.len;
|
139
64
|
}
|
140
|
-
|
65
|
+
const char **old = fio_hash_find(&fio_aliases, FIO_CLI_HASH_VAL(n), n);
|
66
|
+
if (old) {
|
67
|
+
fprintf(stderr,
|
68
|
+
"WARNING: CLI argument name conflict detected\n"
|
69
|
+
" The following two directives conflict:\n"
|
70
|
+
"\t%s\n\t%s\n",
|
71
|
+
*old, line);
|
72
|
+
}
|
73
|
+
fio_hash_insert(&fio_aliases, FIO_CLI_HASH_VAL(n), n, (void *)line);
|
74
|
+
while (n.data[n.len] && (n.data[n.len] == ' ' || n.data[n.len] == ',')) {
|
75
|
+
++n.len;
|
76
|
+
}
|
77
|
+
n.data += n.len;
|
78
|
+
n.len = 0;
|
141
79
|
}
|
142
80
|
}
|
143
81
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
static void fio_cli_parse(void) {
|
149
|
-
if (!FIO_CLI_ARGC || !FIO_CLI_ARGV) {
|
150
|
-
fprintf(
|
151
|
-
stderr,
|
152
|
-
"ERROR: (fio_cli) fio_cli_get_* "
|
153
|
-
"can only be called after `fio_cli_start` and before `fio_cli_end`\n");
|
154
|
-
exit(-1);
|
82
|
+
char const *fio_cli_get_line_type(fio_cli_parser_data_s *parser,
|
83
|
+
const char *line) {
|
84
|
+
if (!line) {
|
85
|
+
return NULL;
|
155
86
|
}
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
87
|
+
char const **pos = parser->names;
|
88
|
+
while (*pos) {
|
89
|
+
switch ((intptr_t)*pos) {
|
90
|
+
case /* FIO_CLI_TYPE_STRING */ 0x1: /* fallthrough */
|
91
|
+
case /* FIO_CLI_TYPE_BOOL */ 0x2: /* fallthrough */
|
92
|
+
case /* FIO_CLI_TYPE_INT */ 0x3: /* fallthrough */
|
93
|
+
++pos;
|
94
|
+
continue;
|
95
|
+
}
|
96
|
+
if (line == *pos) {
|
97
|
+
goto found;
|
98
|
+
}
|
99
|
+
++pos;
|
160
100
|
}
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
101
|
+
return NULL;
|
102
|
+
found:
|
103
|
+
switch ((size_t)pos[1]) {
|
104
|
+
case /* FIO_CLI_TYPE_STRING */ 0x1: /* fallthrough */
|
105
|
+
case /* FIO_CLI_TYPE_BOOL */ 0x2: /* fallthrough */
|
106
|
+
case /* FIO_CLI_TYPE_INT */ 0x3: /* fallthrough */
|
107
|
+
return pos[1];
|
108
|
+
}
|
109
|
+
return NULL;
|
110
|
+
}
|
111
|
+
|
112
|
+
static void fio_cli_set_arg(cstr_s arg, char const *value, char const *line,
|
113
|
+
fio_cli_parser_data_s *parser) {
|
114
|
+
/* handle unknown argument */
|
115
|
+
if (!line || !arg.len) {
|
116
|
+
if (!value) {
|
117
|
+
/*wtf?*/
|
118
|
+
return;
|
119
|
+
}
|
120
|
+
if (!strcmp(value, "-?") || !strcasecmp(value, "-h") ||
|
121
|
+
!strcasecmp(value, "-help") || !strcasecmp(value, "--help")) {
|
122
|
+
goto print_help;
|
123
|
+
}
|
124
|
+
cstr_s n = {.len = ++parser->unknown_count};
|
125
|
+
fio_hash_insert(&fio_values, n.len, n, value);
|
126
|
+
if (!parser->allow_unknown) {
|
127
|
+
arg.len = 0;
|
183
128
|
goto error;
|
184
129
|
}
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
130
|
+
return;
|
131
|
+
}
|
132
|
+
|
133
|
+
/* validate data types */
|
134
|
+
char const *type = fio_cli_get_line_type(parser, line);
|
135
|
+
switch ((size_t)type) {
|
136
|
+
case /* FIO_CLI_TYPE_BOOL */ 0x2:
|
137
|
+
if (value &&
|
138
|
+
(value == arg.data + arg.len ||
|
139
|
+
(value == arg.data + arg.len + 1 && arg.data[arg.len] == '='))) {
|
140
|
+
goto error;
|
192
141
|
}
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
142
|
+
value = "1";
|
143
|
+
break;
|
144
|
+
case /* FIO_CLI_TYPE_INT */ 0x3: /* fallthrough */
|
145
|
+
{
|
146
|
+
if (!value)
|
147
|
+
goto error;
|
148
|
+
char const *tmp = value;
|
149
|
+
if (*tmp == '-' || *tmp == '+') {
|
150
|
+
++tmp;
|
198
151
|
}
|
199
|
-
if (
|
152
|
+
if (!*tmp) {
|
200
153
|
goto error;
|
201
|
-
/* at this point arg_name is a handle to the argument's Symbol */
|
202
|
-
FIOBJ type = fiobj_hash_get(arg_type, arg_name);
|
203
|
-
if (FIOBJ_TYPE_IS(type, FIOBJ_T_NULL)) {
|
204
|
-
/* type is BOOL, no further processing required */
|
205
|
-
start = "1";
|
206
|
-
len = 1;
|
207
|
-
goto set_arg;
|
208
154
|
}
|
209
|
-
|
210
|
-
|
211
|
-
if (i == FIO_CLI_ARGC)
|
212
|
-
goto error;
|
213
|
-
start = FIO_CLI_ARGV[i];
|
214
|
-
} else if (start[len] == '=') {
|
215
|
-
start = start + len + 1;
|
216
|
-
} else
|
217
|
-
start = start + len;
|
218
|
-
len = 0;
|
219
|
-
if (FIOBJ_TYPE_IS(type, FIOBJ_T_FALSE)) /* no restrictions on data */
|
220
|
-
goto set_arg;
|
221
|
-
/* test that the argument is numerical */
|
222
|
-
if (start[len] == '-') /* negative number? */
|
223
|
-
len++;
|
224
|
-
while (start[len] >= '0' && start[len] <= '9')
|
225
|
-
len++;
|
226
|
-
if (start[len] == '.') { /* float number? */
|
227
|
-
while (start[len] >= '0' && start[len] <= '9')
|
228
|
-
len++;
|
155
|
+
while (*tmp && *tmp >= '0' && *tmp <= '9') {
|
156
|
+
++tmp;
|
229
157
|
}
|
230
|
-
if (
|
158
|
+
if (*tmp) {
|
231
159
|
goto error;
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
fprintf(stderr, "\n\t*** Argument Error: %s ***\n", start);
|
237
|
-
fio_cli_handle_error();
|
160
|
+
}
|
161
|
+
}
|
162
|
+
case /* FIO_CLI_TYPE_STRING */ 0x1: /* fallthrough */
|
163
|
+
break;
|
238
164
|
}
|
239
|
-
}
|
240
165
|
|
241
|
-
/*
|
242
|
-
|
243
|
-
|
166
|
+
/* add values using all aliases possible */
|
167
|
+
{
|
168
|
+
cstr_s n = {.data = line};
|
169
|
+
while (n.data[0] == '-') {
|
170
|
+
while (n.data[n.len] && n.data[n.len] != ' ' && n.data[n.len] != ',') {
|
171
|
+
++n.len;
|
172
|
+
}
|
173
|
+
fio_hash_insert(&fio_values, FIO_CLI_HASH_VAL(n), n, value);
|
174
|
+
while (n.data[n.len] && (n.data[n.len] == ' ' || n.data[n.len] == ',')) {
|
175
|
+
++n.len;
|
176
|
+
}
|
177
|
+
n.data += n.len;
|
178
|
+
n.len = 0;
|
179
|
+
}
|
180
|
+
}
|
244
181
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
fiobj_free(info_str);
|
251
|
-
if (info) {
|
252
|
-
info_str = fiobj_str_new(info, strlen(info));
|
253
|
-
} else {
|
254
|
-
info_str = fiobj_str_new(DEFAULT_CLI_INFO, sizeof(DEFAULT_CLI_INFO) - 1);
|
182
|
+
/* handle additional argv progress (if value is on separate argv) */
|
183
|
+
if (type != FIO_CLI_TYPE_BOOL && value && value != arg.data + arg.len &&
|
184
|
+
!arg.data[arg.len]) {
|
185
|
+
/* advance the position marker more than once? */
|
186
|
+
++parser->pos;
|
255
187
|
}
|
256
|
-
|
188
|
+
return;
|
189
|
+
|
190
|
+
error: /* handle errors*/
|
191
|
+
/* TODO! */
|
192
|
+
fprintf(stderr, "\n\r\x1B[31mError:\x1B[0m unknown argument %.*s %s %s\n\n",
|
193
|
+
(int)arg.len, arg.data, arg.len ? "with value" : "",
|
194
|
+
value ? value : "(null)");
|
195
|
+
print_help:
|
196
|
+
fprintf(stderr, "\n%s\n\n",
|
197
|
+
parser->description ? parser->description
|
198
|
+
: "This application accepts any of the following "
|
199
|
+
"possible arguments:");
|
200
|
+
/* print out each line's arguments */
|
201
|
+
char const **pos = parser->names;
|
202
|
+
while (*pos) {
|
203
|
+
switch ((intptr_t)*pos) {
|
204
|
+
case /* FIO_CLI_TYPE_STRING */ 0x1: /* fallthrough */
|
205
|
+
case /* FIO_CLI_TYPE_BOOL */ 0x2: /* fallthrough */
|
206
|
+
case /* FIO_CLI_TYPE_INT */ 0x3: /* fallthrough */
|
207
|
+
++pos;
|
208
|
+
continue;
|
209
|
+
}
|
210
|
+
type = FIO_CLI_TYPE_STRING;
|
211
|
+
switch ((intptr_t)pos[1]) {
|
212
|
+
case /* FIO_CLI_TYPE_STRING */ 0x1: /* fallthrough */
|
213
|
+
case /* FIO_CLI_TYPE_BOOL */ 0x2: /* fallthrough */
|
214
|
+
case /* FIO_CLI_TYPE_INT */ 0x3: /* fallthrough */
|
215
|
+
type = pos[1];
|
216
|
+
}
|
217
|
+
/* print line @ pos, starting with main argument name */
|
218
|
+
int alias_count = 0;
|
219
|
+
int first_len = 0;
|
220
|
+
size_t tmp = 0;
|
221
|
+
char const *const p = *pos;
|
222
|
+
while (p[tmp] == '-') {
|
223
|
+
while (p[tmp] && p[tmp] != ' ' && p[tmp] != ',') {
|
224
|
+
if (!alias_count)
|
225
|
+
++first_len;
|
226
|
+
++tmp;
|
227
|
+
}
|
228
|
+
++alias_count;
|
229
|
+
while (p[tmp] && (p[tmp] == ' ' || p[tmp] == ',')) {
|
230
|
+
++tmp;
|
231
|
+
}
|
232
|
+
}
|
233
|
+
switch ((size_t)type) {
|
234
|
+
case /* FIO_CLI_TYPE_STRING */ 0x1:
|
235
|
+
fprintf(stderr, "\t\x1B[1m%.*s\x1B[0m\x1B[2m <val>\x1B[0m\t%s\n",
|
236
|
+
first_len, p, p + tmp);
|
237
|
+
break;
|
238
|
+
case /* FIO_CLI_TYPE_BOOL */ 0x2:
|
239
|
+
fprintf(stderr, "\t\x1B[1m%.*s\x1B[0m \t%s\n", first_len, p,
|
240
|
+
p + tmp);
|
241
|
+
break;
|
242
|
+
case /* FIO_CLI_TYPE_INT */ 0x3:
|
243
|
+
fprintf(stderr, "\t\x1B[1m%.*s\x1B[0m\x1B[2m ### \x1B[0m\t%s\n",
|
244
|
+
first_len, p, p + tmp);
|
245
|
+
break;
|
246
|
+
}
|
247
|
+
/* print aliase information */
|
248
|
+
tmp = first_len;
|
249
|
+
while (p[tmp] && (p[tmp] == ' ' || p[tmp] == ',')) {
|
250
|
+
++tmp;
|
251
|
+
}
|
252
|
+
while (p[tmp] == '-') {
|
253
|
+
const size_t start = tmp;
|
254
|
+
while (p[tmp] && p[tmp] != ' ' && p[tmp] != ',') {
|
255
|
+
++tmp;
|
256
|
+
}
|
257
|
+
switch ((size_t)type) {
|
258
|
+
case /* FIO_CLI_TYPE_STRING */ 0x1:
|
259
|
+
fprintf(stderr,
|
260
|
+
"\t\x1B[1m%.*s\x1B[0m\x1B[2m <val>\x1B[0m\t(same as "
|
261
|
+
"\x1B[1m%.*s\x1B[0m)\n",
|
262
|
+
(int)(tmp - start), p + start, first_len, p);
|
263
|
+
break;
|
264
|
+
case /* FIO_CLI_TYPE_BOOL */ 0x2:
|
265
|
+
fprintf(stderr,
|
266
|
+
"\t\x1B[1m%.*s\x1B[0m \t(same as \x1B[1m%.*s\x1B[0m)\n",
|
267
|
+
(int)(tmp - start), p + start, first_len, p);
|
268
|
+
break;
|
269
|
+
case /* FIO_CLI_TYPE_INT */ 0x3:
|
270
|
+
fprintf(stderr,
|
271
|
+
"\t\x1B[1m%.*s\x1B[0m\x1B[2m ### \x1B[0m\t(same as "
|
272
|
+
"\x1B[1m%.*s\x1B[0m)\n",
|
273
|
+
(int)(tmp - start), p + start, first_len, p);
|
274
|
+
break;
|
275
|
+
}
|
276
|
+
}
|
257
277
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
free_and_reset(arg_type);
|
268
|
-
free_and_reset(help_str);
|
269
|
-
free_and_reset(info_str);
|
270
|
-
if (parsed)
|
271
|
-
free_and_reset(parsed);
|
272
|
-
|
273
|
-
#undef free_and_reset
|
274
|
-
|
275
|
-
FIO_CLI_ARGC = 0;
|
276
|
-
FIO_CLI_ARGV = NULL;
|
277
|
-
is_parsed = 0;
|
278
|
+
++pos;
|
279
|
+
}
|
280
|
+
fprintf(stderr, "\nUse any of the following input formats:\n"
|
281
|
+
"\t-arg <value>\t-arg=<value>\t-arg<value>\n"
|
282
|
+
"\n"
|
283
|
+
"Use the -h, -help or -? to get this information again.\n"
|
284
|
+
"\n");
|
285
|
+
fio_cli_end();
|
286
|
+
exit(0);
|
278
287
|
}
|
279
288
|
|
280
|
-
|
281
|
-
*
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
* message.
|
293
|
-
*/
|
294
|
-
void fio_cli_accept_num(const char *aliases, const char *desc) {
|
295
|
-
fio_cli_set(aliases, desc, CLI_NUM);
|
296
|
-
}
|
289
|
+
void fio_cli_start AVOID_MACRO(int argc, char const *argv[], int allow_unknown,
|
290
|
+
char const *description, char const **names) {
|
291
|
+
fio_cli_parser_data_s parser = {
|
292
|
+
.allow_unknown = allow_unknown,
|
293
|
+
.description = description,
|
294
|
+
.names = names,
|
295
|
+
.pos = 0,
|
296
|
+
};
|
297
|
+
|
298
|
+
if (fio_hash_count(&fio_values)) {
|
299
|
+
fio_cli_end();
|
300
|
+
}
|
297
301
|
|
298
|
-
|
299
|
-
* Sets a CLI acceptable argument of type String.
|
300
|
-
*
|
301
|
-
* The `aliases` string sets aliases for the same argument. i.e. "string s".
|
302
|
-
*
|
303
|
-
* The first alias will be the name used
|
304
|
-
*
|
305
|
-
* The `desc` string will be printed if `-?`, `-h` of `-help` are used.
|
306
|
-
*
|
307
|
-
* The function will crash the application on failure, printing an error
|
308
|
-
* message.
|
309
|
-
*/
|
310
|
-
void fio_cli_accept_str(const char *aliases, const char *desc) {
|
311
|
-
fio_cli_set(aliases, desc, CLI_STR);
|
312
|
-
}
|
302
|
+
/* prepare aliases hash map */
|
313
303
|
|
314
|
-
|
315
|
-
*
|
316
|
-
*
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
304
|
+
char const **line = names;
|
305
|
+
while (*line) {
|
306
|
+
switch ((intptr_t)*line) {
|
307
|
+
case /* FIO_CLI_TYPE_STRING */ 0x1: /* fallthrough */
|
308
|
+
case /* FIO_CLI_TYPE_BOOL */ 0x2: /* fallthrough */
|
309
|
+
case /* FIO_CLI_TYPE_INT */ 0x3: /* fallthrough */
|
310
|
+
++line;
|
311
|
+
continue;
|
312
|
+
}
|
313
|
+
fio_cli_map_line2alias(*line);
|
314
|
+
++line;
|
315
|
+
}
|
316
|
+
|
317
|
+
/* parse existing arguments */
|
318
|
+
|
319
|
+
while ((++parser.pos) < argc) {
|
320
|
+
char const *value = NULL;
|
321
|
+
cstr_s n = {.data = argv[parser.pos], .len = strlen(argv[parser.pos])};
|
322
|
+
if (parser.pos + 1 < argc) {
|
323
|
+
value = argv[parser.pos + 1];
|
324
|
+
}
|
325
|
+
const char **l = NULL;
|
326
|
+
while (n.len &&
|
327
|
+
!(l = fio_hash_find(&fio_aliases, FIO_CLI_HASH_VAL(n), n))) {
|
328
|
+
--n.len;
|
329
|
+
value = n.data + n.len;
|
330
|
+
}
|
331
|
+
if (n.len && value && value[0] == '=') {
|
332
|
+
++value;
|
333
|
+
}
|
334
|
+
// fprintf(stderr, "Setting %.*s to %s\n", (int)n.len, n.data, value);
|
335
|
+
fio_cli_set_arg(n, value, (l ? (*l) : NULL), &parser);
|
336
|
+
}
|
337
|
+
|
338
|
+
/* Cleanup and save state for API */
|
339
|
+
fio_hash_free(&fio_aliases);
|
340
|
+
fio_unknown_count = parser.unknown_count;
|
328
341
|
}
|
329
342
|
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
const char *fio_cli_get_str(const char *opt) {
|
335
|
-
fio_cli_parse();
|
336
|
-
FIOBJ name = fio_cli_get_name(opt, strlen(opt));
|
337
|
-
if (!name)
|
338
|
-
return NULL;
|
339
|
-
FIOBJ result = fiobj_hash_get(parsed, name);
|
340
|
-
if (!result)
|
341
|
-
return NULL;
|
342
|
-
return fiobj_obj2cstr(result).data;
|
343
|
+
void fio_cli_end(void) {
|
344
|
+
fio_hash_free(&fio_values);
|
345
|
+
fio_hash_free(&fio_aliases);
|
346
|
+
fio_unknown_count = 0;
|
343
347
|
}
|
348
|
+
/* *****************************************************************************
|
349
|
+
CLI Data Access
|
350
|
+
***************************************************************************** */
|
344
351
|
|
345
|
-
/**
|
346
|
-
*
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
FIOBJ result = fiobj_hash_get(parsed, name);
|
356
|
-
if (!result)
|
357
|
-
return 0;
|
358
|
-
return (int)fiobj_obj2num(result);
|
352
|
+
/** Returns the argument's value as a NUL terminated C String. */
|
353
|
+
char const *fio_cli_get(char const *name) {
|
354
|
+
cstr_s n = {.data = name, .len = strlen(name)};
|
355
|
+
if (!fio_hash_count(&fio_values)) {
|
356
|
+
return NULL;
|
357
|
+
}
|
358
|
+
const char **val = fio_hash_find(&fio_values, FIO_CLI_HASH_VAL(n), n);
|
359
|
+
if (val)
|
360
|
+
return *val;
|
361
|
+
return NULL;
|
359
362
|
}
|
360
363
|
|
361
|
-
/**
|
362
|
-
|
363
|
-
*
|
364
|
-
|
365
|
-
*/
|
366
|
-
double fio_cli_get_float(const char *opt) {
|
367
|
-
fio_cli_parse();
|
368
|
-
FIOBJ name = fio_cli_get_name(opt, strlen(opt));
|
369
|
-
if (!name)
|
364
|
+
/** Returns the argument's value as an integer. */
|
365
|
+
int fio_cli_get_i(char const *name) {
|
366
|
+
char const *val = fio_cli_get(name);
|
367
|
+
if (!val)
|
370
368
|
return 0;
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
369
|
+
int ret = 0;
|
370
|
+
int invert = 0;
|
371
|
+
while (*val == '-' || *val == '+') {
|
372
|
+
if (*val == '-') {
|
373
|
+
invert += 1;
|
374
|
+
}
|
375
|
+
++val;
|
376
|
+
}
|
377
|
+
while (*val) {
|
378
|
+
ret = (ret * 10) + (*val - '0');
|
379
|
+
++val;
|
380
|
+
}
|
381
|
+
if ((invert & 1)) {
|
382
|
+
ret = 0 - ret;
|
383
|
+
}
|
384
|
+
return ret;
|
375
385
|
}
|
376
386
|
|
377
|
-
/**
|
378
|
-
|
379
|
-
|
380
|
-
* Boolean that were set to TRUE have the string "1".
|
381
|
-
*/
|
382
|
-
void fio_cli_set_str(const char *opt, const char *value) {
|
383
|
-
fio_cli_parse();
|
384
|
-
FIOBJ name = fio_cli_get_name(opt, strlen(opt));
|
385
|
-
if (!name) {
|
386
|
-
fprintf(stderr, "ERROR: facil.io's CLI helper can only override values for "
|
387
|
-
"valid options\n");
|
388
|
-
exit(-1);
|
389
|
-
}
|
390
|
-
fiobj_hash_set(parsed, name, fiobj_str_new(value, strlen(value)));
|
387
|
+
/** Returns the number of unrecognized argument. */
|
388
|
+
unsigned int fio_cli_unknown_count(void) {
|
389
|
+
return (unsigned int)fio_unknown_count;
|
391
390
|
}
|
392
391
|
|
393
|
-
/**
|
394
|
-
*
|
395
|
-
|
396
|
-
|
397
|
-
*/
|
398
|
-
void fio_cli_set_int(const char *opt, int value) {
|
399
|
-
fio_cli_parse();
|
400
|
-
FIOBJ name = fio_cli_get_name(opt, strlen(opt));
|
401
|
-
if (!name) {
|
402
|
-
fprintf(stderr, "ERROR: facil.io's CLI helper can only override values for "
|
403
|
-
"valid options\n");
|
404
|
-
exit(-1);
|
392
|
+
/** Returns the unrecognized argument using a 0 based `index`. */
|
393
|
+
char const *fio_cli_unknown(unsigned int index) {
|
394
|
+
if (!fio_hash_count(&fio_values) || !fio_unknown_count) {
|
395
|
+
return NULL;
|
405
396
|
}
|
406
|
-
|
397
|
+
cstr_s n = {.data = NULL, .len = index + 1};
|
398
|
+
const char **val = fio_hash_find(&fio_values, index + 1, n);
|
399
|
+
if (val)
|
400
|
+
return *val;
|
401
|
+
return NULL;
|
407
402
|
}
|
408
403
|
|
409
404
|
/**
|
410
|
-
*
|
405
|
+
* Sets the argument's value as a NUL terminated C String (no copy!).
|
411
406
|
*
|
412
|
-
*
|
407
|
+
* Note: this does NOT copy the C strings to memory. Memory should be kept
|
408
|
+
* alive until `fio_cli_end` is called.
|
413
409
|
*/
|
414
|
-
void
|
415
|
-
|
416
|
-
|
417
|
-
if (!name) {
|
418
|
-
fprintf(stderr, "ERROR: facil.io's CLI helper can only override values for "
|
419
|
-
"valid options\n");
|
420
|
-
exit(-1);
|
421
|
-
}
|
422
|
-
fiobj_hash_set(parsed, name, fiobj_float_new(value));
|
410
|
+
void fio_cli_set(char const *name, char const *value) {
|
411
|
+
cstr_s n = (cstr_s){.data = name, .len = strlen(name)};
|
412
|
+
fio_hash_insert(&fio_values, FIO_CLI_HASH_VAL(n), n, value);
|
423
413
|
}
|