[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemacs-commit] qemacs qe.c qe.h util.c x11.c
From: |
Charlie Gordon |
Subject: |
[Qemacs-commit] qemacs qe.c qe.h util.c x11.c |
Date: |
Sun, 16 Apr 2017 13:20:49 -0400 (EDT) |
CVSROOT: /sources/qemacs
Module name: qemacs
Changes by: Charlie Gordon <chqrlie> 17/04/16 13:20:49
Modified files:
. : qe.c qe.h util.c x11.c
Log message:
basic: improve command line parsing
- add qe_strtobool(str, def). Returns boolean value from str:
y yes t true 1 evaluate to true
any other string evaluates to false
the empty string evaluates to def
- add bstr_t type:
constant bounded string with pointer and length.
bstr_make creates a bstr_t from a string pointer or NULL
bstr_token creates a bstr_t from a string upto a separator
bstr_get_nth creates a bstr_t from a the nth element of a string list
bstr_equal compares bstr_t objects for equality
- use macros for type safe registation of command line options
- combine short, long, argument names and help string
- support command line options with optional arguments
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/qemacs/qe.c?cvsroot=qemacs&r1=1.266&r2=1.267
http://cvs.savannah.gnu.org/viewcvs/qemacs/qe.h?cvsroot=qemacs&r1=1.248&r2=1.249
http://cvs.savannah.gnu.org/viewcvs/qemacs/util.c?cvsroot=qemacs&r1=1.80&r2=1.81
http://cvs.savannah.gnu.org/viewcvs/qemacs/x11.c?cvsroot=qemacs&r1=1.48&r2=1.49
Patches:
Index: qe.c
===================================================================
RCS file: /sources/qemacs/qemacs/qe.c,v
retrieving revision 1.266
retrieving revision 1.267
diff -u -b -r1.266 -r1.267
--- qe.c 15 Apr 2017 13:10:53 -0000 1.266
+++ qe.c 16 Apr 2017 17:20:49 -0000 1.267
@@ -8176,21 +8176,19 @@
/******************************************************/
/* command line option handling */
-static CmdOptionDef *first_cmd_options;
+static CmdLineOptionDef *first_cmd_options;
-void qe_register_cmd_line_options(CmdOptionDef *table)
+void qe_register_cmd_line_options(CmdLineOptionDef *table)
{
- CmdOptionDef **pp, *p;
+ CmdLineOptionDef **pp, *p;
/* link command line options table at end of list */
- pp = &first_cmd_options;
- while (*pp != NULL) {
+ for (pp = &first_cmd_options; *pp != NULL; pp = &p->u.next) {
p = *pp;
if (p == table)
return; /* already registered */
- while (p->name != NULL)
+ while (p->desc != NULL)
p++;
- pp = &p->u.next;
}
*pp = table;
}
@@ -8213,8 +8211,7 @@
static void show_usage(void)
{
- CmdOptionDef *p;
- int pos;
+ CmdLineOptionDef *p;
printf("Usage: qe [OPTIONS] [filename ...]\n"
"\n"
@@ -8222,20 +8219,26 @@
"\n");
/* print all registered command line options */
- p = first_cmd_options;
- while (p != NULL) {
- while (p->name != NULL) {
- pos = printf("--%s", p->name);
- if (p->shortname)
- pos += printf(", -%s", p->shortname);
- if (p->flags & CMD_OPT_ARG)
- pos += printf(" %s", p->argname);
- if (pos < 24)
- printf("%*s", pos - 24, "");
- printf("%s\n", p->help);
+ for (p = first_cmd_options; p != NULL; p = p->u.next) {
+ while (p->desc != NULL) {
+ const char *s = p->desc;
+ bstr_t shortname = bstr_token(s, '|', &s);
+ bstr_t name = bstr_token(s, '|', &s);
+ bstr_t argname = bstr_token(s, '|', &s);
+ bstr_t help = bstr_make(s);
+ int pos = printf(" ");
+
+ if (shortname.len)
+ pos += printf(" -%.*s", shortname.len, shortname.s);
+ if (name.len)
+ pos += printf(" --%.*s", name.len, name.s);
+ if (argname.len)
+ pos += printf(" %.*s", argname.len, argname.s);
+ if (pos < 22)
+ printf("%*s", pos - 22, "");
+ printf(" %.*s\n", help.len, help.s);
p++;
}
- p = p->u.next;
}
printf("\n"
"Report bugs to address@hidden First, please see the Bugs\n"
@@ -8247,60 +8250,79 @@
{
int _optind;
- _optind = 1;
- for (;;) {
- const char *r, *r1, *r2, *_optarg;
- CmdOptionDef *p;
+ for (_optind = 1; _optind < argc;) {
+ const char *arg, *r, *_optarg;
+ CmdLineOptionDef *p;
+ bstr_t opt1;
+ bstr_t opt2;
- if (_optind >= argc)
- break;
- r = argv[_optind];
+ r = arg = argv[_optind];
/* stop before first non option */
if (r[0] != '-')
break;
_optind++;
- r2 = r1 = r + 1;
- if (r2[0] == '-') {
- r2++;
+ opt1.s = opt2.s = r + 1;
+ if (r[1] == '-') {
+ opt2.s++;
/* stop after `--' marker */
- if (r2[0] == '\0')
+ if (r[2] == '\0')
+ break;
+ }
+ /* parse optional argument specified with opt=arg or opt:arg syntax */
+ _optarg = NULL;
+ while (*r) {
+ if (*r == ':' || *r == '=') {
+ _optarg = r + 1;
break;
}
+ r++;
+ }
+ opt1.len = r - opt1.s;
+ opt2.len = r - opt2.s;
- p = first_cmd_options;
- while (p != NULL) {
- while (p->name != NULL) {
- if (strequal(p->name, r2) ||
- (p->shortname && strequal(p->shortname, r1))) {
- if (p->flags & CMD_OPT_ARG) {
+ for (p = first_cmd_options; p != NULL; p = p->u.next) {
+ while (p->desc != NULL) {
+ const char *s = p->desc;
+ bstr_t shortname = bstr_token(s, '|', &s);
+ bstr_t name = bstr_token(s, '|', &s);
+ bstr_t argname = bstr_token(s, '|', &s);
+ if (bstr_equal(opt1, shortname) || bstr_equal(opt2, name)) {
+ if (argname.len && _optarg == NULL) {
if (_optind >= argc) {
put_status(NULL,
- "cmdline argument expected -- %s", r);
+ "cmdline argument %.*s expected for
--%.*s",
+ argname.len, argname.s, name.len,
name.s);
goto next_cmd;
}
_optarg = argv[_optind++];
- } else {
- _optarg = NULL;
}
- if (p->flags & CMD_OPT_BOOL) {
- *p->u.int_ptr = 1;
- } else if (p->flags & CMD_OPT_STRING) {
- *p->u.string_ptr = _optarg;
- } else if (p->flags & CMD_OPT_INT) {
+ switch (p->type) {
+ case CMD_LINE_TYPE_BOOL:
+ *p->u.int_ptr = qe_strtobool(_optarg, 1);
+ break;
+ case CMD_LINE_TYPE_INT:
*p->u.int_ptr = strtol(_optarg, NULL, 0);
- } else if (p->flags & CMD_OPT_ARG) {
- p->u.func_arg(_optarg);
- } else {
+ break;
+ case CMD_LINE_TYPE_STRING:
+ *p->u.string_ptr = _optarg;
+ break;
+ case CMD_LINE_TYPE_FVOID:
p->u.func_noarg();
+ break;
+ case CMD_LINE_TYPE_FARG:
+ p->u.func_arg(_optarg);
+ break;
+ case CMD_LINE_TYPE_NONE:
+ case CMD_LINE_TYPE_NEXT:
+ break;
}
goto next_cmd;
}
p++;
}
- p = p->u.next;
}
- put_status(NULL, "unknown cmdline option '%s'", r);
+ put_status(NULL, "unknown cmdline option '%s'", arg);
next_cmd: ;
}
@@ -8365,28 +8387,29 @@
qe_state.tty_charset = qe_strdup(name);
}
-static CmdOptionDef cmd_options[] = {
- { "help", "h", NULL, 0, "display this help message and exit",
- { .func_noarg = show_usage }},
- { "no-init-file", "q", NULL, CMD_OPT_BOOL, "do not load config files",
- { .int_ptr = &no_init_file }},
- { "single-window", "1", NULL, CMD_OPT_BOOL, "keep a single window when
loading multiple files",
- { .int_ptr = &single_window }},
- { "no-windows", "nw", NULL, CMD_OPT_BOOL, "force tty terminal usage",
- { .int_ptr = &force_tty }},
- { "ttycharset", "c", "CHARSET", CMD_OPT_ARG, "specify tty charset",
- { .func_arg = set_tty_charset }},
- { "use-session", "s", NULL, CMD_OPT_BOOL, "load and save session files",
- { .int_ptr = &use_session_file }},
- { "user", "u", "USER", CMD_OPT_ARG, "load ~USER/.qe/config instead of your
own",
- { .func_arg = set_user_option }},
- { "version", "V", NULL, 0, "display version information and exit",
- { .func_noarg = show_version }},
+static CmdLineOptionDef cmd_options[] = {
+ CMD_LINE_FVOID("h", "help", show_usage,
+ "display this help message and exit"),
+ CMD_LINE_FVOID("?", "", show_usage, ""),
+ CMD_LINE_BOOL("q", "no-init-file", &no_init_file,
+ "do not load config files"),
+ CMD_LINE_BOOL("1", "single-window", &single_window,
+ "keep a single window when loading multiple files"),
+ CMD_LINE_BOOL("nw", "no-windows", &force_tty,
+ "force tty terminal usage"),
+ CMD_LINE_FARG("c", "charset", "CHARSET", set_tty_charset,
+ "specify tty charset"),
+ CMD_LINE_BOOL("s", "use-session", &use_session_file,
+ "load and save session files"),
+ CMD_LINE_FARG("u", "user", "USER", set_user_option,
+ "load ~USER/.qe/config instead of your own"),
+ CMD_LINE_FVOID("V", "version", show_version,
+ "display version information and exit"),
#ifndef CONFIG_TINY
- { "free-all", NULL, NULL, CMD_OPT_BOOL, "free all structures upon exit",
- { .int_ptr = &free_everything }},
+ CMD_LINE_BOOL("", "free-all", &free_everything,
+ "free all structures upon exit"),
#endif
- { NULL, NULL, NULL, 0, NULL, { NULL }},
+ CMD_LINE_LINK()
};
/* default key bindings */
Index: qe.h
===================================================================
RCS file: /sources/qemacs/qemacs/qe.h,v
retrieving revision 1.248
retrieving revision 1.249
diff -u -b -r1.248 -r1.249
--- qe.h 15 Apr 2017 13:10:53 -0000 1.248
+++ qe.h 16 Apr 2017 17:20:49 -0000 1.249
@@ -434,6 +434,7 @@
}
int qe_strcollate(const char *s1, const char *s2);
+int qe_strtobool(const char *s, int def);
void qe_strtolower(char *buf, int buf_size, const char *str);
void skip_spaces(const char **pp);
@@ -579,32 +580,61 @@
int buf_printf(buf_t *bp, const char *fmt, ...) qe__attr_printf(2,3);
int buf_putc_utf8(buf_t *bp, int c);
+/* Bounded constant strings used in various parse functions */
+typedef struct bstr_t {
+ const char *s;
+ int len;
+} bstr_t;
+
+static inline bstr_t bstr_make(const char *s) {
+ bstr_t bs = { s, s ? strlen(s) : 0 };
+ return bs;
+}
+
+bstr_t bstr_token(const char *s, int sep, const char **pp);
+bstr_t bstr_get_nth(const char *s, int n);
+
+static inline int bstr_equal(bstr_t s1, bstr_t s2) {
+ /* NULL and empty strings are equivalent */
+ return s1.len == s2.len && !memcmp(s1.s, s2.s, s1.len);
+}
+
/* our own implementation of qsort_r() */
void qe_qsort_r(void *base, size_t nmemb, size_t size, void *thunk,
int (*compar)(void *, const void *, const void *));
-/* command line option */
-#define CMD_OPT_ARG 0x0001 /* argument */
-#define CMD_OPT_STRING 0x0002 /* string */
-#define CMD_OPT_BOOL 0x0004 /* boolean */
-#define CMD_OPT_INT 0x0008 /* int */
+/* Command line options */
+enum CmdLineOptionType {
+ CMD_LINE_TYPE_NONE = 0, /* nothing */
+ CMD_LINE_TYPE_BOOL = 1, /* boolean ptr */
+ CMD_LINE_TYPE_INT = 2, /* int ptr */
+ CMD_LINE_TYPE_STRING = 3, /* string ptr */
+ CMD_LINE_TYPE_FVOID = 4, /* function() */
+ CMD_LINE_TYPE_FARG = 5, /* function(string) */
+ CMD_LINE_TYPE_NEXT = 6, /* next pointer */
+};
-typedef struct CmdOptionDef {
- const char *name;
- const char *shortname;
- const char *argname;
- int flags;
- const char *help;
+typedef struct CmdLineOptionDef {
+ const char *desc;
+ enum CmdLineOptionType type;
union {
- const char **string_ptr;
int *int_ptr;
+ const char **string_ptr;
void (*func_noarg)(void);
void (*func_arg)(const char *);
- struct CmdOptionDef *next;
+ struct CmdLineOptionDef *next;
} u;
-} CmdOptionDef;
+} CmdLineOptionDef;
+
+#define CMD_LINE_NONE() { NULL, CMD_LINE_TYPE_NONE, { NULL }}
+#define CMD_LINE_BOOL(s,n,p,h) { s "|" n "||" h, CMD_LINE_TYPE_BOOL, {
.int_ptr = p }}
+#define CMD_LINE_INT(s,n,a,p,h) { s "|" n "|" a "|" h, CMD_LINE_TYPE_INT, {
.int_ptr = p }}
+#define CMD_LINE_STRING(s,n,a,p,h) { s "|" n "|" a "|" h,
CMD_LINE_TYPE_STRING, { .string_ptr = p }}
+#define CMD_LINE_FVOID(s,n,p,h) { s "|" n "||" h, CMD_LINE_TYPE_FVOID, {
.func_noarg = p }}
+#define CMD_LINE_FARG(s,n,a,p,h) { s "|" n "|" a "|" h, CMD_LINE_TYPE_FARG, {
.func_arg = p }}
+#define CMD_LINE_LINK() { NULL, CMD_LINE_TYPE_NEXT, { NULL }}
-void qe_register_cmd_line_options(CmdOptionDef *table);
+void qe_register_cmd_line_options(CmdLineOptionDef *table);
int find_resource_file(char *path, int path_size, const char *pattern);
Index: util.c
===================================================================
RCS file: /sources/qemacs/qemacs/util.c,v
retrieving revision 1.80
retrieving revision 1.81
diff -u -b -r1.80 -r1.81
--- util.c 12 Apr 2017 07:33:20 -0000 1.80
+++ util.c 16 Apr 2017 17:20:49 -0000 1.81
@@ -470,6 +470,14 @@
/* CG: need a local version of strcasecmp: qe_strcasecmp() */
+int qe_strtobool(const char *s, int def) {
+ if (s && *s) {
+ return strxfind("1|y|yes|t|true", s) ? 1 : 0;
+ } else {
+ return def;
+ }
+}
+
/* Should return int, length of converted string? */
void qe_strtolower(char *buf, int size, const char *str)
{
@@ -2222,6 +2230,47 @@
return p;
}
+/*---------------- bounded strings ----------------*/
+
+/* get the n-th string from a `|` separated list */
+bstr_t bstr_get_nth(const char *s, int n) {
+ bstr_t bs;
+
+ for (bs.s = s;; s++) {
+ if (*s == '\0' || *s == '|') {
+ if (n-- == 0) {
+ bs.len = s - bs.s;
+ break;
+ }
+ if (*s) {
+ bs.s = s + 1;
+ } else {
+ bs.len = 0;
+ bs.s = NULL;
+ break;
+ }
+ }
+ }
+ return bs;
+}
+
+/* get the first string from a list and push pointer */
+bstr_t bstr_token(const char *s, int sep, const char **pp) {
+ bstr_t bs = { s, 0 };
+
+ if (s) {
+ /* XXX: should special case spaces? */
+ for (; s != '\0' && *s != sep; s++)
+ continue;
+
+ bs.len = s - bs.s;
+ if (pp) {
+ *pp = *s ? s + 1 : NULL;
+ }
+ }
+ return bs;
+}
+
/*---------------- qe_qsort_r ----------------*/
/* Our own implementation of qsort_r() since it is not available
Index: x11.c
===================================================================
RCS file: /sources/qemacs/qemacs/x11.c,v
retrieving revision 1.48
retrieving revision 1.49
diff -u -b -r1.48 -r1.49
--- x11.c 11 Apr 2017 06:46:13 -0000 1.48
+++ x11.c 16 Apr 2017 17:20:49 -0000 1.49
@@ -1911,14 +1911,14 @@
CMD_DEF_END,
};
-static CmdOptionDef cmd_options[] = {
- { "display", "d", "display", CMD_OPT_STRING | CMD_OPT_ARG, "set X11
display",
- { .string_ptr = &display_str }},
- { "geometry", "g", "WxH", CMD_OPT_STRING | CMD_OPT_ARG, "set X11 display
size",
- { .string_ptr = &geometry_str }},
- { "font-size", "fs", "ptsize", CMD_OPT_INT | CMD_OPT_ARG, "set default
font size",
- { .int_ptr = &font_ptsize }},
- { NULL, NULL, NULL, 0, NULL, { NULL }},
+static CmdLineOptionDef cmd_options[] = {
+ CMD_LINE_STRING("d", "display", "DISPLAY", &display_str,
+ "set X11 display"),
+ CMD_LINE_STRING("g", "geometry", "WxH", &geometry_str,
+ "set X11 display size"),
+ CMD_LINE_INT("fs", "font-size", "ptsize", &font_ptsize,
+ "set default font size"),
+ CMD_LINE_LINK()
};
static int x11_init(void)
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemacs-commit] qemacs qe.c qe.h util.c x11.c,
Charlie Gordon <=