Fixes to cmdopts
authorMyhailo Danylenko <isbear@ukrpost.net>
Sun, 24 Feb 2013 06:49:47 +0200
changeset 65 7e44adeed9a7
parent 64 d328b18462bd
child 66 5616a2397c3c
Fixes to cmdopts
cmdopts.diff
--- a/cmdopts.diff	Sun Feb 24 04:47:32 2013 +0200
+++ b/cmdopts.diff	Sun Feb 24 06:49:47 2013 +0200
@@ -2,10 +2,201 @@
 # Parent 92fa48ef53c909928706ab4c51518953339a38e4
 Unified command option parsing
 
+diff -r 92fa48ef53c9 mcabber/mcabber/commands.c
+--- a/mcabber/mcabber/commands.c	Sun Jan 27 00:40:37 2013 +0200
++++ b/mcabber/mcabber/commands.c	Sun Feb 24 06:49:31 2013 +0200
+@@ -1634,130 +1634,109 @@
+ 
+ static void do_say_to(char *arg)
+ {
+-  char **paramlst;
+-  char *fjid, *msg_utf8;
++  char *fjid;
+   char *msg;
+-  char *unescaped_msg = NULL;
+-  char *uncompletedfjid = NULL;
+-  char *file = NULL;
++  char *file;
++  gchar *freeme  = NULL; // fjid
++  gchar *freeme2 = NULL; // msg
+   LmMessageSubType msg_type = LM_MESSAGE_SUB_TYPE_NOT_SET;
+-  bool quiet = FALSE;
+-  bool eval = FALSE;
++  cmdopts_t options = {
++    (cmdopt_t[5]){
++      { CMDOPT_SWITCH, 'n', "normal",   { .swc = 0 }    },
++      { CMDOPT_SWITCH, 'h', "headline", { .swc = 0 }    },
++      { CMDOPT_SWITCH, 'e', "escapes",  { .swc = 0 }    },
++      { CMDOPT_SWITCH, 'q', "quiet",    { .swc = 0 }    },
++      { CMDOPT_LAST,   'f', "file",     { .opt = NULL } },
++    },
++    (cmdarg_t[2]){
++      { CMDOPT_REQUIRED,                              { .arg = NULL } },
++      { CMDOPT_LAST | CMDOPT_PLAIN | CMDOPT_CATCHALL, { .arg = NULL } },
++    },
++    NULL,
++    NULL,
++  };
+ 
+   if (!xmpp_is_online()) {
+     scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
+     return;
+   }
+ 
+-  msg_type = scan_mtype(&arg);
+-  paramlst = split_arg(arg, 2, 1); // jid, message (or option, jid, message)
+-
+-  if (!*paramlst) {  // No parameter?
+-    scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
+-    free_arg_lst(paramlst);
+-    return;
++  { // parse arguments
++    const char *error = cmdopts_parse(arg, &options);
++    if (error != NULL) {
++      scr_log_print(LPRINT_NORMAL, error);
++      return;
++    }
+   }
+ 
+-  // Check for an option parameter
+-  while (*paramlst) {
+-    if (!strcmp(*paramlst, "-q")) {
+-      char **oldparamlst = paramlst;
+-      paramlst = split_arg(*(oldparamlst+1), 2, 1); // jid, message
+-      free_arg_lst(oldparamlst);
+-      quiet = TRUE;
+-    } else if (!strcmp(*paramlst, "-e")) {
+-      char **oldparamlst = paramlst;
+-      paramlst = split_arg(*(oldparamlst+1), 2, 1); // jid, message
+-      free_arg_lst(oldparamlst);
+-      eval = TRUE;
+-    } else if (!strcmp(*paramlst, "-f")) {
+-      char **oldparamlst = paramlst;
+-      paramlst = split_arg(*(oldparamlst+1), 2, 1); // filename, jid
+-      free_arg_lst(oldparamlst);
+-      if (!*paramlst) {
+-        scr_LogPrint(LPRINT_NORMAL, "Wrong usage.");
+-        free_arg_lst(paramlst);
+-        return;
+-      }
+-      file = g_strdup(*paramlst);
+-      // One more parameter shift...
+-      oldparamlst = paramlst;
+-      paramlst = split_arg(*(oldparamlst+1), 2, 1); // jid, nothing
+-      free_arg_lst(oldparamlst);
+-    } else
+-      break;
++  if (options.opts[0].value.swc) {
++    msg_type = LM_MESSAGE_SUB_TYPE_NORMAL;
++  } else if (options.opts[1].value.swc) {
++    msg_type = LM_MESSAGE_SUB_TYPE_HEADLINE;
+   }
+ 
+-  if (!*paramlst) {
+-    scr_LogPrint(LPRINT_NORMAL, "Wrong usage.");
+-    free_arg_lst(paramlst);
+-    return;
+-  }
+-
+-  fjid = *paramlst;
+-  msg = *(paramlst+1);
+-
++  fjid = options.args[0].value.arg;
++  msg  = options.args[1].value.arg;
++  file = options.opts[4].value.opt;
++
++  // ideally, this should go to commandline parsing subsystem
+   if (fjid[0] == '.') {
+     const gchar *cjid = (current_buddy ? CURRENT_JID : NULL);
+     if (fjid[1] == '\0') {
+-      fjid = g_strdup(cjid);
++      fjid = (char *)cjid; // FIXME
+     } else if (fjid[1] == JID_RESOURCE_SEPARATOR) {
+       char *res_utf8 = to_utf8(fjid+2);
+-      fjid = g_strdup_printf("%s%c%s", cjid, JID_RESOURCE_SEPARATOR, res_utf8);
++      freeme = fjid = g_strdup_printf("%s%c%s", cjid, JID_RESOURCE_SEPARATOR, res_utf8);
+       g_free(res_utf8);
+-    } else
+-      fjid = to_utf8(fjid);
+-  } else
+-    fjid = to_utf8(fjid);
+-
++    }
++  }
++
++  // ditto
+   if (!strchr(fjid, JID_DOMAIN_SEPARATOR)) {
+     const gchar *append_server = settings_opt_get("default_server");
+     if (append_server) {
+       gchar *res = strchr(fjid, JID_RESOURCE_SEPARATOR);
+-      uncompletedfjid = fjid;
+       if (res) {
+         *res++ = '\0';
+         fjid = g_strdup_printf("%s%c%s%c%s", fjid, JID_DOMAIN_SEPARATOR, append_server,
+                                JID_RESOURCE_SEPARATOR, res);
+       } else
+         fjid = g_strdup_printf("%s%c%s", fjid, JID_DOMAIN_SEPARATOR, append_server);
++      g_free(freeme);
++      freeme = fjid;
+     }
+   }
+ 
++  // as well
+   if (check_jid_syntax(fjid)) {
+     scr_LogPrint(LPRINT_NORMAL, "Please specify a valid Jabber ID.");
+-    free_arg_lst(paramlst);
+-    g_free(uncompletedfjid);
+-    g_free(fjid);
++    g_free(freeme);
+     return;
+   }
+ 
+-  if (!file) {
+-    msg_utf8 = to_utf8(msg);
+-    if (eval) {
+-      unescaped_msg = ut_unescape_tabs_cr(msg_utf8);
++  if (file == NULL) {
++    if (options.opts[2].value.swc) {
++      freeme2 = ut_unescape_tabs_cr(msg);
+       // We must not free() if the original string was returned
+-      if (unescaped_msg == msg_utf8)
+-        unescaped_msg = NULL;
++      if (freeme2 == msg)
++        freeme2 = NULL;
++      else
++        msg = freeme2;
+     }
+-    msg = (unescaped_msg ? unescaped_msg : msg_utf8);
+   } else {
+     char *filename_xp;
+     if (msg)
+       scr_LogPrint(LPRINT_NORMAL, "say_to: extra parameter ignored.");
+     filename_xp = expand_filename(file);
+-    msg = msg_utf8 = load_message_from_file(filename_xp);
++    freeme2 = msg = load_message_from_file(filename_xp);
+     g_free(filename_xp);
+-    g_free(file);
+   }
+ 
+-  send_message_to(fjid, msg, NULL, msg_type, quiet);
+-
+-  g_free(uncompletedfjid);
+-  g_free(fjid);
+-  g_free(msg_utf8);
+-  g_free(unescaped_msg);
+-  free_arg_lst(paramlst);
++  send_message_to(fjid, msg, NULL, msg_type, options.opts[3].value.swc);
++
++  cmdopts_free(&options);
++  g_free(freeme);
++  g_free(freeme2);
+ }
+ 
+ //  buffer_updown(updown, nblines)
 diff -r 92fa48ef53c9 mcabber/mcabber/utils.c
 --- a/mcabber/mcabber/utils.c	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/mcabber/utils.c	Sun Feb 24 04:24:14 2013 +0200
-@@ -555,6 +555,311 @@
++++ b/mcabber/mcabber/utils.c	Sun Feb 24 06:49:31 2013 +0200
+@@ -555,6 +555,312 @@
      *str = tolower(*str);
  }
  
@@ -222,7 +413,6 @@
 +          }
 +        }
 +        state = in_space;
-+        p ++;
 +      } else if (*p == '\\' && !(flags & CMDOPT_PLAIN)) { // next char escape
 +        memmove(p, p+1, e-(p+1));
 +        e --;
@@ -267,14 +457,16 @@
 +    argument = options -> args;
 +    do {
 +      if (argument -> flags & CMDOPT_REQUIRED) {
-+        if (argument -> flags & CMDOPT_SUBCOMMAND && argument -> value.cmd == NULL) {
-+          error = "Subcommand is not specified";
-+          break;
-+        }
-+      } else {
-+        if ((!(argument -> flags & CMDOPT_SUBCOMMAND)) && argument -> value.arg == NULL) {
-+          error = "Required argument is not specified";
-+          break;
++        if (argument -> flags & CMDOPT_SUBCOMMAND) {
++          if (argument -> value.cmd == NULL) {
++            error = "Subcommand is not specified";
++            break;
++          }
++        } else {
++          if (argument -> value.arg == NULL) {
++            error = "Required argument is not specified";
++            break;
++          }
 +        }
 +      }
 +    } while (!(argument++ -> flags & CMDOPT_LAST));
@@ -319,7 +511,7 @@
  // Only quotes need a backslash
 diff -r 92fa48ef53c9 mcabber/mcabber/utils.h
 --- a/mcabber/mcabber/utils.h	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/mcabber/utils.h	Sun Feb 24 04:24:14 2013 +0200
++++ b/mcabber/mcabber/utils.h	Sun Feb 24 06:49:31 2013 +0200
 @@ -43,6 +43,93 @@
  char **split_arg(const char *arg, unsigned int n, int dontstriplast);
  void free_arg_lst(char **arglst);
@@ -348,7 +540,7 @@
 +
 +// Flags:
 +// Only applies to options, defined if option does not have argument.
-+#define CMDOPT_SWITCH     ( 0<<1 )
++#define CMDOPT_SWITCH     ( 1<<0 )
 +// Don't process quotes and escapes in argument (applies to option arguments too).
 +#define CMDOPT_PLAIN      ( 1<<1 )
 +// For options   - put all encountered values into GSList value.multiopt
@@ -356,14 +548,14 @@
 +// For switches  - increment value.swc instead of logical flipping.
 +// For arguments - grab the rest of the line without splitting on spaces.
 +// Implicitly last argument.
-+#define CMDOPT_CATCHALL   ( 2<<1 )
++#define CMDOPT_CATCHALL   ( 1<<2 )
 +// Option/argument must have value.
-+#define CMDOPT_REQUIRED   ( 3<<1 )
++#define CMDOPT_REQUIRED   ( 1<<3 )
 +// Last entry in struct sequence.
-+#define CMDOPT_LAST       ( 4<<1 )
++#define CMDOPT_LAST       ( 1<<4 )
 +// Argument only, argument is the name for subcommand.
 +// Implicitly last argument.
-+#define CMDOPT_SUBCOMMAND ( 5<<1 )
++#define CMDOPT_SUBCOMMAND ( 1<<5 )
 +
 +// thoughts about future:
 +// command struct contains cmdopts