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