qemacs-commit
[Top][All Lists]
Advanced

[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)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]