cemu
载入中...
搜索中...
未找到
argparse-new.h
浏览该文件的文档.
1
12#ifndef __ARGPARSE_H__
13#define __ARGPARSE_H__
14
15#include <stdbool.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19
20/* 解析器包含的子命令数 */
21#ifndef AP_MAX_NCOMMAND
22#define AP_MAX_NCOMMAND 10
23#endif
24
25/* 长参数名前的flag */
26#ifndef AP_LONG_FLAG
27#define AP_LONG_FLAG "--"
28#endif
29
30/* 短参数名前的flag */
31#ifndef AP_SHORT_FLAG
32#define AP_SHORT_FLAG "-"
33#endif
34
35#define AP_END \
36 { \
37 0 \
38 }
39
40#define ap_min(a, b) ((a) > (b) ? (b) : (a))
41#define ap_max(a, b) ((a) > (b) ? (a) : (b))
42
43#define NOW (&pp->commands[pp->command_pos])
44
45/* 错误提示 */
46
47#define _green(s) "\033[32m" s "\033[0m"
48#define _red(s) "\033[31m" s "\033[0m"
49#define ERROR_MSG _red("[ERROR]")
50#define e(msg) (ERROR_MSG ": " msg "\n")
51
52// 命令冲突
53#ifndef ERROR_COMMAND_CONFLICT
54#define ERROR_COMMAND_CONFLICT e("Conflict.")
55#endif
56
57// 没有传递子命令
58#ifndef ERROR_NO_SUBCOMMAND
59#define ERROR_NO_SUBCOMMAND e("Pass a subcommand.")
60#endif
61
62// 没有传递参数值
63#ifndef ERROR_LOST_ARG_VALUE
64#define ERROR_LOST_ARG_VALUE e("\"%s\" lost arg value.")
65#endif
66
67#ifndef ERROR_DONOT_NEED_VALUE
68#define ERROR_DONOT_NEED_VALUE e("\"%s\" does not need arg value.")
69#endif
70
71#ifndef ERROR_ARG_NOT_EXIST
72#define ERROR_ARG_NOT_EXIST e("Arg name \"%s\" does not exist.")
73#endif
74
75#ifndef ERROR_LOST_ARG_NAME
76#define ERROR_LOST_ARG_NAME e("Except a arg name, but got \"%s\".")
77#endif
78
79#ifndef ERROR_SUBCOMMAND_NOT_EXIST
80#define ERROR_SUBCOMMAND_NOT_EXIST e("Subcommand %s does not exist.")
81#endif
82
83/* 是否跟随参数 */
84typedef enum {
85 AP_YES = 0,
86 AP_NO
87} ArgValue;
88
89typedef struct
90{
91 /* 单短线参数名 */
92 char* short_arg;
93 /* 双短线参数名 */
94 char* long_arg;
95 /* 是否跟随参数值 */
96 ArgValue arg_have_value;
97 /* 传递值 */
98 char* value;
99 /* 初始值 */
100 union {
101 int i;
102 bool b;
103 float f;
104 char* s;
105 void* v;
106 } init;
107 /* 参数的说明 */
108 char* help;
109} ap_arg_t;
110
111/* 定义参数用到的宏 */
112#define ap_defineArgs(name) static ap_arg_t name[]
113#define ap_defineCallback(name) void name(int argc, char* argv[], char* env[])
114
115/* command对应的回调函数 */
116typedef void (*callback_t)(int argc, char* argv[], char* env[]);
117
118typedef struct
119{
120 /* 命令名
121 * - 全局命令为NULL
122 * - 子命令时,为子命令名
123 **/
124 char* command;
125 /* 对命令的描述 */
126 char* description;
127 /* 命令的用法 */
128 char* usage;
129 /* 是否是子命令 */
130 int subcommand;
131 /* 参数个数 */
132 int nargs;
133 /* 命令的回调函数 */
134 callback_t callback;
135 /* 存储的参数 */
136 ap_arg_t* args;
138
139/* 打印command的回调函数 */
140typedef void (*print_ap_command_t)(ap_command_t*);
141
142typedef struct Parser Parser;
143struct Parser {
144 /* 程序开始运行打印的内容
145 * 可以是logo之类的
146 **/
147 char* print;
148 /* 命令个数 */
149 int ncommand;
150 /* 存储的命令 */
151 ap_command_t commands[AP_MAX_NCOMMAND];
152 /* 当前命令行使用的command命令 */
153 int command_pos;
154 /* 自定义打印command参数 */
155 print_ap_command_t print_command;
156} p = {
157 .ncommand = 0,
158 .command_pos = 0},
159 *pp = &p;
160
161static int have_global = 0;
162static int have_subcommand = 0;
163
170static inline void
171ap_init_parser(char* print_message, print_ap_command_t print_command)
172{
173 pp->print = print_message;
174 if (print_command != NULL) {
175 pp->print_command = print_command;
176 }
177}
178
188static inline void
190 char* command,
191 char* description,
192 char* usage,
193 callback_t callback,
194 ap_arg_t* args)
195{
196 if (command == NULL) {
197 have_global = 1;
198 } else {
199 have_subcommand = 1;
200 }
201 /* 全局命令和子命令有且只能存在一种
202 * 要么有一个全局命令
203 * 要么存在多个子命令
204 **/
205
206 if (have_global && have_subcommand) {
207 fprintf(stderr, ERROR_COMMAND_CONFLICT);
208 exit(1);
209 }
210 if (!(have_global || have_subcommand)) {
211 fprintf(stderr, ERROR_NO_SUBCOMMAND);
212 exit(1);
213 }
214
215 if (pp->ncommand > AP_MAX_NCOMMAND - 1) {
216 fprintf(stderr, _red("[ERROR]:") "Too many commands. Change AP_MAX_NCOMMAND bigger.\n");
217 exit(1);
218 }
219
220 pp->commands[pp->ncommand].command = command;
221 pp->commands[pp->ncommand].description= (char *)malloc(strlen(description) + 1);
222 strcpy(pp->commands[pp->ncommand].description, description == NULL ? "" : description);
223 pp->commands[pp->ncommand].usage = (char *)malloc(strlen(usage) + 1);
224 strcpy(pp->commands[pp->ncommand].usage, usage == NULL ? "" : usage);
225 pp->commands[pp->ncommand].callback = callback;
226 pp->commands[pp->ncommand].args = args;
227 // 统计当前command有多少参数
228 int nargs = 0;
229 while (1) {
230 if (args[nargs].long_arg || args[nargs].short_arg) {
231 if (args[nargs].help == NULL) {
232 args[nargs].help = "";
233 }
234 nargs++;
235 } else {
236 break;
237 }
238 }
239 pp->commands[pp->ncommand].nargs = nargs;
240 pp->ncommand++;
241}
242
250static inline int
251_is_eq(char* arg_name, ap_arg_t arg)
252{
253 char* short_arg = arg.short_arg;
254 char* long_arg = arg.long_arg;
255 if (strcmp(arg_name, long_arg) == 0 || strcmp(arg_name, short_arg) == 0) {
256 return 1;
257 }
258 return 0;
259}
260
267static inline ap_arg_t*
268ap_get(char* arg_name)
269{
270 if ((NOW) == NULL) {
271 return NULL;
272 }
273
274 ap_arg_t* p = NULL;
275 int nargs = (NOW)->nargs;
276 ap_arg_t* args = (NOW)->args;
277 for (int i = 0; i < nargs; i++) {
278 if (_is_eq(arg_name, args[i])) {
279 p = &args[i];
280 break;
281 }
282 }
283 return p;
284}
285
291static inline void
293{
294 fprintf(stderr, "\n" _green("%s") "\n%s\n", c->command, c->description);
295 fprintf(stderr, "%s\n", c->usage);
296 for (size_t i = 0; i < c->nargs; i++) {
297 fprintf(
298 stderr,
299 "%s%s %s%s%4s%s\n",
300 AP_SHORT_FLAG,
301 c->args[i].short_arg,
302 AP_LONG_FLAG,
303 c->args[i].long_arg,
304 "",
305 c->args[i].help);
306 }
307 fprintf(stderr, "\n");
308}
309
314static inline void
316{
317 fprintf(stderr, "\n%s\n\n", pp->print);
318 if (pp->ncommand > 1) {
319 fprintf(stderr, "Commands:\n");
320 for (size_t i = 0; i < pp->ncommand; i++) {
321 fprintf(stderr, _green("%8s ") "%s\n", pp->commands[i].command, pp->commands[i].description);
322 }
323 } else {
324 pp->print_command(NOW);
325 }
326
327 fprintf(stderr, "\n");
328}
329
330static inline void
331ap_print_command(void)
332{
333 if (!pp->print_command) {
335 } else {
336 pp->print_command(NOW);
337 }
338}
339
346static inline void
347_ap_parser_command_line(int argc, char* argv[])
348{
349 if (argc > 0) {
350 if (strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "--help") == 0) {
351 ap_print_command( );
352 exit(0);
353 }
354 }
355 // 当前是参数名状态,还是参数值状态
356 // 为0为参数名状态
357 // 为1为参数值状态
358 int status = 0;
359
360 // 解析的位置
361 int count = 0;
362
363 // 参数名的前缀长度
364 int short_flag_len = strlen(AP_SHORT_FLAG);
365 int long_flag_len = strlen(AP_LONG_FLAG);
366
367 // 准备装载的参数
368 ap_arg_t* arg = NULL;
369 char* arg_name = NULL;
370 for (;;) {
371 if (count >= argc) {
372 break;
373 }
374
375 // 解析器的位置
376 char* need_parse = argv[count];
377 int need_parse_len = strlen(need_parse);
378
379 // 判断是否为一个参数名
380 int is_short = strncmp(need_parse, AP_SHORT_FLAG, ap_min(need_parse_len, short_flag_len)) == 0;
381 int is_long = strncmp(need_parse, AP_LONG_FLAG, ap_min(need_parse_len, long_flag_len)) == 0;
382
383 if (is_short || is_long) {
384 status = 0;
385 // 去掉参数名前面的prefix
386 const char* prefix;
387 if (is_long) {
388 prefix = AP_LONG_FLAG;
389 } else {
390 prefix = AP_SHORT_FLAG;
391 }
392 int prefix_len = strlen(prefix);
393 arg_name = need_parse + prefix_len;
394
395 // 检查参数是否存在
396 int exist = 0;
397 for (int i = 0; i < (NOW)->nargs; i++) {
398 arg = &((NOW)->args[i]);
399 int short_succ = strcmp(arg_name, arg->short_arg) == 0;
400 int long_succ = strcmp(arg_name, arg->long_arg) == 0;
401 if (short_succ || long_succ) {
402 exist = 1;
403 break;
404 }
405 }
406 if (!exist) {
407 fprintf(stderr, ERROR_ARG_NOT_EXIST, arg_name - prefix_len);
408 exit(1);
409 }
410 } else {
411 // 参数值/一个位置参数
412 status = 1;
413 }
414
415 if (arg == NULL) {
416 fprintf(stderr, ERROR_LOST_ARG_NAME, need_parse);
417 exit(1);
418 }
419
420 // 根据status来进行下一步的处理
421 if (status && arg->arg_have_value == AP_NO) {
422 // 不需要参数值
423 fprintf(stderr, ERROR_DONOT_NEED_VALUE, arg->long_arg);
424 exit(1);
425 }
426
427 if (status && arg->arg_have_value == AP_YES) {
428 arg->value = need_parse;
429 arg = NULL;
430 }
431
432 if (!status && arg->arg_have_value == AP_NO) {
433 arg->init.b = 1;
434 }
435 count++;
436 }
437 if (arg && arg->arg_have_value == AP_YES) {
438 fprintf(stderr, ERROR_LOST_ARG_VALUE, arg->long_arg);
439 exit(1);
440 }
441}
442
449static inline void
450ap_do_parser(int argc, char* argv[], char* env[])
451{
452 int argc_copy = argc;
453 char** argv_copy = argv;
454 if (argc > 1) {
455 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
457 exit(0);
458 }
459 }
460
461 // 跳过文件名
462 argc--;
463 argv++;
464 if (have_subcommand) {
465 char* subcommand;
466 int exist = 0;
467 if (!argc) {
469 fprintf(stderr, ERROR_NO_SUBCOMMAND);
470 exit(1);
471 }
472 subcommand = argv[0];
473 /* 在这里自动装载子命令 */
474 for (int i = 0; i < pp->ncommand; i++) {
475 if (strcmp(pp->commands[i].command, subcommand) == 0) {
476 pp->commands[i].subcommand = 1;
477 pp->command_pos = i;
478 exist = 1;
479 break;
480 }
481 }
482 if (!exist) {
483 fprintf(stderr, ERROR_SUBCOMMAND_NOT_EXIST, subcommand);
484 exit(1);
485 }
486 } else {
487 // 只有全局命令
488 pp->command_pos = 0;
489 }
490
491 /* 开始解析命令行参数 */
492 _ap_parser_command_line(argc - have_subcommand, argv + have_subcommand);
493 /* 开始调用回调函数 */
494 (NOW)->callback(argc_copy, argv_copy, env);
495}
496
497#endif
static ap_arg_t * ap_get(char *arg_name)
根据参数名获取参数值
Definition argparse-new.h:268
static void ap_do_parser(int argc, char *argv[], char *env[])
解析命令行
Definition argparse-new.h:450
static void ap_init_parser(char *print_message, print_ap_command_t print_command)
初始化解析器
Definition argparse-new.h:171
static int _is_eq(char *arg_name, ap_arg_t arg)
判断当前参数名是否与command中的参数名相同
Definition argparse-new.h:251
static void ap_default_print_command(ap_command_t *c)
打印command
Definition argparse-new.h:292
static void ap_add_command(char *command, char *description, char *usage, callback_t callback, ap_arg_t *args)
添加一个子命令
Definition argparse-new.h:189
static void ap_print_parser(void)
打印解析器
Definition argparse-new.h:315
static void _ap_parser_command_line(int argc, char *argv[])
解析命令行,内部接口
Definition argparse-new.h:347
#define NULL
Definition list.h:22
Definition argparse-new.h:143
Definition argparse-new.h:90
Definition argparse-new.h:119