cmdopts.diff
author Myhailo Danylenko <isbear@ukrpost.net>
Sun, 24 Feb 2013 04:47:32 +0200
changeset 64 d328b18462bd
child 65 7e44adeed9a7
permissions -rw-r--r--
Add cmdopts.diff
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
64
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
     1
# HG changeset patch
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
     2
# Parent 92fa48ef53c909928706ab4c51518953339a38e4
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
     3
Unified command option parsing
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
     4
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
     5
diff -r 92fa48ef53c9 mcabber/mcabber/utils.c
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
     6
--- a/mcabber/mcabber/utils.c	Sun Jan 27 00:40:37 2013 +0200
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
     7
+++ b/mcabber/mcabber/utils.c	Sun Feb 24 04:24:14 2013 +0200
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
     8
@@ -555,6 +555,311 @@
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
     9
     *str = tolower(*str);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    10
 }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    11
 
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    12
+// FURTHER TODO:
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    13
+// Allow to specify catchall argument in the middle of string (requires some reverse parser)
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    14
+// Better error messages (caller frees them)
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    15
+// --help generates error with short usage, based on info in options struct
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    16
+
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    17
+// in_space        -> in_space, in_optstart, in_argstart
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    18
+// in_optstart     -> in_shortoptend, in_longoptstart, in_argstart ('-')
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    19
+// in_shortoptend  -> in_space, error
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    20
+// in_longoptstart -> in_longopt, in_space, in_argstart ('---')
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    21
+// in_longopt      -> in_longopt, in_space, error
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    22
+// in_argstart     -> in_arg, success
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    23
+// in_arg          -> in_arg, in_space, error
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    24
+
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    25
+// arguments: rw buffer in utf8, end of buffer pointer, options description struct
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    26
+static const char *cmdopts_parse_internal(gchar *arg, gchar *e, cmdopts_t *options)
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    27
+{
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    28
+  // parser state
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    29
+  enum {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    30
+    in_space,
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    31
+    in_optstart,
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    32
+    in_shortoptstart,
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    33
+    in_shortoptend,
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    34
+    in_longoptstart,
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    35
+    in_longopt,
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    36
+    in_argstart,
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    37
+    in_arg,
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    38
+  } state = in_space;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    39
+  // current pointer, start of object pointer
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    40
+  gchar *p, *s;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    41
+  //
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    42
+  gboolean quotes = FALSE;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    43
+  gboolean opts_ended = FALSE;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    44
+  // option, for which argument is currently parsed
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    45
+  cmdopt_t *option = NULL;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    46
+  // argument, that we currently parse
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    47
+  cmdarg_t *argument = NULL;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    48
+  // flags of option/argument
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    49
+  guint flags = 0;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    50
+  // error message to return
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    51
+  const char *error = NULL;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    52
+
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    53
+  p = arg;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    54
+  // we allow parser to do one extra run on final '\0'
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    55
+  while (p <= e && error == NULL) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    56
+    if (state == in_space) { // space between args/options
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    57
+      if (*p == ' ' || *p == '\0') { // still space
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    58
+        p ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    59
+      } else if (*p == '-' && !opts_ended) { // option
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    60
+        state = in_optstart;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    61
+        p ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    62
+      } else { // argument
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    63
+        if (!option) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    64
+          opts_ended = TRUE;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    65
+        }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    66
+        s = p;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    67
+        state = in_argstart;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    68
+      }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    69
+    } else if (state == in_optstart) { // long/short option
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    70
+      if (*p == ' ' || *p == '\0') { // argument '-'
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    71
+        opts_ended = TRUE;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    72
+        s = p - 1;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    73
+        state = in_argstart;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    74
+      } else if (*p == '-') { // long option
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    75
+        state = in_longoptstart;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    76
+        p ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    77
+      } else { // short option
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    78
+        s = p;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    79
+        state = in_shortoptend;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    80
+        p ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    81
+      }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    82
+    } else if (state == in_shortoptend) { // short option
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    83
+      if (*p == ' ' || *p == '\0') { // option really ended
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    84
+        gboolean found = FALSE;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    85
+        option = options -> opts;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    86
+        if (option) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    87
+          do {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    88
+            if (option -> shortopt == *s) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    89
+              found = TRUE;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    90
+              break;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    91
+            }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    92
+          } while ((!(option++ -> flags & CMDOPT_LAST)) && !found);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    93
+        }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    94
+        if (found) { // option is known
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    95
+          if (option -> flags & CMDOPT_SWITCH) { // it is switch
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    96
+            if (option -> flags & CMDOPT_CATCHALL) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    97
+              option -> value.swc ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    98
+            } else {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
    99
+              option -> value.swc = !option -> value.swc;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   100
+            }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   101
+            option = NULL;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   102
+          } else { // it is option
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   103
+            if (*p == '\0') {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   104
+              error = "Short option argument not specified";
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   105
+            }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   106
+          }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   107
+          state = in_space;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   108
+          p ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   109
+        } else { // option is unknown
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   110
+          error = "Unknown short option";
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   111
+        }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   112
+      } else { // short option not ended
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   113
+        error = "Extra characters at short option end";
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   114
+      }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   115
+    } else if (state == in_longoptstart) { // long option initialization
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   116
+      if (*p == ' ' || *p == '\0') { // end of options '--'
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   117
+        opts_ended = TRUE;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   118
+        state = in_space;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   119
+        p ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   120
+      } else if (*p == '-') { // argument, starting with '---'
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   121
+        opts_ended = TRUE;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   122
+        s = p - 2;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   123
+        state = in_argstart;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   124
+      } else { // it is long option
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   125
+        s = p;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   126
+        state = in_longopt;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   127
+        p ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   128
+      }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   129
+    } else if (state == in_longopt) { // long option name
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   130
+      if (*p == ' ' || *p == '\0') { // long option ended
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   131
+        gboolean found = FALSE;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   132
+        gboolean eof = *p == '\0';
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   133
+        *p = '\0';
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   134
+        option = options -> opts;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   135
+        if (option) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   136
+          do {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   137
+            if (!g_strcmp0 (option -> longopt, s)) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   138
+              found = TRUE;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   139
+              break;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   140
+            }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   141
+          } while ((!(option++ -> flags & CMDOPT_LAST)) && !found);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   142
+        }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   143
+        if (found) { // option is known
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   144
+          if (option -> flags & CMDOPT_SWITCH) { // it is switch
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   145
+            if (option -> flags & CMDOPT_CATCHALL) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   146
+              option -> value.swc ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   147
+            } else {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   148
+              option -> value.swc = !option -> value.swc;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   149
+            }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   150
+            option = NULL;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   151
+          } else { // it is option
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   152
+            if (eof) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   153
+              error = "Long option argument not specified";
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   154
+            }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   155
+          }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   156
+          state = in_space;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   157
+          p ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   158
+        } else { // option is unknown
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   159
+          error = "Unknown long option";
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   160
+        }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   161
+      } else { // still long option
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   162
+        p ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   163
+      }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   164
+    } else if (state == in_argstart) { // option/command argument initialization
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   165
+      if (option) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   166
+        flags = option -> flags & ~CMDOPT_CATCHALL; // catchall in options indicates multi-options
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   167
+      } else {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   168
+        if (!argument) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   169
+          argument = options -> args;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   170
+        }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   171
+        if (!argument) { // no need to parse arguments at all
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   172
+          break;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   173
+        }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   174
+        flags = argument -> flags;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   175
+        if ((flags & CMDOPT_CATCHALL) && (flags & CMDOPT_PLAIN)) { // can finish right away
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   176
+          argument -> value.arg = s;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   177
+          break;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   178
+        }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   179
+      }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   180
+      quotes = FALSE;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   181
+      state = in_arg;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   182
+    } else if (state == in_arg) { // option/command argument value
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   183
+      if (*p == '\0' && quotes) { // end of line in quotes
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   184
+        error = "Unfinished quoted argument";
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   185
+      } else if ((*p == ' ' && (!quotes) && !(flags & CMDOPT_CATCHALL)) || *p == '\0') { // argument ended
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   186
+        if (*p != '\0') {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   187
+          *p = '\0';
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   188
+          p ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   189
+        } 
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   190
+        if (option) { // option argument
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   191
+          if (option -> flags & CMDOPT_CATCHALL) { // multi-value option
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   192
+            option -> value.multiopt = g_slist_append (option -> value.multiopt, s);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   193
+          } else { // single-value option
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   194
+            option -> value.opt = s;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   195
+          }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   196
+          option = NULL;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   197
+        } else { // command argument
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   198
+          if (argument -> flags & CMDOPT_SUBCOMMAND) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   199
+            gboolean found = FALSE;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   200
+            subcmd_t *subcommand = options -> cmds;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   201
+            if (subcommand) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   202
+              do {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   203
+                if (!g_strcmp0(s, subcommand -> name)) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   204
+                  found = TRUE;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   205
+                  break;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   206
+                }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   207
+              } while (!(subcommand++ -> flags & CMDOPT_LAST));
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   208
+            }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   209
+            if (found) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   210
+              argument -> value.cmd = subcommand;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   211
+              error = cmdopts_parse_internal(p, e, subcommand -> options);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   212
+              break;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   213
+            } else {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   214
+              error = "Unknown subcommand";
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   215
+            }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   216
+          } else {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   217
+            argument -> value.arg = s;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   218
+            if (argument -> flags & CMDOPT_LAST) { // last argument
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   219
+              break;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   220
+            }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   221
+            argument ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   222
+          }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   223
+        }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   224
+        state = in_space;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   225
+        p ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   226
+      } else if (*p == '\\' && !(flags & CMDOPT_PLAIN)) { // next char escape
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   227
+        memmove(p, p+1, e-(p+1));
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   228
+        e --;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   229
+        if (*p == '\0') {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   230
+          error = "Escape at the end of line";
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   231
+        }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   232
+        p ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   233
+      } else if (*p == '"' && !(flags & CMDOPT_PLAIN)) { // quotation start/end
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   234
+        memmove(p, p+1, e-(p+1));
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   235
+        e --;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   236
+        quotes = !quotes;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   237
+      } else { // still argument
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   238
+        p ++;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   239
+      }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   240
+    }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   241
+  }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   242
+
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   243
+  // check required flags on options
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   244
+  if (error == NULL && options -> opts) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   245
+    option = options -> opts;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   246
+    do {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   247
+      if (option -> flags & CMDOPT_REQUIRED) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   248
+        if (option -> flags & CMDOPT_SWITCH) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   249
+          // no way to check trigger switches, but no point in it as well
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   250
+          if (option -> flags & CMDOPT_CATCHALL && option -> value.swc == 0) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   251
+            error = "Required switch is not specified";
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   252
+            break;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   253
+          }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   254
+        } else {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   255
+          if ((option -> flags & CMDOPT_CATCHALL && option -> value.multiopt == NULL) ||
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   256
+              ((!(option -> flags & CMDOPT_CATCHALL)) && option -> value.opt == NULL)) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   257
+            error = "Required option is not specified";
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   258
+            break;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   259
+          }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   260
+        }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   261
+      }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   262
+    } while (!(option++ -> flags & CMDOPT_LAST));
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   263
+  }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   264
+
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   265
+  // check required flags on arguments
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   266
+  if (error == NULL && options -> args) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   267
+    argument = options -> args;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   268
+    do {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   269
+      if (argument -> flags & CMDOPT_REQUIRED) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   270
+        if (argument -> flags & CMDOPT_SUBCOMMAND && argument -> value.cmd == NULL) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   271
+          error = "Subcommand is not specified";
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   272
+          break;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   273
+        }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   274
+      } else {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   275
+        if ((!(argument -> flags & CMDOPT_SUBCOMMAND)) && argument -> value.arg == NULL) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   276
+          error = "Required argument is not specified";
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   277
+          break;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   278
+        }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   279
+      }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   280
+    } while (!(argument++ -> flags & CMDOPT_LAST));
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   281
+  }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   282
+
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   283
+  return error;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   284
+}
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   285
+
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   286
+const char *cmdopts_parse(const char *arg, cmdopts_t *options)
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   287
+{
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   288
+  gchar *utf8 = to_utf8(arg);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   289
+  gchar *e;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   290
+
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   291
+  for (e = utf8; *e; e++);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   292
+  options -> freeme = utf8;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   293
+  return cmdopts_parse_internal(utf8, e, options);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   294
+}
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   295
+
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   296
+void cmdopts_free(cmdopts_t *options)
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   297
+{
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   298
+  cmdopt_t *option = options -> opts;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   299
+  subcmd_t *subcommand = options -> cmds;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   300
+  if (option) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   301
+    do {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   302
+      if ((option -> flags & (CMDOPT_CATCHALL|CMDOPT_SWITCH)) == CMDOPT_CATCHALL) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   303
+        g_slist_free(option -> value.multiopt);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   304
+        option -> value.multiopt = NULL;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   305
+      }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   306
+    } while (!(option++ -> flags & CMDOPT_LAST));
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   307
+  }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   308
+  if (subcommand) {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   309
+    do {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   310
+      cmdopts_free(subcommand -> options);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   311
+    } while (!(subcommand++ -> flags & CMDOPT_LAST));
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   312
+  }
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   313
+  g_free(options -> freeme);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   314
+  options -> freeme = NULL;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   315
+}
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   316
+
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   317
 //  strip_arg_special_chars(string)
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   318
 // Remove quotes and backslashes before an escaped quote
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   319
 // Only quotes need a backslash
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   320
diff -r 92fa48ef53c9 mcabber/mcabber/utils.h
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   321
--- a/mcabber/mcabber/utils.h	Sun Jan 27 00:40:37 2013 +0200
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   322
+++ b/mcabber/mcabber/utils.h	Sun Feb 24 04:24:14 2013 +0200
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   323
@@ -43,6 +43,93 @@
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   324
 char **split_arg(const char *arg, unsigned int n, int dontstriplast);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   325
 void free_arg_lst(char **arglst);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   326
 
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   327
+//  error cmdopts_parse (argstring, optionlist)
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   328
+// Function parses command argument string according to provided list of
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   329
+// options and arguments. If in this process it encounters an error, it
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   330
+// returns error string (that should be displayed and g_free'd afterwards).
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   331
+// Note: For now returned error is constant string, that shouldn't be freed,
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   332
+// but we're getting there.
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   333
+// After processing you should free freeme and any GSList values of catchall
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   334
+// options (only lists itself, not values). For your convenience, there is
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   335
+// cmdopts_free(), that does exactly that.
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   336
+// The function recognizes four kinds of expressions:
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   337
+//  - Options with arguments in a form '-f bar' or '--foo bar'
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   338
+//  - Switches without arguments in a form '-f' or '--foo'
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   339
+//  - End-of-options marker '--'
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   340
+//  - Individual arguments ('-' and '---' are considered arguments too)
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   341
+// To define command line syntax, you pass cmdopts_t struct, that contains
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   342
+// two contiguous lists of cmdopt_t and cmdarg_t structs accordingly. The
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   343
+// last struct in list must have CMDOPT_LAST flag set.
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   344
+// You can specify your own default values, they will be replaced/appended
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   345
+// if needed.
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   346
+// You can omit specifying longopt or shortopt (put NULL or '\0' there).
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   347
+// Note: returned values and arguments are already converted to utf8.
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   348
+
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   349
+// Flags:
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   350
+// Only applies to options, defined if option does not have argument.
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   351
+#define CMDOPT_SWITCH     ( 0<<1 )
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   352
+// Don't process quotes and escapes in argument (applies to option arguments too).
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   353
+#define CMDOPT_PLAIN      ( 1<<1 )
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   354
+// For options   - put all encountered values into GSList value.multiopt
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   355
+//                 instead of overwriting value.opt.
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   356
+// For switches  - increment value.swc instead of logical flipping.
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   357
+// For arguments - grab the rest of the line without splitting on spaces.
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   358
+// Implicitly last argument.
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   359
+#define CMDOPT_CATCHALL   ( 2<<1 )
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   360
+// Option/argument must have value.
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   361
+#define CMDOPT_REQUIRED   ( 3<<1 )
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   362
+// Last entry in struct sequence.
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   363
+#define CMDOPT_LAST       ( 4<<1 )
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   364
+// Argument only, argument is the name for subcommand.
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   365
+// Implicitly last argument.
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   366
+#define CMDOPT_SUBCOMMAND ( 5<<1 )
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   367
+
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   368
+// thoughts about future:
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   369
+// command struct contains cmdopts
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   370
+// cmdopt/cmdarg struct contains argument type, that implies completion id and argument correctness checks
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   371
+// cmdopt/cmdarg struct contains default value
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   372
+// when building completion for command, we allow options (if not before --)
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   373
+// would be good to have 'subcommands' mcabber commands
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   374
+//
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   375
+// so, the process of command execution looks like:
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   376
+// - we walk through the options, set default values
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   377
+// - we parse argument string, populating options
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   378
+// - we check for required options availability
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   379
+// - we call callback
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   380
+// - we free resources
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   381
+typedef struct cmdopts_struct cmdopts_t;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   382
+typedef struct {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   383
+  guint      flags;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   384
+  const char *name;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   385
+  cmdopts_t  *options;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   386
+} subcmd_t;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   387
+typedef struct {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   388
+  guint      flags;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   389
+  char       shortopt;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   390
+  const char *longopt;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   391
+  union {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   392
+    GSList *multiopt;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   393
+    gchar  *opt;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   394
+    guint  swc;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   395
+  } value;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   396
+} cmdopt_t;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   397
+typedef struct {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   398
+  guint flags;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   399
+  union {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   400
+    gchar    *arg;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   401
+    subcmd_t *cmd;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   402
+  } value;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   403
+} cmdarg_t;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   404
+struct cmdopts_struct {
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   405
+  cmdopt_t *opts;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   406
+  cmdarg_t *args;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   407
+  subcmd_t *cmds;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   408
+  gchar    *freeme;
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   409
+};
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   410
+
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   411
+const char *cmdopts_parse (const char *arg, cmdopts_t *options);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   412
+void cmdopts_free(cmdopts_t *options);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   413
+
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   414
 void replace_nl_with_dots(char *bufstr);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   415
 char *ut_expand_tabs(const char *text);
d328b18462bd Add cmdopts.diff
Myhailo Danylenko <isbear@ukrpost.net>
parents:
diff changeset
   416
 char *ut_unescape_tabs_cr(const char *text);