Add cmdopts.diff
authorMyhailo Danylenko <isbear@ukrpost.net>
Sun, 24 Feb 2013 04:47:32 +0200
changeset 64 d328b18462bd
parent 63 d268aa028975
child 65 7e44adeed9a7
Add cmdopts.diff
cmdopts.diff
move-rename-jid.diff
separate-extcmd.diff
series
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmdopts.diff	Sun Feb 24 04:47:32 2013 +0200
@@ -0,0 +1,416 @@
+# HG changeset patch
+# Parent 92fa48ef53c909928706ab4c51518953339a38e4
+Unified command option parsing
+
+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 @@
+     *str = tolower(*str);
+ }
+ 
++// FURTHER TODO:
++// Allow to specify catchall argument in the middle of string (requires some reverse parser)
++// Better error messages (caller frees them)
++// --help generates error with short usage, based on info in options struct
++
++// in_space        -> in_space, in_optstart, in_argstart
++// in_optstart     -> in_shortoptend, in_longoptstart, in_argstart ('-')
++// in_shortoptend  -> in_space, error
++// in_longoptstart -> in_longopt, in_space, in_argstart ('---')
++// in_longopt      -> in_longopt, in_space, error
++// in_argstart     -> in_arg, success
++// in_arg          -> in_arg, in_space, error
++
++// arguments: rw buffer in utf8, end of buffer pointer, options description struct
++static const char *cmdopts_parse_internal(gchar *arg, gchar *e, cmdopts_t *options)
++{
++  // parser state
++  enum {
++    in_space,
++    in_optstart,
++    in_shortoptstart,
++    in_shortoptend,
++    in_longoptstart,
++    in_longopt,
++    in_argstart,
++    in_arg,
++  } state = in_space;
++  // current pointer, start of object pointer
++  gchar *p, *s;
++  //
++  gboolean quotes = FALSE;
++  gboolean opts_ended = FALSE;
++  // option, for which argument is currently parsed
++  cmdopt_t *option = NULL;
++  // argument, that we currently parse
++  cmdarg_t *argument = NULL;
++  // flags of option/argument
++  guint flags = 0;
++  // error message to return
++  const char *error = NULL;
++
++  p = arg;
++  // we allow parser to do one extra run on final '\0'
++  while (p <= e && error == NULL) {
++    if (state == in_space) { // space between args/options
++      if (*p == ' ' || *p == '\0') { // still space
++        p ++;
++      } else if (*p == '-' && !opts_ended) { // option
++        state = in_optstart;
++        p ++;
++      } else { // argument
++        if (!option) {
++          opts_ended = TRUE;
++        }
++        s = p;
++        state = in_argstart;
++      }
++    } else if (state == in_optstart) { // long/short option
++      if (*p == ' ' || *p == '\0') { // argument '-'
++        opts_ended = TRUE;
++        s = p - 1;
++        state = in_argstart;
++      } else if (*p == '-') { // long option
++        state = in_longoptstart;
++        p ++;
++      } else { // short option
++        s = p;
++        state = in_shortoptend;
++        p ++;
++      }
++    } else if (state == in_shortoptend) { // short option
++      if (*p == ' ' || *p == '\0') { // option really ended
++        gboolean found = FALSE;
++        option = options -> opts;
++        if (option) {
++          do {
++            if (option -> shortopt == *s) {
++              found = TRUE;
++              break;
++            }
++          } while ((!(option++ -> flags & CMDOPT_LAST)) && !found);
++        }
++        if (found) { // option is known
++          if (option -> flags & CMDOPT_SWITCH) { // it is switch
++            if (option -> flags & CMDOPT_CATCHALL) {
++              option -> value.swc ++;
++            } else {
++              option -> value.swc = !option -> value.swc;
++            }
++            option = NULL;
++          } else { // it is option
++            if (*p == '\0') {
++              error = "Short option argument not specified";
++            }
++          }
++          state = in_space;
++          p ++;
++        } else { // option is unknown
++          error = "Unknown short option";
++        }
++      } else { // short option not ended
++        error = "Extra characters at short option end";
++      }
++    } else if (state == in_longoptstart) { // long option initialization
++      if (*p == ' ' || *p == '\0') { // end of options '--'
++        opts_ended = TRUE;
++        state = in_space;
++        p ++;
++      } else if (*p == '-') { // argument, starting with '---'
++        opts_ended = TRUE;
++        s = p - 2;
++        state = in_argstart;
++      } else { // it is long option
++        s = p;
++        state = in_longopt;
++        p ++;
++      }
++    } else if (state == in_longopt) { // long option name
++      if (*p == ' ' || *p == '\0') { // long option ended
++        gboolean found = FALSE;
++        gboolean eof = *p == '\0';
++        *p = '\0';
++        option = options -> opts;
++        if (option) {
++          do {
++            if (!g_strcmp0 (option -> longopt, s)) {
++              found = TRUE;
++              break;
++            }
++          } while ((!(option++ -> flags & CMDOPT_LAST)) && !found);
++        }
++        if (found) { // option is known
++          if (option -> flags & CMDOPT_SWITCH) { // it is switch
++            if (option -> flags & CMDOPT_CATCHALL) {
++              option -> value.swc ++;
++            } else {
++              option -> value.swc = !option -> value.swc;
++            }
++            option = NULL;
++          } else { // it is option
++            if (eof) {
++              error = "Long option argument not specified";
++            }
++          }
++          state = in_space;
++          p ++;
++        } else { // option is unknown
++          error = "Unknown long option";
++        }
++      } else { // still long option
++        p ++;
++      }
++    } else if (state == in_argstart) { // option/command argument initialization
++      if (option) {
++        flags = option -> flags & ~CMDOPT_CATCHALL; // catchall in options indicates multi-options
++      } else {
++        if (!argument) {
++          argument = options -> args;
++        }
++        if (!argument) { // no need to parse arguments at all
++          break;
++        }
++        flags = argument -> flags;
++        if ((flags & CMDOPT_CATCHALL) && (flags & CMDOPT_PLAIN)) { // can finish right away
++          argument -> value.arg = s;
++          break;
++        }
++      }
++      quotes = FALSE;
++      state = in_arg;
++    } else if (state == in_arg) { // option/command argument value
++      if (*p == '\0' && quotes) { // end of line in quotes
++        error = "Unfinished quoted argument";
++      } else if ((*p == ' ' && (!quotes) && !(flags & CMDOPT_CATCHALL)) || *p == '\0') { // argument ended
++        if (*p != '\0') {
++          *p = '\0';
++          p ++;
++        } 
++        if (option) { // option argument
++          if (option -> flags & CMDOPT_CATCHALL) { // multi-value option
++            option -> value.multiopt = g_slist_append (option -> value.multiopt, s);
++          } else { // single-value option
++            option -> value.opt = s;
++          }
++          option = NULL;
++        } else { // command argument
++          if (argument -> flags & CMDOPT_SUBCOMMAND) {
++            gboolean found = FALSE;
++            subcmd_t *subcommand = options -> cmds;
++            if (subcommand) {
++              do {
++                if (!g_strcmp0(s, subcommand -> name)) {
++                  found = TRUE;
++                  break;
++                }
++              } while (!(subcommand++ -> flags & CMDOPT_LAST));
++            }
++            if (found) {
++              argument -> value.cmd = subcommand;
++              error = cmdopts_parse_internal(p, e, subcommand -> options);
++              break;
++            } else {
++              error = "Unknown subcommand";
++            }
++          } else {
++            argument -> value.arg = s;
++            if (argument -> flags & CMDOPT_LAST) { // last argument
++              break;
++            }
++            argument ++;
++          }
++        }
++        state = in_space;
++        p ++;
++      } else if (*p == '\\' && !(flags & CMDOPT_PLAIN)) { // next char escape
++        memmove(p, p+1, e-(p+1));
++        e --;
++        if (*p == '\0') {
++          error = "Escape at the end of line";
++        }
++        p ++;
++      } else if (*p == '"' && !(flags & CMDOPT_PLAIN)) { // quotation start/end
++        memmove(p, p+1, e-(p+1));
++        e --;
++        quotes = !quotes;
++      } else { // still argument
++        p ++;
++      }
++    }
++  }
++
++  // check required flags on options
++  if (error == NULL && options -> opts) {
++    option = options -> opts;
++    do {
++      if (option -> flags & CMDOPT_REQUIRED) {
++        if (option -> flags & CMDOPT_SWITCH) {
++          // no way to check trigger switches, but no point in it as well
++          if (option -> flags & CMDOPT_CATCHALL && option -> value.swc == 0) {
++            error = "Required switch is not specified";
++            break;
++          }
++        } else {
++          if ((option -> flags & CMDOPT_CATCHALL && option -> value.multiopt == NULL) ||
++              ((!(option -> flags & CMDOPT_CATCHALL)) && option -> value.opt == NULL)) {
++            error = "Required option is not specified";
++            break;
++          }
++        }
++      }
++    } while (!(option++ -> flags & CMDOPT_LAST));
++  }
++
++  // check required flags on arguments
++  if (error == NULL && options -> args) {
++    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;
++        }
++      }
++    } while (!(argument++ -> flags & CMDOPT_LAST));
++  }
++
++  return error;
++}
++
++const char *cmdopts_parse(const char *arg, cmdopts_t *options)
++{
++  gchar *utf8 = to_utf8(arg);
++  gchar *e;
++
++  for (e = utf8; *e; e++);
++  options -> freeme = utf8;
++  return cmdopts_parse_internal(utf8, e, options);
++}
++
++void cmdopts_free(cmdopts_t *options)
++{
++  cmdopt_t *option = options -> opts;
++  subcmd_t *subcommand = options -> cmds;
++  if (option) {
++    do {
++      if ((option -> flags & (CMDOPT_CATCHALL|CMDOPT_SWITCH)) == CMDOPT_CATCHALL) {
++        g_slist_free(option -> value.multiopt);
++        option -> value.multiopt = NULL;
++      }
++    } while (!(option++ -> flags & CMDOPT_LAST));
++  }
++  if (subcommand) {
++    do {
++      cmdopts_free(subcommand -> options);
++    } while (!(subcommand++ -> flags & CMDOPT_LAST));
++  }
++  g_free(options -> freeme);
++  options -> freeme = NULL;
++}
++
+ //  strip_arg_special_chars(string)
+ // Remove quotes and backslashes before an escaped quote
+ // 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
+@@ -43,6 +43,93 @@
+ char **split_arg(const char *arg, unsigned int n, int dontstriplast);
+ void free_arg_lst(char **arglst);
+ 
++//  error cmdopts_parse (argstring, optionlist)
++// Function parses command argument string according to provided list of
++// options and arguments. If in this process it encounters an error, it
++// returns error string (that should be displayed and g_free'd afterwards).
++// Note: For now returned error is constant string, that shouldn't be freed,
++// but we're getting there.
++// After processing you should free freeme and any GSList values of catchall
++// options (only lists itself, not values). For your convenience, there is
++// cmdopts_free(), that does exactly that.
++// The function recognizes four kinds of expressions:
++//  - Options with arguments in a form '-f bar' or '--foo bar'
++//  - Switches without arguments in a form '-f' or '--foo'
++//  - End-of-options marker '--'
++//  - Individual arguments ('-' and '---' are considered arguments too)
++// To define command line syntax, you pass cmdopts_t struct, that contains
++// two contiguous lists of cmdopt_t and cmdarg_t structs accordingly. The
++// last struct in list must have CMDOPT_LAST flag set.
++// You can specify your own default values, they will be replaced/appended
++// if needed.
++// You can omit specifying longopt or shortopt (put NULL or '\0' there).
++// Note: returned values and arguments are already converted to utf8.
++
++// Flags:
++// Only applies to options, defined if option does not have argument.
++#define CMDOPT_SWITCH     ( 0<<1 )
++// 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
++//                 instead of overwriting value.opt.
++// 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 )
++// Option/argument must have value.
++#define CMDOPT_REQUIRED   ( 3<<1 )
++// Last entry in struct sequence.
++#define CMDOPT_LAST       ( 4<<1 )
++// Argument only, argument is the name for subcommand.
++// Implicitly last argument.
++#define CMDOPT_SUBCOMMAND ( 5<<1 )
++
++// thoughts about future:
++// command struct contains cmdopts
++// cmdopt/cmdarg struct contains argument type, that implies completion id and argument correctness checks
++// cmdopt/cmdarg struct contains default value
++// when building completion for command, we allow options (if not before --)
++// would be good to have 'subcommands' mcabber commands
++//
++// so, the process of command execution looks like:
++// - we walk through the options, set default values
++// - we parse argument string, populating options
++// - we check for required options availability
++// - we call callback
++// - we free resources
++typedef struct cmdopts_struct cmdopts_t;
++typedef struct {
++  guint      flags;
++  const char *name;
++  cmdopts_t  *options;
++} subcmd_t;
++typedef struct {
++  guint      flags;
++  char       shortopt;
++  const char *longopt;
++  union {
++    GSList *multiopt;
++    gchar  *opt;
++    guint  swc;
++  } value;
++} cmdopt_t;
++typedef struct {
++  guint flags;
++  union {
++    gchar    *arg;
++    subcmd_t *cmd;
++  } value;
++} cmdarg_t;
++struct cmdopts_struct {
++  cmdopt_t *opts;
++  cmdarg_t *args;
++  subcmd_t *cmds;
++  gchar    *freeme;
++};
++
++const char *cmdopts_parse (const char *arg, cmdopts_t *options);
++void cmdopts_free(cmdopts_t *options);
++
+ void replace_nl_with_dots(char *bufstr);
+ char *ut_expand_tabs(const char *text);
+ char *ut_unescape_tabs_cr(const char *text);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/move-rename-jid.diff	Sun Feb 24 04:47:32 2013 +0200
@@ -0,0 +1,156 @@
+# HG changeset patch
+# Parent 92fa48ef53c909928706ab4c51518953339a38e4
+
+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	Thu Feb 21 02:40:11 2013 +0200
+@@ -2143,6 +2143,7 @@
+   }
+ }
+ 
++// /rename [-j jid] name
+ static void do_rename(char *arg)
+ {
+   gpointer bud;
+@@ -2151,9 +2152,43 @@
+   char *newname, *p;
+   char *name_utf8;
+ 
+-  if (!current_buddy)
+-    return;
+-  bud = BUDDATA(current_buddy);
++  if (arg[0] == '-' && arg[1] == 'j' && arg[2] == ' ') {
++    GSList *found;
++    char *jid;
++    char **args = split_arg(arg, 3, 1); // option, jid, group
++    if (!args[1] || !*args[1]) {
++      scr_log_print(LPRINT_NORMAL, "Option -j requires a jid argument.");
++      free_arg_lst(args);
++      return;
++    }
++    jid = to_utf8(args[1]);
++    if (check_jid_syntax(jid)) {
++      scr_log_print(LPRINT_NORMAL, "You must specify a valid jid!");
++      g_free(jid);
++      free_arg_lst(args);
++      return;
++    }
++    found = roster_find (jid, jidsearch, ROSTER_TYPE_USER |
++                         ROSTER_TYPE_ROOM | ROSTER_TYPE_AGENT);
++    if (!found) {
++      scr_log_print(LPRINT_NORMAL, "No buddy with jid %s in roster!", jid);
++      g_free(jid);
++      free_arg_lst(args);
++      return;
++    }
++    g_free(jid);
++    bud = found->data;
++    if (args[2]) // split_arg can return NULL here
++      newname = g_strdup(args[2]);
++    else
++      newname = g_strdup("");
++    free_arg_lst(args);
++  } else {
++    if (!current_buddy)
++      return;
++    bud = BUDDATA(current_buddy);
++    newname = g_strdup(arg);
++  }
+ 
+   bjid   = buddy_getjid(bud);
+   group  = buddy_getgroupname(bud);
+@@ -2162,11 +2197,13 @@
+ 
+   if (type & ROSTER_TYPE_SPECIAL) {
+     scr_LogPrint(LPRINT_NORMAL, "You can't rename this item.");
++    g_free(newname);
+     return;
+   }
+ 
+-  if (!*arg && !(type & ROSTER_TYPE_GROUP)) {
++  if ((!newname || !*newname) && !(type & ROSTER_TYPE_GROUP)) {
+     scr_LogPrint(LPRINT_NORMAL, "Please specify a new name.");
++    g_free(newname);
+     return;
+   }
+ 
+@@ -2181,7 +2218,6 @@
+   //  }
+   //}
+ 
+-  newname = g_strdup(arg);
+   // Remove trailing space
+   for (p = newname; *p; p++) ;
+   while (p > newname && *p == ' ') *p = 0;
+@@ -2221,6 +2257,7 @@
+   update_roster = TRUE;
+ }
+ 
++// /move [-j jid] groupname
+ static void do_move(char *arg)
+ {
+   gpointer bud;
+@@ -2229,9 +2266,43 @@
+   char *newgroupname, *p;
+   char *group_utf8;
+ 
+-  if (!current_buddy)
+-    return;
+-  bud = BUDDATA(current_buddy);
++  if (arg[0] == '-' && arg[1] == 'j' && arg[2] == ' ') {
++    GSList *found;
++    char *jid;
++    char **args = split_arg(arg, 3, 1); // option, jid, group
++    if (!args[1] || !*args[1]) {
++      scr_log_print(LPRINT_NORMAL, "Option -j requires a jid argument.");
++      free_arg_lst(args);
++      return;
++    }
++    jid = to_utf8(args[1]);
++    if (check_jid_syntax(jid)) {
++      scr_log_print(LPRINT_NORMAL, "You must specify a valid jid!");
++      g_free(jid);
++      free_arg_lst(args);
++      return;
++    }
++    found = roster_find (jid, jidsearch, ROSTER_TYPE_USER |
++                         ROSTER_TYPE_ROOM | ROSTER_TYPE_AGENT);
++    if (!found) {
++      scr_log_print(LPRINT_NORMAL, "No buddy with jid %s in roster!", jid);
++      g_free(jid);
++      free_arg_lst(args);
++      return;
++    }
++    g_free(jid);
++    bud = found->data;
++    if (args[2]) // split_arg can return NULL here
++      newgroupname = g_strdup(args[2]);
++    else
++      newgroupname = g_strdup("");
++    free_arg_lst(args);
++  } else {
++    if (!current_buddy)
++      return;
++    bud = BUDDATA(current_buddy);
++    newgroupname = g_strdup(arg);
++  }
+ 
+   bjid = buddy_getjid(bud);
+   name = buddy_getname(bud);
+@@ -2242,14 +2313,15 @@
+ 
+   if (type & ROSTER_TYPE_GROUP) {
+     scr_LogPrint(LPRINT_NORMAL, "You can't move groups!");
++    g_free(newgroupname);
+     return;
+   }
+   if (type & ROSTER_TYPE_SPECIAL) {
+     scr_LogPrint(LPRINT_NORMAL, "You can't move this item.");
++    g_free(newgroupname);
+     return;
+   }
+ 
+-  newgroupname = g_strdup(arg);
+   // Remove trailing space
+   for (p = newgroupname; *p; p++) ;
+   while (p > newgroupname && *p == ' ') *p-- = 0;
--- a/separate-extcmd.diff	Fri Jan 18 11:32:15 2013 +0200
+++ b/separate-extcmd.diff	Sun Feb 24 04:47:32 2013 +0200
@@ -2,7 +2,7 @@
 
 diff -r 75d573fb8845 mcabber/mcabber/Makefile.am
 --- a/mcabber/mcabber/Makefile.am	Fri Jan 18 11:23:51 2013 +0200
-+++ b/mcabber/mcabber/Makefile.am	Fri Jan 18 11:30:51 2013 +0200
++++ b/mcabber/mcabber/Makefile.am	Sun Jan 27 00:38:57 2013 +0200
 @@ -7,7 +7,7 @@
  		  xmpp.c xmpp.h xmpp_helper.c xmpp_helper.h xmpp_defines.h \
  		  xmpp_iq.c xmpp_iq.h xmpp_iqrequest.c xmpp_iqrequest.h \
@@ -22,7 +22,7 @@
  if OTR
 diff -r 75d573fb8845 mcabber/mcabber/extcmd.c
 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/mcabber/extcmd.c	Fri Jan 18 11:30:51 2013 +0200
++++ b/mcabber/mcabber/extcmd.c	Sun Jan 27 00:38:57 2013 +0200
 @@ -0,0 +1,152 @@
 +/*
 + * extcmd.c      -- External event handler command
@@ -178,7 +178,7 @@
 +/* vim: set expandtab cindent cinoptions=>2\:2(0 ts=2 sw=2:  For Vim users... */
 diff -r 75d573fb8845 mcabber/mcabber/extcmd.h
 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/mcabber/extcmd.h	Fri Jan 18 11:30:51 2013 +0200
++++ b/mcabber/mcabber/extcmd.h	Sun Jan 27 00:38:57 2013 +0200
 @@ -0,0 +1,15 @@
 +#ifndef __MCABBER_EXTCMD_H__
 +#define __MCABBER_EXTCMD_H__ 1
@@ -197,7 +197,7 @@
 +#endif
 diff -r 75d573fb8845 mcabber/mcabber/hooks.c
 --- a/mcabber/mcabber/hooks.c	Fri Jan 18 11:23:51 2013 +0200
-+++ b/mcabber/mcabber/hooks.c	Fri Jan 18 11:30:51 2013 +0200
++++ b/mcabber/mcabber/hooks.c	Sun Jan 27 00:38:57 2013 +0200
 @@ -24,6 +24,7 @@
  #include <string.h>
  #include <sys/types.h>
@@ -466,7 +466,7 @@
  /* vim: set expandtab cindent cinoptions=>2\:2(0 sw=2 ts=2:  For Vim users... */
 diff -r 75d573fb8845 mcabber/mcabber/hooks.h
 --- a/mcabber/mcabber/hooks.h	Fri Jan 18 11:23:51 2013 +0200
-+++ b/mcabber/mcabber/hooks.h	Fri Jan 18 11:30:51 2013 +0200
++++ b/mcabber/mcabber/hooks.h	Sun Jan 27 00:38:57 2013 +0200
 @@ -66,9 +66,6 @@
  guint hk_subscription(LmMessageSubType mstype, const gchar *bjid,
                        const gchar *msg);
@@ -479,8 +479,8 @@
  /* vim: set expandtab cindent cinoptions=>2\:2(0 sw=2 ts=2:  For Vim users... */
 diff -r 75d573fb8845 mcabber/mcabber/main.c
 --- a/mcabber/mcabber/main.c	Fri Jan 18 11:23:51 2013 +0200
-+++ b/mcabber/mcabber/main.c	Fri Jan 18 11:30:51 2013 +0200
-@@ -19,17 +19,15 @@
++++ b/mcabber/mcabber/main.c	Sun Jan 27 00:38:57 2013 +0200
+@@ -19,14 +19,18 @@
   * USA
   */
  
@@ -492,20 +492,22 @@
 -#include <termios.h>
 -#include <sys/types.h>
 -#include <sys/wait.h>
-+#include <stdio.h>   // fprintf, fileno, fgets, puts
-+#include <stdlib.h>  // exit, getenv
-+#include <unistd.h>  // tcsetattr, tcgetattr, getopt
-+#include <string.h>  // strchr, strlen, memset
-+#include <signal.h>  // signal
-+#include <termios.h> // tcsetattr, tcgetattr
++#include <stdio.h>     // fprintf, fileno, fgets, puts
++#include <stdlib.h>    // exit, getenv
++#include <unistd.h>    // tcsetattr, tcgetattr, getopt
++#include <string.h>    // strchr, strlen, memset
++#include <signal.h>    // signal
++#include <termios.h>   // tcsetattr, tcgetattr
++#include <sys/types.h> // waitpid
++#include <sys/wait.h>  // waitpid
++#include <glib.h>
++#include <config.h>
++#include <poll.h>      // POLLIN, POLLERR, POLLPRI
++
  #include <glib.h>
  #include <config.h>
--#include <poll.h>
-+#include <poll.h>    // POLLIN, POLLERR, POLLPRI
- 
- #include "caps.h"
- #include "screen.h"
-@@ -44,6 +42,7 @@
+ #include <poll.h>
+@@ -44,6 +48,7 @@
  #include "xmpp.h"
  #include "help.h"
  #include "events.h"
@@ -513,47 +515,34 @@
  
  #ifndef MODULES_ENABLE
  # include "fifo.h"
-@@ -58,10 +57,6 @@
- # include "hgcset.h"
- #endif
- 
--#ifndef WAIT_ANY
--# define WAIT_ANY -1
--#endif
--
- static unsigned int terminate_ui;
- GMainContext *main_context;
- 
-@@ -98,23 +93,7 @@
+@@ -348,10 +353,10 @@
+       case 'h':
+       case '?':
+         printf("Usage: %s [-h|-V|-f mcabberrc_file]\n\n", argv[0]);
+-        return (c == 'h' ? 0 : -1);
++        return (c == 'h' ? EXIT_SUCCESS : EXIT_FAILURE);
+       case 'V':
+         compile_options();
+-        return 0;
++        return EXIT_SUCCESS;
+       case 'f':
+         configFile = g_strdup(optarg);
+         break;
+@@ -360,7 +365,7 @@
  
- void sig_handler(int signum)
- {
--  if (signum == SIGCHLD) {
--    int status;
--    pid_t pid;
--    do {
--      pid = waitpid (WAIT_ANY, &status, WNOHANG);
--      // Check the exit status value if 'eventcmd_checkstatus' is set
--      if (settings_opt_get_int("eventcmd_checkstatus")) {
--        if (pid > 0) {
--          // exit status 2 -> beep
--          if (WIFEXITED(status) && WEXITSTATUS(status) == 2) {
--            scr_beep();
--          }
--        }
--      }
--    } while (pid > 0);
--    signal(SIGCHLD, sig_handler);
--  } else if (signum == SIGTERM) {
-+  if (signum == SIGTERM) {
-     mcabber_terminate("Killed by SIGTERM");
-   } else if (signum == SIGINT) {
-     mcabber_terminate("Killed by SIGINT");
-@@ -332,7 +311,6 @@
+   if (optind < argc) {
+     fprintf(stderr, "Usage: %s [-h|-V|-f mcabberrc_file]\n\n", argv[0]);
+-    return -1;
++    return EXIT_FAILURE;
+   }
  
-   signal(SIGTERM, sig_handler);
-   signal(SIGINT,  sig_handler);
--  signal(SIGCHLD, sig_handler);
- #ifdef USE_SIGWINCH
-   signal(SIGWINCH, sig_handler);
- #endif
+   /* Initialize command system, roster and default key bindings */
+@@ -529,7 +534,7 @@
+ 
+   printf("\n\nThanks for using mcabber!\n");
+ 
+-  return 0;
++  return EXIT_SUCCESS;
+ }
+ 
+ /* vim: set expandtab cindent cinoptions=>2\:2(0 sw=2 ts=2:  For Vim users... */
--- a/series	Fri Jan 18 11:32:15 2013 +0200
+++ b/series	Sun Feb 24 04:47:32 2013 +0200
@@ -10,5 +10,7 @@
 add-cmake.diff
 use-gslice.diff
 timeformat.diff
+cmdopts.diff
+move-rename-jid.diff
 templates.diff
 dynamic-layout.diff