[cmdopts] Constantize some more fields
authorMyhailo Danylenko <isbear@ukrpost.net>
Sat, 23 Mar 2013 03:53:27 +0200
changeset 81 8e1ccd27d60f
parent 80 93088d0c8140
child 82 06d4a9185902
[cmdopts] Constantize some more fields
cmdopts.diff
docs/cmdopts.mdwn
--- a/cmdopts.diff	Fri Mar 22 02:09:13 2013 +0200
+++ b/cmdopts.diff	Sat Mar 23 03:53:27 2013 +0200
@@ -37,10 +37,10 @@
   * misc:
     * fix help for /buffer date
 
-diff -r 1b0b563a81e6 mcabber/doc/commands_HOWTO.mdwn
+diff -r 1b0b563a81e6 mcabber/doc/HOWTO_commands.mdwn
 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/doc/commands_HOWTO.mdwn	Fri Mar 22 01:56:17 2013 +0200
-@@ -0,0 +1,967 @@
++++ b/mcabber/doc/HOWTO_commands.mdwn	Sat Mar 23 03:49:50 2013 +0200
+@@ -0,0 +1,972 @@
 +
 +**New commands interface for MCabber**
 +
@@ -59,12 +59,12 @@
 + * Try to still be lightweight.
 + * Try to still be readable.
 +
-+It is built around static structure, "command description". User can add or
-+remove these structures to list of commands. FIXME more
++It is built around static structure, "command description".  User can add or
++remove these structures to list of commands.  *FIXME* more
 +
 +## Command description struct, 'cmdopts_t'
 +
-+[[!format c """ // -------------------------------------------------------------
++[[!format c """// --------------------------------------------------------------
 +
 +typedef struct cmdopts_struct cmdopts_t;
 +
@@ -85,52 +85,55 @@
 +    size_t              valno;
 +};
 +
-+// -------------------------------------------------------------      """     ]]
++// --------------------------------------------------------------     """     ]]
 +
 +This struct describes command as a whole and links to argument descriptions.
 +This struct is also used to describe individual subcommands, as they are quite
 +similar to normal command, because they can have their own options, arguments
-+and subcommands. The fields of this struct:
++and subcommands.  The fields of this struct:
 +
 + * 'name' - name of the command or subcommand.
 +
 + * 'flags' - currently there's only one flag:
 +
 +    + 'cmd_safe' -  command is safe to execute in main mcabberrc during
-+      initialization. Have no meaning for subcommands.
++      initialization.  Have no meaning for subcommands.
 +    + 'cmd_default' - default value of no flags enabled.
 + 
-+ * 'check' - execution environment checker for command. This callback is used to
-+   do general checks before even parsing command line. You can write your own
-+   checker or use standard ones, for example - 'cmd_check_online', that checks,
-+   if you are currently online.
-+
-+ * 'handle' - command function. It is executed only if command line was
-+   successfully parsed and argument values passed the type checking. Unused in
++ * 'check' - execution environment checker for command.  This callback is used
++   to do general checks before even parsing command line.  You can write your
++   own checker or use standard ones, for example - 'cmd_check_online', that
++   checks, if you are currently online.
++
++ * 'handle' - command function.  It is executed only if command line was
++   successfully parsed and argument values passed the type checking.  Unused in
 +   subcommands.
 +
 + * 'opts' - pointer to the array of 'cmdopt_t' structs, describing command-line
-+   options ("-f bar") and switches ("-x"), that this command accepts.
++   options ("-f bar") and switches ("-x"), that this command accepts.  Array
++   must end with option, that have 0 as short option character.
 + 
 + * 'args' - similarly, pointer to the array of 'cmdarg_t' structs, that describe
-+   command-line positional arguments (in order).
++   command-line positional arguments (in order).  Array must end with argument,
++   that have NULL name.
 + 
 + * 'cmds' - pointer to the array of subcommands of this command (or subcommand).
-+   How parser switches to subcommands we will describe later.
++   How parser switches to subcommands we will describe later.  Array must end
++   with subcommand, that have NULL name.
 + 
 + * 'userdata' - arbitrary pointer, where you can put some data, that should
-+   accompany this command or subcommand. Unused by parser.
++   accompany this command or subcommand.  Unused by parser.
 +
 + * 'valno' - this is internal value, that is initialized at command definition
-+   time, you should not modify it. Currently unused in subcommands.
++   time, you should not modify it.  Currently unused in subcommands.
 +
 +## Command function, 'cmd_handler_t'
 +
-+[[!format c """ // -------------------------------------------------------------
++[[!format c """// --------------------------------------------------------------
 +
 +typedef gchar *(*cmd_handler_t) (cmdopts_t *command, cmdarg_value_t *values);
 +
-+// -------------------------------------------------------------      """     ]]
++// --------------------------------------------------------------     """     ]]
 +
 +Command function is passed it's command definition struct (mainly to give it
 +access to userdata) and dynamically allocated array of parsed argument values.
@@ -144,7 +147,7 @@
 +
 +## Option description struct, 'cmdopt_t'
 +
-+[[!format c """ // -------------------------------------------------------------
++[[!format c """// --------------------------------------------------------------
 +
 +typedef struct {
 +    const char stortopt;
@@ -152,14 +155,14 @@
 +    cmdarg_t   arg;
 +} cmdopt_t;
 +
-+// -------------------------------------------------------------      """     ]]
++// --------------------------------------------------------------     """     ]]
 +
 +This struct just adds short option character and long option name to generic
 +argument struct, that we'll look at right now.
 +
 +## Argument description struct, 'cmdarg_t'
 +
-+[[!format c """ // -------------------------------------------------------------
++[[!format c """// --------------------------------------------------------------
 +
 +typedef struct cmdarg_struct cmdarg_t;
 +
@@ -174,6 +177,7 @@
 +    cmdarg_eol      = 0x0003, // catchall + plain
 +    cmdarg_chreq    = 0x000C, // check + required
 +    cmdarg_special  = 0x0030, // subcmd + switch
++    cmdarg_trigger  = 0x0024, // switch + check
 +} cmdarg_flags_t;
 +
 +struct cmdarg_struct {
@@ -186,10 +190,10 @@
 +    gconstpointer        userdata;
 +};
 +
-+// -------------------------------------------------------------      """     ]]
++// --------------------------------------------------------------     """     ]]
 +
 +This struct stores information about mapping between command-line entity
-+(switch, option, argument, subcommand) and element in 'values' array. First,
++(switch, option, argument, subcommand) and element in 'values' array.  First,
 +let's briefly describe fields, and then walk through their use in different
 +entities.
 +
@@ -221,7 +225,7 @@
 + 
 + * 'defval' - default value for argument in "unchecked" form - i.e., in the form
 +   of string, as it appears on command line (we'll discuss type checkers and
-+   what can they do to value later). Before parsing command line, parser will
++   what can they do to value later).  Before parsing command line, parser will
 +   assign this value to corresponding value structure.
 +
 + * 'type' - pointer to structure, describing argument type.
@@ -229,47 +233,47 @@
 + * 'chkdata' - if type needs some additional info, it is a place to supply it.
 +
 + * 'userdata' - place for arbitrary info, that should accompany this argument or
-+   option. Unused by parser.
++   option.  Unused by parser.
 +
 +Now, let's discuss general case - option with argument or positional argument.
 +
 +When parser encounters such argument, it checks 'catchall' and 'plain' flags and
 +crops argument value from command line accordingly, then it assigns it to the
 +'value.arg' field of 'cmdarg_value_t' struct in array 'values' with index, given
-+in 'pos'. Also it marks such value as 'visited' and puts a link to argument
-+description into value's 'src' field. More about effect of these actions later,
++in 'pos'.  Also it marks such value as 'visited' and puts a link to argument
++description into value's 'src' field.  More about effect of these actions later,
 +in 'cmdarg_value_t' section.
 +
 +However, if argument struct is a part of option description struct, and have
-+flag 'switch' set, parser will not try to parse value. Instead it will increase
-+the count in 'value.swc' in corresponding 'cmdarg_value_t' struct. Argument name
-+for switches is essentially ignored, but for safety sake it is recommended to
-+duplicate switch long option name here. Flags 'catchall' and 'plain' obviously
-+have no effect. Flag 'check' makes switch a trigger, that flips between 'on' and
-+'off' for every occurence of flag on command line. Flags 'required' and 'subcmd'
-+also have no effect for obvious reasons. Default value is ignored for switches,
-+they always start with count 0 (off). Since switch is internal type, argument
-+type field is ignored as well. Flags and source fields of value are updated as
-+usual.
++flag 'switch' set, parser will not try to parse value.  Instead it will increase
++the count in 'value.swc' in corresponding 'cmdarg_value_t' struct.  Argument
++name for switches is essentially ignored, but for safety sake it is recommended
++to duplicate switch long option name here.  Flags 'catchall' and 'plain'
++obviously have no effect.  Flag 'check' makes switch a trigger, that flips
++between 'on' and 'off' for every occurence of flag on command line.  Flags
++'required' and 'subcmd' also have no effect for obvious reasons.  Default value
++is ignored for switches, they always start with count 0 (off).  Since switch is
++internal type, argument type field is ignored as well.  Flags and source fields
++of value are updated as usual.
 +
 +If flag 'subcmd' is set for positional argument, parser crops argument value
 +according to flags as usual, but instead of assigning it, walks through list of
 +subcommands in command description struct and compares obtained value to
-+subcommand names. If it finds corresponding subcommand, it assigns pointer to
++subcommand names.  If it finds corresponding subcommand, it assigns pointer to
 +subcommand description struct to 'value.cmd' field of corresponding
-+'cmdarg_value_t' struct and updates it's source and flags. Then, instead of
++'cmdarg_value_t' struct and updates it's source and flags.  Then, instead of
 +proceeding with parsing process, it recursively calls parser on remaining part
-+of command line, passing subparser subcommand description. Note, that if
++of command line, passing subparser subcommand description.  Note, that if
 +subcommand parser will end parsing before hitting end of command line, parser
-+will proceed with parsing arguments for main command. Default value and argument
-+type fields are ignored for subcommands.
++will proceed with parsing arguments for main command.  Default value and
++argument type fields are ignored for subcommands.
 +
 +Now let's take a look at value structure, that you'll be dealing with the most
 +in the actual code.
 +
 +## Argument value structure, 'cmdarg_value_t'
 +
-+[[!format c """ // -------------------------------------------------------------
++[[!format c """// --------------------------------------------------------------
 +
 +typedef struct cmdarg_value_struct cmdarg_value_t;
 +
@@ -280,29 +284,29 @@
 +} cmdval_flags_t;
 +
 +struct cmdarg_value_struct {
-+    cmdarg_t       *src;
++    const cmdarg_t *src;
 +    cmdval_flags_t flags;
 +    union {
-+        guint        uint;
-+        gint         sint;
-+        guint        swc;
-+        const gchar  *roarg;
-+        gchar        *arg;
-+        cmdopts_t    *cmd;
++        guint           uint;
++        gint            sint;
++        guint           swc;
++        const gchar     *roarg;
++        gchar           *arg;
++        const cmdopts_t *cmd;
 +        struct {
-+            gpointer   bud;
-+            gchar      *resource;
++            gpointer    bud;
++            gchar       *resource;
 +        } rjid;
-+        gpointer     ptr;
++        gpointer        ptr;
 +    } value;
 +};
 +
-+// -------------------------------------------------------------      """     ]]
++// --------------------------------------------------------------     """     ]]
 +
 +Command may happen to be called recursively - i.e., something in command may
 +cause the event, that will cause another call to the same command, thus we
 +cannot store actual values in command/argument definition struct, and have to
-+allocate dynamic memory for them. This struct is designed exactly for this.
++allocate dynamic memory for them.  This struct is designed exactly for this.
 +Let's take a look at it's fields:
 +
 + * 'src' - this points to the argument description, from which this struct is
@@ -334,56 +338,57 @@
 +
 +Parser starts by allocating memory for values array, and then initializing it by
 +walking through command description, looking at options and arguments and
-+assigning default values to corresponding entries in array. It also puts pointer
-+to the argument description into value's 'src' field. Thus, all used in command
-+description values will have this field initialized, even if they were not
-+specified on command line. This comes handly later, when checking for reqired
-+value presence. For switches parser just sets the counter to zero. Note, that
-+parser does not descend into subcommands at this stage. It does the same
-+procedure for subcommand, but later, when it already knows which subcommand is
-+selected. Also note, that if several arguments have the same value index, parser
-+will use latest encountered one to initialize the value. This is used for
-+default value in "argument clustering", that I'll show you later.
++assigning default values to corresponding entries in array.  It also puts
++pointer to the argument description into value's 'src' field.  Thus, all used in
++command description values will have this field initialized, even if they were
++not specified on command line.  This comes handly later, when checking for
++reqired value presence.  For switches parser just sets the counter to zero.
++Note, that parser does not descend into subcommands at this stage.  It does the
++same procedure for subcommand, but later, when it already knows which subcommand
++is selected.  Also note, that if several arguments have the same value index,
++parser will use latest encountered one to initialize the value.  This is used
++for default value in "argument clustering", that I'll show you later.
 +
 +Then parser calls command environment checker callback (if present), and if it
-+returns error - terminates the process right now. Note, that subcommands can
++returns error - terminates the process right now.  Note, that subcommands can
 +also have checkers.
 +
-+Next parser does its job of parsing command line. Each time it extracts argument
-+value, it into 'value.arg' field of corresponding value entry and pointer to
-+argument description struct into 'src' field. Also it sets 'visited' flag on
-+value. At this stage value is still just unchecked string, except for special
-+argument types. For switch occurence count in 'value.swc' gets increased each
-+time argument was specified. Note however, that if several switches use the same
-+value index ("clustered switches"), counter gets reset, when switches change one
-+another in sequence - i.e. "-e -s -s -s" will count as three "-s", but "-s -s -e
-+-s" will count as only one "-s". For subcommands parser checks for corresponding
-+subcommand in 'cmds' list, assigns it to 'value.cmd' and recursively passes the
-+end of command line to be parsed with subcommand description. Note, that for
-+subcommands parser does "checking on the spot" - if parsed argument value does
-+not match any subcommand, and argument have 'required' flag set, it raises error
-+immediately (if flag is not set, it merely assigns NULL and proceeds parsing
-+according to current command description).
-+
-+Then parser walks through array of values and performs value checking. Note,
++Next parser does its job of parsing command line.  Each time it extracts
++argument value, it into 'value.arg' field of corresponding value entry and
++pointer to argument description struct into 'src' field.  Also it sets 'visited'
++flag on value.  At this stage value is still just unchecked string, except for
++special argument types.  For switch occurence count in 'value.swc' gets
++increased each time argument was specified.  Note however, that if several
++switches use the same value index ("clustered switches"), counter gets reset,
++when switches change one another in sequence - i.e. "-e -s -s -s" will count as
++three "-s", but "-s -s -e -s" will count as only one "-s".  For subcommands
++parser checks for corresponding subcommand in 'cmds' list, assigns it to
++'value.cmd' and recursively passes the end of command line to be parsed with
++subcommand description.  Note, that for subcommands parser does "checking on the
++spot" - if parsed argument value does not match any subcommand, and argument
++have 'required' flag set, it raises error immediately (if flag is not set, it
++merely assigns NULL and proceeds parsing according to current command
++description).
++
++Then parser walks through array of values and performs value checking.  Note,
 +that all values, that need checking at this point should have 'src' field
 +initialized - either set at default value assignment step, or during parsing,
-+so, parser knows properties of value's argument. Parser only pays attention to
++so, parser knows properties of value's argument.  Parser only pays attention to
 +the values, that either have 'visited' flag set (i.e. provided by user) or that
 +have 'check' flag in argument description (useful for mandatory arguments or
-+default values, that need convesion). If value corresponds to a switch, and
++default values, that need convesion).  If value corresponds to a switch, and
 +argument have 'check' flag set, switch occurence count is replaced by remainder
-+of division it by 2 (this way switch behaves like trigger). If it is a
++of division it by 2 (this way switch behaves like trigger).  If it is a
 +subcommand, and it have 'required' flag set, parser checks, if it have non-NULL
-+value. If it is usual argument (option or positional), and it does have 'type',
++value.  If it is usual argument (option or positional), and it does have 'type',
 +that have 'check' callback set, parser calls this checker, passing it value
 +structure (again, value structure contains pointer to argument description, so,
-+checker can access 'chkdata' field, supplied by user). If checker returns error
-+string and argument have 'required' flag set, parser raises error. If flag is
++checker can access 'chkdata' field, supplied by user).  If checker returns error
++string and argument have 'required' flag set, parser raises error.  If flag is
 +not set, parser just prints warning and proceeds with checking.
 +
 +If checking was successful, parser calls command function, providing it with
-+command description and values array. This function can also return error, but
++command description and values array.  This function can also return error, but
 +at this stage it does not change process, only causes error message to be
 +printed.
 +
@@ -393,7 +398,7 @@
 +
 +## Argument type, 'cmdarg_type_t'
 +
-+[[!format c """ // -------------------------------------------------------------
++[[!format c """// --------------------------------------------------------------
 +
 +typedef struct cmdarg_type_struct cmdarg_type_t;
 +
@@ -408,7 +413,7 @@
 +    cmdarg_completor_t  complete;
 +};
 +
-+// -------------------------------------------------------------      """     ]]
++// --------------------------------------------------------------     """     ]]
 +
 +As you can see, argument type is nothing more than a set of callbacks:
 +
@@ -420,38 +425,38 @@
 +   should be set to corresponding function, and each time checker really needs
 +   value to be freed, it should set flag 'freeme' on value.
 +
-+ * 'complete' - FIXME not yet designed callback, that will return list of
++ * 'complete' - *FIXME* not yet designed callback, that will return list of
 +   possible completions according to given prefix.
 +
 +After parsing command line parser performs argument value checking, that's where
-+it calls 'check' callbacks.  Checker is given pointer to value structure, that
-+it needs to check. Checker can modify value string (except when it is default
++it calls 'check' callbacks.   Checker is given pointer to value structure, that
++it needs to check.  Checker can modify value string (except when it is default
 +value, but you have to supply your default values so, that they do not need
 +modifying) or completely replace it with another string or even non-string
-+object. If checker uses some resources (eg. allocates memory for replacement
++object.  If checker uses some resources (eg.  allocates memory for replacement
 +value), it can set the flag 'freeme' on value to request call to value
-+destructor, when values array will be freed. If checker needs some additional
++destructor, when values array will be freed.  If checker needs some additional
 +data (eg. it is some generic checker, that needs list of valid values or other
-+parameters), these data can be supplied in 'chkdata' field. Checker function
++parameters), these data can be supplied in 'chkdata' field.  Checker function
 +should return NULL on success or error string, that will be g_free()'d by
-+parser. Take note, that if argument does not have 'reqired' flag set, parser
++parser.  Take note, that if argument does not have 'reqired' flag set, parser
 +will ignore checker error, so, it is recommended to nullify invalid value before
 +returning error (but it is not required).
 +
 +# Examples
 +
 +When writing description for a command, first thing, you have to do - is to
-+determine, which values your command can get from user. You don't have to be
++determine, which values your command can get from user.  You don't have to be
 +shy - new interface is designed to encourage commands to be as flexible and
-+option-rich as possible. 
++option-rich as possible.  
 +
 +Second - consider, which ones are to be specified as positional arguments, and
 +which should become options or switches.
 +
 +Next you will want to decide, which checks and restrictions should you put on
-+values. Essentially, determine value type.
-+
-+And then you can begin writing command definition. So, let's start with
++values.  Essentially, determine value type.
++
++And then you can begin writing command definition.  So, let's start with
 +something simple.
 +
 +## Single-argument no-checks command
@@ -463,10 +468,10 @@
 +
 +Definition for such command will look like:
 +
-+[[!format c """ // -------------------------------------------------------------
++[[!format c """// --------------------------------------------------------------
 +
 +// command function predeclaration
-+gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values);
++gchar *do_ex1 (const cmdopts_t *command, cmdarg_value_t *values);
 +
 +// command arguments definition
 +cmdopts_t def_ex1 = {
@@ -492,8 +497,8 @@
 +};
 +
 +// Command function gets shown above command description (we don't need it) and
-+// argument value list. Returns error message or NULL.
-+gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values)
++// argument value list.  Returns error message or NULL.
++gchar *do_ex1 (const cmdopts_t *command, cmdarg_value_t *values)
 +{
 +    gchar *message = values[0].value.arg;
 +    // now do something with message:
@@ -515,22 +520,22 @@
 +cmd_undef (&def_ex1);
 +...
 +
-+[[!format c """ // -------------------------------------------------------------
++[[!format c """// --------------------------------------------------------------
 +
 +A lot of things to do to achieve a simple goal - does not look quite appealing
-+so far. Still, let's tweak our example a bit.
++so far.  Still, let's tweak our example a bit.
 +
 +Remember the third step - decide, which checks should apply to our argument.
 +Now, look at our command - we check, if message is NULL or if message is empty.
 +But imagine, that user has given us a message " " - it's of no big use to us,
 +so, probably, we should also strip leading/trailing spaces before doing the
-+check. That's where argument types come into play. We can write argument
++check.  That's where argument types come into play.  We can write argument
 +checker for that! But luckily, we already have built-in standard checker, that
-+does exactly what we need - checks if string contains non-space characters. All
++does exactly what we need - checks if string contains non-space characters.  All
 +we need to do - to specify '&cmdarg_type_nonspace' as argument type and remove
 +our check inside of the command:
 +
-+[[!format c """ // -------------------------------------------------------------
++[[!format c """// --------------------------------------------------------------
 +
 +...
 +cmdopts_t def_ex1 = {
@@ -561,7 +566,7 @@
 +    NULL,
 +};
 +
-+gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values)
++gchar *do_ex1 (const cmdopts_t *command, cmdarg_value_t *values)
 +{
 +    scr_log_print (LPRINT_NORMAL, "Got the message: \"%s\".",
 +                   values[0].value.arg);
@@ -569,17 +574,17 @@
 +}
 +...
 +
-+// -------------------------------------------------------------      """     ]]
-+
-+Ok, that's a little bit better. Now let's move on to something more complex.
++// --------------------------------------------------------------     """     ]]
++
++Ok, that's a little bit better.  Now let's move on to something more complex.
 +
 +## Switches
 +
 +Let's add switches '-s' and '-l', that will define, where to print the message
-+to - to log or to screen. For that we will need another two value indices - one
++to - to log or to screen.  For that we will need another two value indices - one
 +for each switch.
 +
-+[[!format c """ // -------------------------------------------------------------
++[[!format c """// --------------------------------------------------------------
 +
 +...
 +cmdopts_t def_ex1 = {
@@ -613,7 +618,7 @@
 +    NULL,
 +};
 +
-+gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values)
++gchar *do_ex1 (const cmdopts_t *command, cmdarg_value_t *values)
 +{
 +    // default value
 +    guint whereto = LPRINT_NORMAL;
@@ -626,21 +631,21 @@
 +}
 +...
 +
-+// -------------------------------------------------------------      """     ]]
++// --------------------------------------------------------------     """     ]]
 +
 +Ok, that works, but what if user have aliases, and wants last specified option
 +to override the value? Currently, if -s was once specified, -l will not have any
-+effect, regardless of count or position in command line. Not that good. Let's
-+use the trick, that I call "argument clustering". We'll specify the same value
-+index for both switches. Since 'value' struct have the pointer to the argument,
++effect, regardless of count or position in command line.  Not that good.  Let's
++use the trick, that I call "argument clustering".  We'll specify the same value
++index for both switches.  Since 'value' struct have the pointer to the argument,
 +it was initialized from last time, we can recognize, which switch was used last.
 +By default this pointer points to the last argument with this index in command
-+definition - we can use that to specify default value. Now, to identify switches
-+we can use argument names, but 'argument' struct contains userdata field, where
-+we can put our LPRINT_* constants and just use it directly. So, with clustered
-+switches, we will have:
-+
-+[[!format c """ // -------------------------------------------------------------
++definition - we can use that to specify default value.  Now, to identify
++switches we can use argument names, but 'argument' struct contains userdata
++field, where we can put our LPRINT_* constants and just use it directly.  So,
++with clustered switches, we will have:
++
++[[!format c """// --------------------------------------------------------------
 +
 +...
 +cmdopts_t def_ex1 = {
@@ -650,7 +655,7 @@
 +    do_ex1,
 +    (cmdopt_t[3]){
 +        // Set both argument indices to 1, specify our constants in userdata
-+        // field. Screen is default value, thus, it goes last.
++        // field.  Screen is default value, thus, it goes last.
 +        { 'l', "log",    { "log",    1, cmdarg_switch, NULL, NULL, NULL,
 +                             (gpointer)LPRINT_LOG    } },
 +        { 's', "screen", { "screen", 1, cmdarg_switch, NULL, NULL, NULL,
@@ -665,7 +670,7 @@
 +    NULL,
 +};
 +
-+gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values)
++gchar *do_ex1 (const cmdopts_t *command, cmdarg_value_t *values)
 +{
 +    scr_log_print ((guint)values[1].src -> userdata,
 +                   "Got the message: \"%s\".", values[0].value.arg);
@@ -673,9 +678,9 @@
 +}
 +...
 +
-+// -------------------------------------------------------------      """     ]]
-+
-+That's much better. This trick may be quite useful not only with switches, but
++// --------------------------------------------------------------     """     ]]
++
++That's much better.  This trick may be quite useful not only with switches, but
 +also with options, sometimes even clustering options with arguments can be
 +handy.
 +
@@ -685,33 +690,33 @@
 +'check' and 'required' mostly only in combination with default value - otherwise
 +it defeats the purpose - to be optional.
 +
-+[[!format c """ // -------------------------------------------------------------
++[[!format c """// --------------------------------------------------------------
 +
 +// TODO:
 +//   example (not really used as of now - were too complex to deal using old
 +//   interface).
 +
-+// -------------------------------------------------------------      """     ]]
++// --------------------------------------------------------------     """     ]]
 +
 +## Subcommands
 +
-+Now, let's discuss another internal argument type - subcommand. Since
++Now, let's discuss another internal argument type - subcommand.  Since
 +subcommands are quite common in mcabber, and since they have quite big impact on
 +parsing process, they were made a part of parser.
 +
-+Currently, only positional arguments can be subcommands. You can have options or
++Currently, only positional arguments can be subcommands.  You can have options or
 +other arguments precede them, though in practice there's no examples of that so
 +far.
 +
-+So, to indicate, that argument is a subcommand, you just add flag 'subcmd'. When
-+parser will encounter such argument, it will look up command structure with
++So, to indicate, that argument is a subcommand, you just add flag 'subcmd'.
++When parser will encounter such argument, it will look up command structure with
 +specified name in the list 'cmds' of command definition and proceed parsing,
-+using that command definition instead of main one. A good example of command
++using that command definition instead of main one.  A good example of command
 +with several completely different subcommands would be '/color', so, let's look:
 +
-+[[!format c """ // -------------------------------------------------------------
-+
-+static gchar *do_color (cmdopts_t *command, cmdarg_value_t *values);
++[[!format c """// --------------------------------------------------------------
++
++static gchar *do_color (const cmdopts_t *command, cmdarg_value_t *values);
 +
 +// We will put these values in subcommand definition 'userdata' fields
 +// to simplify the task of determining, which subcommand was actually selected.
@@ -794,7 +799,7 @@
 +    },
 +};
 +
-+static gchar *do_color (cmdopts_t *options, cmdarg_value_t *values)
++static gchar *do_color (const cmdopts_t *options, cmdarg_value_t *values)
 +{
 +    scmd_color_t subcmd =
 +                  (scmd_color_t) (values[pos_color_scmd].value.cmd -> userdata);
@@ -827,7 +832,7 @@
 +    return NULL;
 +}
 +
-+// -------------------------------------------------------------      """     ]]
++// --------------------------------------------------------------     """     ]]
 +
 +Here you also see a lot of new types:
 +
@@ -853,7 +858,7 @@
 +
 +Let's take a look at simple checker, that we've encountered first - 'nonspace':
 +
-+[[!format c """ // -------------------------------------------------------------
++[[!format c """// --------------------------------------------------------------
 +
 +// Checker gets parsed value string in 'value.arg', argument description in
 +// 'src' and returns error string or NULL.
@@ -902,11 +907,11 @@
 +    NULL,
 +};
 +
-+// -------------------------------------------------------------      """     ]]
-+
-+Quite simple, I hope. Now, let's look at more complex type - 'fjid':
-+
-+[[!format c """ // -------------------------------------------------------------
++// --------------------------------------------------------------     """     ]]
++
++Quite simple, I hope.  Now, let's look at more complex type - 'fjid':
++
++[[!format c """// --------------------------------------------------------------
 +
 +// This checker checks syntax of fjid and expands "current-buddy" expressions
 +// "." and "./resource".
@@ -966,13 +971,13 @@
 +    NULL,
 +};
 +
-+// -------------------------------------------------------------      """     ]]
++// --------------------------------------------------------------     """     ]]
 +
 +If possible, you are encouraged to re-use existing checkers - for example, bjid
 +checker uses fjid checker to expand "current-buddy" expressions and check
 +syntax, and only strips resource afterwards:
 +
-+[[!format c """ // -------------------------------------------------------------
++[[!format c """// --------------------------------------------------------------
 +
 +gchar *cmdarg_check_bjid (cmdarg_value_t *arg)
 +{
@@ -996,21 +1001,21 @@
 +    NULL,
 +};
 +
-+// -------------------------------------------------------------      """     ]]
-+
-+So far we've only modified string in value. But checkers are not limited to
++// --------------------------------------------------------------     """     ]]
++
++So far we've only modified string in value.  But checkers are not limited to
 +this, for example, uint checker performs atoi() on value and assigns resulting
-+number to value.uint. Take a look at definition of cmdarg_value_t struct - value
-+is actually a union of different types of value. If you need something different
-+from existing - you can always allocate your own struct and use value.ptr.
-+However, if you think, that your case is generic enough - contact mcabber
-+developers, we'll consider adding more variants there. Maybe we'll even add your
-+argument type to built-in types.
++number to value.uint.  Take a look at definition of cmdarg_value_t struct -
++value is actually a union of different types of value.  If you need something
++different from existing - you can always allocate your own struct and use
++value.ptr.  However, if you think, that your case is generic enough - contact
++mcabber developers, we'll consider adding more variants there.  Maybe we'll even
++add your argument type to built-in types.
 +
 +<!-- vim: se ts=4 sw=4 et filetype=markdown tw=80: -->
 diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_buffer.txt
 --- a/mcabber/doc/help/cs/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/cs/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_buffer.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -25,7 +25,7 @@
   Přesune se o [n] řádků nahoru (výchozí: polovina obrazovky).
  /buffer down [n]
@@ -1022,7 +1027,7 @@
   Přesune se na procentuální pozici n%.
 diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_del.txt
 --- a/mcabber/doc/help/cs/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/cs/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_del.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
@@ -1031,7 +1036,7 @@
  Smaže aktuální kontakt ze seznamu kontaktů (rosteru) a zruší povolení oznamování o stavu daného kontaktu (autorizaci) na obou stranách.
 diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_move.txt
 --- a/mcabber/doc/help/cs/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/cs/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_move.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [skupina]
@@ -1042,7 +1047,7 @@
  Tip: V módu rozhovoru lze použít "/roster alternate" pro skok na přesunutý kontakt.
 diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_rename.txt
 --- a/mcabber/doc/help/cs/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/cs/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_rename.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME jméno
@@ -1054,7 +1059,7 @@
 +Optionally you can use one of --jid, --group or --name to select object, different from current.
 diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_buffer.txt
 --- a/mcabber/doc/help/de/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/de/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/de/hlp_buffer.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -25,7 +25,7 @@
   Scrollt den Puffer um n Zeilen hoch. Gibt man keine Zahl an, scrollt er um einen halben Bildschirm
  /buffer down [n]
@@ -1066,7 +1071,7 @@
   Springe zur Position "n" im Chatpuffer
 diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_del.txt
 --- a/mcabber/doc/help/de/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/de/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/de/hlp_del.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
@@ -1075,7 +1080,7 @@
  Löscht den gerade ausgewählten Buddy vom Roster. Außerdem werden die automatischen Presence Benachrichtigungen vom/zum Buddy gestoppt.
 diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_move.txt
 --- a/mcabber/doc/help/de/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/de/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/de/hlp_move.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,6 +1,7 @@
  
 - /MOVE [groupname]
@@ -1087,7 +1092,7 @@
  Tipp: Wenn der Chatmodus aktiviert ist, kannst du "/roster alternate" benutzen um zu dem gerade bewegten Buddy zu springen.
 diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_rename.txt
 --- a/mcabber/doc/help/de/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/de/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/de/hlp_rename.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME name
@@ -1099,7 +1104,7 @@
 +Optionally you can use one of --jid, --group or --name to select object, different from current.
 diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_buffer.txt
 --- a/mcabber/doc/help/en/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/en/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/en/hlp_buffer.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -25,7 +25,7 @@
   Scroll the buffer up [n] lines (default: half a screen)
  /buffer down [n]
@@ -1111,7 +1116,7 @@
   Jump to position %n of the buddy chat buffer
 diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_del.txt
 --- a/mcabber/doc/help/en/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/en/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/en/hlp_del.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
@@ -1121,7 +1126,7 @@
 +Delete the current buddy or one, specified with [jid] from our roster, unsubscribe from its presence notification and unsubscribe it from ours.
 diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_move.txt
 --- a/mcabber/doc/help/en/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/en/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/en/hlp_move.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [groupname]
@@ -1132,7 +1137,7 @@
  Tip: if the chatmode is enabled, you can use "/roster alternate" to jump to the moved buddy.
 diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_rename.txt
 --- a/mcabber/doc/help/en/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/en/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/en/hlp_rename.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME name
@@ -1144,7 +1149,7 @@
 +Optionally you can use one of --jid, --group or --name to select object, different from current.
 diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_buffer.txt
 --- a/mcabber/doc/help/fr/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/fr/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_buffer.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -25,7 +25,7 @@
   Défile vers le haut de [n] lignes (par défaut un demi écran)
  /buffer down [n]
@@ -1156,7 +1161,7 @@
   Va à la position n% du tampon
 diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_del.txt
 --- a/mcabber/doc/help/fr/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/fr/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_del.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
@@ -1165,7 +1170,7 @@
  Supprime le contact sélectionné du roster, supprime notre abonnement à ses notifications de présence et supprime son abonnement aux nôtres.
 diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_move.txt
 --- a/mcabber/doc/help/fr/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/fr/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_move.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [groupname]
@@ -1176,7 +1181,7 @@
  Astuce : si le mode discussion (chatmode) est activé, vous pouvez utiliser "/roster alternate" pour vous positionner sur le contact que vous venez de déplacer.
 diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_rename.txt
 --- a/mcabber/doc/help/fr/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/fr/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_rename.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME nom
@@ -1188,7 +1193,7 @@
 +Optionally you can use one of --jid, --group or --name to select object, different from current.
 diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_buffer.txt
 --- a/mcabber/doc/help/it/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/it/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/it/hlp_buffer.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -25,7 +25,7 @@
   Fa scorrere indietro il buffer di [n] linee (default: metà schermo)
  /buffer down [n]
@@ -1200,7 +1205,7 @@
   Salta alla posizione %n del buffer di chat corrente
 diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_del.txt
 --- a/mcabber/doc/help/it/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/it/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/it/hlp_del.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
@@ -1209,7 +1214,7 @@
  Elimina il contatto corrente dal roster, cancellando la sottoscrizione alle reciproche notifiche della propria presenza.
 diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_move.txt
 --- a/mcabber/doc/help/it/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/it/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/it/hlp_move.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [gruppo]
@@ -1220,7 +1225,7 @@
  Trucco: se la modalità chat è abilitata, puoi usare "/roster alternate" per spostarti sul contatto appena mosso.
 diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_rename.txt
 --- a/mcabber/doc/help/it/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/it/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/it/hlp_rename.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME nome
@@ -1232,7 +1237,7 @@
 +Optionally you can use one of --jid, --group or --name to select object, different from current.
 diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_buffer.txt
 --- a/mcabber/doc/help/nl/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/nl/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_buffer.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -25,7 +25,7 @@
   Scroll de buffer [n] regels omhoog (standaard: een half scherm)
  /buffer down [n]
@@ -1244,7 +1249,7 @@
   Spring naar positie %n in de buddy chat buffer
 diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_del.txt
 --- a/mcabber/doc/help/nl/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/nl/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_del.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
@@ -1253,7 +1258,7 @@
  Verwijder de actieve buddy uit ons roster, en zet het wederzijds toezenden van status veranderingen stop.
 diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_move.txt
 --- a/mcabber/doc/help/nl/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/nl/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_move.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [groepsnaam]
@@ -1264,7 +1269,7 @@
  Tip: indien chatmode actief is, kun je "/roster alternate" gebruiken om direct naar de verplaatste buddy te springen.
 diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_rename.txt
 --- a/mcabber/doc/help/nl/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/nl/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_rename.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME naam
@@ -1276,7 +1281,7 @@
 +Optionally you can use one of --jid, --group or --name to select object, different from current.
 diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_del.txt
 --- a/mcabber/doc/help/pl/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/pl/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_del.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
@@ -1285,7 +1290,7 @@
  Usuwa aktualnie zaznaczoną osobę z rostera, usuwa subskrypcję powiadomienia dostępności u danej osoby oraz u nas.
 diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_move.txt
 --- a/mcabber/doc/help/pl/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/pl/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_move.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [nazwa grupy]
@@ -1296,7 +1301,7 @@
  Podpowiedź: jeśli jest włączony tryb czatu, możesz użyć "/roster alternate" aby skoczyć do przeniesionej osoby.
 diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_rename.txt
 --- a/mcabber/doc/help/pl/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/pl/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_rename.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME nazwa
@@ -1308,7 +1313,7 @@
 +Optionally you can use one of --jid, --group or --name to select object, different from current.
 diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_buffer.txt
 --- a/mcabber/doc/help/ru/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/ru/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_buffer.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -25,7 +25,7 @@
   Перемещает на [n] строк вверх в буфере (истории переписки) (по умолчанию: половина экрана)
  /buffer down [n]
@@ -1320,7 +1325,7 @@
   Перемещает на позицию %n в текущем буфере (истории переписки)
 diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_del.txt
 --- a/mcabber/doc/help/ru/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/ru/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_del.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
@@ -1330,7 +1335,7 @@
 +Удаляет текущего пользователя (или указанного с помощью jid) из списка контактов, отключает уведомления о его статусе и отключает уведомление пользователя о вашем статусе.
 diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_move.txt
 --- a/mcabber/doc/help/ru/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/ru/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_move.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,6 +1,7 @@
  
 - /MOVE [groupname]
@@ -1342,7 +1347,7 @@
  
 diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_rename.txt
 --- a/mcabber/doc/help/ru/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/ru/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_rename.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME name
@@ -1354,7 +1359,7 @@
 +Для указания обьекта, отличного от текущего, можно использовать опции --jid, --group и --name.
 diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_buffer.txt
 --- a/mcabber/doc/help/uk/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/uk/hlp_buffer.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_buffer.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -25,7 +25,7 @@
   Посунути буфер вверх на n рядків (якщо не вказано - пів екрану).
  /buffer down [n]
@@ -1366,7 +1371,7 @@
   Перейти до вказаної у процентах позиції.
 diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_del.txt
 --- a/mcabber/doc/help/uk/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/uk/hlp_del.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_del.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
@@ -1376,7 +1381,7 @@
 +Потерти поточний контакт (або контакт, що має вказаний jid) зі списку. Також відписатися від його сповіщень про статус і відписати його від ваших.
 diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_move.txt
 --- a/mcabber/doc/help/uk/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/uk/hlp_move.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_move.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [група]
@@ -1388,7 +1393,7 @@
  Примітка: в режимі розмови можна використати "/roster alternate", щоб перейти до нового місця контакту контакту.
 diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_rename.txt
 --- a/mcabber/doc/help/uk/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/uk/hlp_rename.txt	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_rename.txt	Sat Mar 23 03:49:50 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME ім'я
@@ -1399,7 +1404,7 @@
 +Опції --jid, --group та --name дозволяють перейменовувати об’єкти, відмінні від поточного.
 diff -r 1b0b563a81e6 mcabber/mcabber/commands.c
 --- a/mcabber/mcabber/commands.c	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/mcabber/commands.c	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/mcabber/commands.c	Sat Mar 23 03:49:50 2013 +0200
 @@ -19,7 +19,7 @@
   * USA
   */
@@ -1409,7 +1414,7 @@
  #include <stdlib.h>
  #include <sys/types.h>
  #include <sys/stat.h>
-@@ -43,512 +43,671 @@
+@@ -43,512 +43,681 @@
  #include "xmpp.h"
  #include "main.h"
  
@@ -1443,7 +1448,7 @@
 +
 +//static void room_bookmark(gpointer bud, char *arg);
 +
-+#define BUILTIN_COUNT 9
++#define BUILTIN_COUNT 10
 +static cmdopts_t def_roster,
 +                 def_color,
 +                 def_status,
@@ -1451,10 +1456,10 @@
 +                 def_add,
 +                 def_del,
 +                 def_group,
-+                 def_say;
++                 def_say,
 +                 def_msay,
++                 def_say_to;
 +#if 0
-+                 def_say_to,
 +                 def_buffer,
 +                 def_clear,
 +                 def_info,
@@ -1569,8 +1574,8 @@
 +  cmd_list[6]  = &def_group;
 +  cmd_list[7]  = &def_say;
 +  cmd_list[8]  = &def_msay;
++  cmd_list[9]  = &def_say_to;
 +#if 0
-+  cmd_list[9]  = &def_say_to;
 +  cmd_list[10] = &def_buffer;
 +  cmd_list[11] = &def_clear;
 +  cmd_list[12] = &def_info;
@@ -1612,23 +1617,23 @@
 +  cmd_count = 0;
 +}
 +
-+static size_t cmdopts_count_values (cmdopts_t *command)
++static size_t cmdopts_count_values (const cmdopts_t *command)
 +{
 +  size_t max = -1;
 +  if (command -> opts) {
-+    cmdopt_t *opt;
++    const cmdopt_t *opt;
 +    for (opt = command -> opts; opt -> shortopt != 0; opt ++)
 +      if (opt -> arg.pos > max)
 +        max = opt -> arg.pos;
 +  }
 +  if (command -> args) {
-+    cmdarg_t *arg;
++    const cmdarg_t *arg;
 +    for (arg = command -> args; arg -> name != NULL; arg ++)
 +      if (arg -> pos > max)
 +        max = arg -> pos;
 +  }
 +  if (command -> cmds) {
-+    cmdopts_t *scmd;
++    const cmdopts_t *scmd;
 +    for (scmd = command -> cmds; scmd -> name != NULL; scmd ++) {
 +      size_t cnt = cmdopts_count_values (scmd);
 +      if (cnt > max)
@@ -1721,7 +1726,7 @@
 +  return error;
 +}
 +
-+static cmdarg_value_t *cmdopts_allocate_values (cmdopts_t *command)
++static cmdarg_value_t *cmdopts_allocate_values (const cmdopts_t *command)
 +{
 +  cmdarg_value_t *values;
 +  size_t         n = command -> valno;
@@ -1746,7 +1751,7 @@
 +// Parsed string MUST be writable. Regardless of success or error, input
 +// string should be considered corrupted by parsing process.
 +// Even in case of error, commanddef should be passed to cmdopts_free().
-+static gchar *cmdopts_parse_internal(gchar **pr, gchar **er, cmdopts_t *command, cmdarg_value_t *values)
++static gchar *cmdopts_parse_internal(gchar **pr, gchar **er, const cmdopts_t *command, cmdarg_value_t *values)
 +{
 +  enum {             // Parser state transitions:
 +    in_space,        // -> in_space, in_optstart, in_argstart
@@ -1755,21 +1760,21 @@
 +    in_longoptstart, // -> in_longopt, in_space, in_argstart ("---")
 +    in_longopt,      // -> in_longopt, in_space, error
 +    in_argstart,     // -> in_space, error
-+  } state = in_argstart;     // current parser state
-+  gchar    *p        = *pr;  // current pointer
-+  gchar    *e        = *er;  // end of line pointer
-+  gchar    *s;               // start of current object pointer
-+  gboolean opts_ended = FALSE; // don't allow options any more
-+  cmdopt_t *option   = NULL; // option, for which argument is currently parsed
-+  size_t   argno     = 0;    // number of current positional argument
-+  gchar    *error    = NULL; // error message to return
++  } state = in_argstart;         // current parser state
++  gchar    *p            = *pr;  // current pointer
++  gchar    *e            = *er;  // end of line pointer
++  gchar    *s;                   // start of current object pointer
++  gboolean opts_ended   = FALSE; // don't allow options any more
++  const cmdopt_t *option = NULL; // option, for which argument is currently parsed
++  size_t   argno        = 0;     // number of current positional argument
++  gchar    *error       = NULL;  // error message to return
 +
 +  // prepare: set default values for arguments and unset some fields
 +  if (error == NULL) {
-+    gsize n;
++    size_t n;
 +    if (command -> opts) {
 +      for (n = 0; command -> opts[n].shortopt != 0; n ++) {
-+        cmdopt_t       *opt = command -> opts + n;
++        const cmdopt_t *opt = command -> opts + n;
 +        cmdarg_value_t *val = values + opt -> arg.pos;
 +        // do not overwrite already specified values
 +        if (val -> src == NULL || !(val -> flags & cmdval_visited)) {
@@ -1784,7 +1789,7 @@
 +    }
 +    if (command -> args) {
 +      for (n = 0; command -> args[n].name != NULL; n ++) {
-+        cmdarg_t       *arg = command -> args + n;
++        const cmdarg_t *arg = command -> args + n;
 +        cmdarg_value_t *val = values + arg -> pos;
 +        // do not overwrite already specified values
 +        if (val -> src == NULL || !(val -> flags & cmdval_visited)) {
@@ -1844,8 +1849,12 @@
 +        if (option != NULL) { // option is known
 +          if (option -> arg.flags & cmdarg_switch) { // it is switch
 +            cmdarg_value_t *val = values + option -> arg.pos;
-+            val -> value.swc ++;
-+            val -> src    = &(option -> arg);
++            if (val -> src != &(option -> arg)) {
++              val -> value.swc = 1;
++              val -> src       = &(option -> arg);
++            } else {
++              val -> value.swc ++;
++            }
 +            val -> flags |= cmdval_visited;
 +            option = NULL;
 +          } else if (p == e) {
@@ -1889,8 +1898,12 @@
 +        if (option != NULL) { // option is known
 +          if (option -> arg.flags & cmdarg_switch) { // it is switch
 +            cmdarg_value_t *val = values + option -> arg.pos;
-+            val -> value.swc ++;
-+            val -> src    = &(option -> arg);
++            if (val -> src != &(option -> arg)) {
++              val -> value.swc = 1;
++              val -> src       = &(option -> arg);
++            } else {
++              val -> value.swc ++;
++            }
 +            val -> flags |= cmdval_visited;
 +            option = NULL;
 +          } else if (p == e) {
@@ -1905,8 +1918,8 @@
 +        p ++;
 +      }
 +    } else if (state == in_argstart) { // option/command argument initialization
-+      const char *err;
-+      cmdarg_t   *arg;
++      const char     *err;
++      const cmdarg_t *arg;
 +
 +      if (option) { // option argument
 +        arg = &(option -> arg);
@@ -1933,19 +1946,21 @@
 +          option = NULL;
 +        } else { // normal argument
 +          if (arg -> flags & cmdarg_subcmd) { // subcommand
-+            cmdopts_t *subcmd;
++            const cmdopts_t *subcmd;
 +            for (subcmd = command -> cmds; subcmd -> name != NULL; subcmd ++)
 +              if (!strcmp (s, subcmd -> name))
 +                break;
 +            if (subcmd -> name != NULL) { // found subcommand
++              gchar *err;
 +              val -> value.cmd = subcmd;
-+              if ((error = cmdopts_parse_internal (&p, &e, subcmd, values))) {
-+                gchar *err = error;
++              if ((err = cmdopts_parse_internal (&p, &e, subcmd, values))) {
 +                error = g_strdup_printf("%s %s", command -> name, err);
 +                g_free (err);
 +              }
-+            } else { // wrong subcommand
++            } else if (arg -> flags & cmdarg_required) { // unknown subcommand
 +              error = g_strdup_printf("%s: Unable to find subcommand \"%s\".", command -> name, s);
++            } else { // XXX warning message?
++              val -> value.cmd = NULL;
 +            }
 +          }
 +          argno ++;
@@ -1966,7 +1981,7 @@
 +// - option          check              call checker          fatal check error
 +// - argument        check              call checker          fatal check error
 +// - subcommand      no effect          check for required    fail if missing
-+static gchar *cmdopts_check_values (cmdopts_t *command, cmdarg_value_t *values)
++static gchar *cmdopts_check_values (const cmdopts_t *command, cmdarg_value_t *values)
 +{
 +  size_t n = command -> valno;
 +
@@ -2012,7 +2027,7 @@
 +
 +//  cmdopts_free ( commanddef )
 +// Free various parser data, used in parsing process
-+static void cmdopts_free_values (cmdopts_t *command, cmdarg_value_t *values)
++static void cmdopts_free_values (const cmdopts_t *command, cmdarg_value_t *values)
  {
 -  cmd *n_cmd = g_slice_new0(cmd);
 -  strncpy(n_cmd->name, name, 32-1);
@@ -2573,7 +2588,7 @@
    if (!*line) { // User only pressed enter
      if (scr_get_multimode()) {
        scr_append_multiline("");
-@@ -556,141 +715,585 @@
+@@ -556,141 +725,585 @@
      }
      if (current_buddy) {
        if (buddy_gettype(BUDDATA(current_buddy)) & ROSTER_TYPE_GROUP)
@@ -2705,7 +2720,7 @@
 +//  command environment checkers
 +//
 +
-+gchar *cmd_check_online (cmdopts_t *command, cmdarg_value_t *values)
++gchar *cmd_check_online (const cmdopts_t *command, cmdarg_value_t *values)
 +{
 +  if (!xmpp_is_online())
 +    return g_strdup ("You are not connected!");
@@ -3263,7 +3278,7 @@
  static void display_and_free_note(struct annotation *note, const char *winId)
  {
    gchar tbuf[128];
-@@ -755,41 +1358,15 @@
+@@ -755,41 +1368,15 @@
    g_slist_free(notes);
  }
  
@@ -3313,14 +3328,14 @@
      struct annotation *note = xmpp_get_storage_rosternotes(bjid, FALSE);
      if (note) {
        display_and_free_note(note, bjid);
-@@ -800,484 +1377,622 @@
+@@ -800,484 +1387,662 @@
    }
  }
  
 -//  roster_updown(updown, nitems)
 -// updown: -1=up, +1=down
 -inline static void roster_updown(int updown, char *nitems)
-+static gchar *do_roster (cmdopts_t *command, cmdarg_value_t *values);
++static gchar *do_roster (const cmdopts_t *command, cmdarg_value_t *values);
 +
 +typedef enum {
 +  scmd_roster_bottom, scmd_roster_top, scmd_roster_up, scmd_roster_down,
@@ -3398,7 +3413,7 @@
 +  },
 +};
 +
-+static gchar *do_roster(cmdopts_t *options, cmdarg_value_t *values)
++static gchar *do_roster (const cmdopts_t *options, cmdarg_value_t *values)
  {
 -  int nbitems;
 -
@@ -3575,6 +3590,17 @@
 -    scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
 -    free_arg_lst(paramlst);
 -    return;
+-  }
+-
+-  if (!strcasecmp(subcmd, "roster")) {
+-    char *status, *wildcard, *color;
+-    char **arglist = split_arg(arg, 3, 0);
+-
+-    status = *arglist;
+-    wildcard = to_utf8(arglist[1]);
+-    color = arglist[2];
+-
+-    if (status && !strcmp(status, "clear")) { // Not a color command, clear all
 +  if (!g_strcmp0 (arg -> value.arg, "clear"))
 +    return NULL;
 +  else
@@ -3588,33 +3614,12 @@
 +};
 +
 +// bjid + "*"
-+// Returns string, not buddy.
-+// XXX:
-+//  * strdup jid?
-+//  * requires type in chkdata
 +static gchar *cmdarg_check_color_roomjid (cmdarg_value_t *arg)
 +{
-+  gchar *error;
-+
-+  if (!g_strcmp0(arg -> value.arg, "*"))
++  if (!g_strcmp0 (arg -> value.arg, "*"))
 +    return NULL;
-+  
-+  if (!(error = cmdarg_check_roster_bjid (arg))) {
-+    arg -> value.roarg = buddy_getjid (arg -> value.rjid.bud);
-   }
- 
--  if (!strcasecmp(subcmd, "roster")) {
--    char *status, *wildcard, *color;
--    char **arglist = split_arg(arg, 3, 0);
--
--    status = *arglist;
--    wildcard = to_utf8(arglist[1]);
--    color = arglist[2];
--
--    if (status && !strcmp(status, "clear")) { // Not a color command, clear all
-+  if (error)
-+    arg -> value.arg = NULL;
-+  return error;
++  else
++    return cmdarg_check_bjid (arg);
 +}
 +
 +static const cmdarg_type_t cmdarg_type_color_roomjid = {
@@ -3639,7 +3644,7 @@
 +
 +// command
 +
-+static gchar *do_color (cmdopts_t *command, cmdarg_value_t *values);
++static gchar *do_color (const cmdopts_t *command, cmdarg_value_t *values);
 +
 +typedef enum {
 +  scmd_color_roster,
@@ -3677,16 +3682,16 @@
 +    {"roster", cmd_default, NULL, NULL, NULL, (cmdarg_t[4]){
 +        { "statusmask|clear", pos_color_roster_status, cmdarg_chreq, NULL, &cmdarg_type_color_statusmask, (gpointer)"ofdna_?" },
 +        { "jidmask",          pos_color_roster_jid,    cmdarg_check, NULL, &cmdarg_type_bjidmask },
-+        { "color|-",          pos_color_roster_color,  cmdarg_check, NULL, &cmdarg_type_color    },
++        { "color|-",          pos_color_roster_color,  cmdarg_check, NULL, &cmdarg_type_color },
 +        {NULL}
 +      }, NULL, (gpointer)scmd_color_roster},
 +    {"muc", cmd_default, NULL, NULL, NULL, (cmdarg_t[3]){
-+        { "roomjid",         pos_color_muc_room, cmdarg_chreq, NULL, &cmdarg_type_color_roomjid, (gpointer)ROSTER_TYPE_ROOM },
-+        { "on|off|preset|-", pos_color_muc_mode, cmdarg_chreq, "on", &cmdarg_type_string2enum,   (gpointer)s2e_color_muc },
++        { "roomjid",         pos_color_muc_room, cmdarg_chreq, NULL, &cmdarg_type_color_roomjid },
++        { "on|off|preset|-", pos_color_muc_mode, cmdarg_chreq, "on", &cmdarg_type_string2enum, (gpointer)s2e_color_muc },
 +        {NULL}
 +      }, NULL, (gpointer)scmd_color_muc},
 +    {"mucnick", cmd_default, NULL, NULL, NULL, (cmdarg_t[3]){
-+        { "nick",    pos_color_nick_nick,  cmdarg_chreq, NULL, &cmdarg_type_nick  },
++        { "nick",    pos_color_nick_nick,  cmdarg_chreq, NULL, &cmdarg_type_nick },
 +        { "color|-", pos_color_nick_color, cmdarg_chreq, NULL, &cmdarg_type_color },
 +        {NULL}
 +      }, NULL, (gpointer)scmd_color_mucnick},
@@ -3694,7 +3699,7 @@
 +  },
 +};
 +
-+static gchar *do_color (cmdopts_t *options, cmdarg_value_t *values)
++static gchar *do_color (const cmdopts_t *options, cmdarg_value_t *values)
 +{
 +  scmd_color_t subcmd = (scmd_color_t) (values[pos_color_scmd].value.cmd -> userdata);
 +
@@ -3825,7 +3830,7 @@
 +
 +// command
 +
-+static gchar *do_status (cmdopts_t *command, cmdarg_value_t *values);
++static gchar *do_status (const cmdopts_t *command, cmdarg_value_t *values);
 +
 +typedef enum {
 +  pos_status_status  = 0,
@@ -3888,17 +3893,21 @@
 +  NULL,
 +  do_status,
 +  (cmdopt_t[2]){
-+    {'t', "to", {"jid", pos_status_jid, cmdarg_required, NULL, &cmdarg_type_fjid}},
++    { 't', "to",
++           { "jid", pos_status_jid, cmdarg_default, NULL, &cmdarg_type_fjid } },
++    {0}
 +  },
 +  (cmdarg_t[3]){
-+    {"status",  pos_status_status,  cmdarg_chreq, "show", &cmdarg_type_status_status, (gpointer)s2e_status2},
-+    {"message", pos_status_message, cmdarg_eol,   NULL,   &cmdarg_type_nonspace},
++    { "status",  pos_status_status,  cmdarg_chreq, "show",
++                 &cmdarg_type_status_status, (gpointer)s2e_status2 },
++    { "message", pos_status_message, cmdarg_eol,   NULL,
++                 &cmdarg_type_nonspace },
 +    {NULL}
 +  },
 +  NULL,
 +};
 +
-+static gchar *do_status (cmdopts_t *options, cmdarg_value_t *values)
++static gchar *do_status (const cmdopts_t *options, cmdarg_value_t *values)
  {
 -  if (!*arg) {
 +  if (values[pos_status_status].value.uint == imstatus_size) {
@@ -3926,7 +3935,7 @@
 +//  /status_to
 +//
 +
-+static gchar *do_status_to (cmdopts_t *command, cmdarg_value_t *values);
++static gchar *do_status_to (const cmdopts_t *command, cmdarg_value_t *values);
 +
 +typedef enum {
 +  pos_statusto_jid     = 0,
@@ -3964,7 +3973,7 @@
 +  NULL,
 +};
 +
-+static gchar *do_status_to (cmdopts_t *options, cmdarg_value_t *values)
++static gchar *do_status_to (const cmdopts_t *options, cmdarg_value_t *values)
  {
 -  char **paramlst;
 -  char *fjid, *st, *msg;
@@ -4013,19 +4022,13 @@
 -        *p = tolower(*p);
 -      fjid = jid_utf8 = to_utf8(fjid);
 -    }
--  } else {
--    // Add the current buddy
--    if (current_buddy)
--      fjid = (char*)buddy_getjid(BUDDATA(current_buddy));
--    if (!fjid)
--      scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
 +  // prevent default status message
 +  msg = msg ? msg : "";
 +
-+  scr_LogPrint(LPRINT_LOGNORM, 
-+               "Sending to <%s> /status %s %s", fjid, stname, msg);
++  scr_log_print (LPRINT_LOGNORM, 
++                 "Sending to <%s> /status %s %s", fjid, stname, msg);
 +  if (!xmpp_is_online())
-+    scr_LogPrint(LPRINT_NORMAL, "You are currently not connected...");
++    scr_log_print (LPRINT_NORMAL, "You are currently not connected...");
 +  xmpp_setstatus(st, fjid, msg, FALSE);
 +
 +  return NULL;
@@ -4035,7 +4038,7 @@
 +//  /add
 +//
 +
-+static gchar *do_add (cmdopts_t *command, cmdarg_value_t *values);
++static gchar *do_add (const cmdopts_t *command, cmdarg_value_t *values);
 +
 +typedef enum {
 +  pos_add_jid  = 0,
@@ -4049,14 +4052,14 @@
 +  do_add,
 +  NULL,
 +  (cmdarg_t[3]){
-+    {"jid",  pos_add_jid,  cmdarg_chreq,   ".",  &cmdarg_type_bjid},
-+    {"name", pos_add_name, cmdarg_default, NULL, &cmdarg_type_nonspace},
++    { "jid",  pos_add_jid,  cmdarg_chreq,   ".",  &cmdarg_type_bjid },
++    { "name", pos_add_name, cmdarg_default, NULL, &cmdarg_type_nonspace },
 +    {NULL}
 +  },
 +  NULL,
 +};
 +
-+static gchar *do_add (cmdopts_t *options, cmdarg_value_t *values)
++static gchar *do_add (const cmdopts_t *options, cmdarg_value_t *values)
 +{
 +  gchar *jid = values[pos_add_jid].value.arg;
 +
@@ -4064,8 +4067,8 @@
 +  //mc_strtolower(jid);
 +
 +  xmpp_addbuddy(jid, values[pos_add_name].value.arg, NULL);
-+  scr_LogPrint(LPRINT_LOGNORM, "Sent presence notification request to <%s>.",
-+               jid);
++  scr_log_print (LPRINT_LOGNORM, "Sent presence notification request to <%s>.",
++                 jid);
 +
 +  return NULL;
 +}
@@ -4074,7 +4077,7 @@
 +//  /del
 +//
 +
-+static gchar *do_del (cmdopts_t *command, cmdarg_value_t *values);
++static gchar *do_del (const cmdopts_t *command, cmdarg_value_t *values);
 +
 +typedef enum {
 +  pos_del_jid    = 0,
@@ -4087,17 +4090,19 @@
 +  cmd_check_online,
 +  do_del,
 +  (cmdopt_t[2]){
-+    {'n', "dryrun", {"dryrun", pos_del_dryrun, cmdarg_switch|cmdarg_check, NULL, NULL}},
++    { 'n', "dryrun",
++      { "dryrun", pos_del_dryrun, cmdarg_trigger, NULL, NULL } },
 +    {0}
 +  },
 +  (cmdarg_t[2]){
-+    {"jid", pos_del_jid, cmdarg_chreq, ".", &cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_GROUP)},
++    { "jid", pos_del_jid, cmdarg_chreq, ".", &cmdarg_type_roster_bjid,
++           (gpointer) (ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_GROUP) },
 +    {NULL}
 +  },
 +  NULL,
 +};
 +
-+static gchar *do_del (cmdopts_t *options, cmdarg_value_t *values)
++static gchar *do_del (const cmdopts_t *options, cmdarg_value_t *values)
 +{
 +  gpointer   buddy = values[pos_del_jid].value.rjid.bud;
 +  const char *jid  = buddy_getjid (buddy);
@@ -4105,11 +4110,19 @@
 +  if (buddy_gettype(buddy) & ROSTER_TYPE_ROOM)
 +    // This is a chatroom
 +    if (buddy_getinsideroom(buddy))
-+      return g_strdup ("You haven't left this room!");
-+
-+  scr_LogPrint(LPRINT_LOGNORM, "Removing <%s>...", jid);
-+
-+  if (!(values[pos_del_dryrun].value.swc)) {
++      return g_strdup_printf ("You have to leave room <%s> before deleting it!",
++                              jid);
++
++  scr_log_print (LPRINT_LOGNORM, "Removing <%s>...", jid);
++
++  if (values[pos_del_dryrun].value.swc) {
++    scr_log_print (LPRINT_LOGNORM, "... not really.");
+   } else {
+-    // Add the current buddy
+-    if (current_buddy)
+-      fjid = (char*)buddy_getjid(BUDDATA(current_buddy));
+-    if (!fjid)
+-      scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
 +    // Close the buffer
 +    scr_buffer_purge(1, jid);
 +
@@ -4300,7 +4313,7 @@
 -  free_arg_lst(paramlst);
  }
  
-+static gchar *do_group (cmdopts_t *command, cmdarg_value_t *values);
++static gchar *do_group (const cmdopts_t *command, cmdarg_value_t *values);
 +
 +typedef enum {
 +  pos_group_group  = 0,
@@ -4308,17 +4321,17 @@
 +} pos_group_t;
 +
 +static const string2enum_t s2e_group_scmd[] = {
-+  {"expand", scmd_group_unfold},
-+  {"unfold", scmd_group_unfold},
-+  {"shrink", scmd_group_fold  },
-+  {"fold",   scmd_group_fold  },
-+  {"toggle", scmd_group_toggle},
-+  {NULL,     0                },
++  { "expand", scmd_group_unfold },
++  { "unfold", scmd_group_unfold },
++  { "shrink", scmd_group_fold   },
++  { "fold",   scmd_group_fold   },
++  { "toggle", scmd_group_toggle },
++  { NULL,     0                 },
 +};
 +
 +#define SCMD_GROUP(NAME, REALNAME) \
 +    { #NAME, cmd_default, NULL, NULL, NULL, NULL, NULL, \
-+      (gpointer)scmd_group_##REALNAME}
++             (gpointer)scmd_group_##REALNAME }
 +static cmdopts_t def_group = {
 +  "group",
 +  cmd_default,
@@ -4326,15 +4339,16 @@
 +  do_group,
 +  NULL,
 +  (cmdarg_t[3]){
-+    {"subcommand", pos_group_action, cmdarg_chreq, NULL, &cmdarg_type_string2enum,
-+                                                  (gpointer)s2e_group_scmd},
-+    {"group", pos_group_group, cmdarg_chreq|cmdarg_eol, ".",  &cmdarg_type_roster_group},
++    { "subcommand", pos_group_action, cmdarg_chreq,              NULL,
++                    &cmdarg_type_string2enum, (gpointer)s2e_group_scmd },
++    { "group",      pos_group_group,  cmdarg_chreq | cmdarg_eol, ".",
++                    &cmdarg_type_roster_group },
 +    {NULL}
 +  },
 +  NULL,
 +};
 +
-+static gchar *do_group(cmdopts_t *options, cmdarg_value_t *values)
++static gchar *do_group(const cmdopts_t *options, cmdarg_value_t *values)
 +{
 +  //if (!current_buddy) // XXX do we need this still?
 +  //  return g_strdup("Command needs selected buddy.");
@@ -4349,13 +4363,55 @@
 +//  /say
 +//
 +
++// FIXME: remove excessive checks, simplify this all. Uses:
++// send_message_to():
++// - send_message()
++// - /msay send_to
++// - /say_to
++// - /room privmsg
++// send_message():
++// - say_cmd()
++// - /msay send
++// say_cmd():
++// - process_line()
++// - /say
++// Probably at least send_message can be removed, and /msay send can use
++// say_cmd().
++// 
++// say_cmd() does:
++// - scr_set_chatmode(TRUE);
++// - scr_show_buddy_window();
++// - check current buddy presence and type
++// - buddy_setflags(bud, ROSTER_FLAG_LOCK, TRUE);
++// send_message() does:
++// - check current buddy presence and jid availability (type check should ensure that, I think)
++// - determines active resource of current buddy
++// send_message_to() does:
++// - checks online
++// - checks jid presence
++// - checks message presence
++// - checks syntax of jid
++// - converts message type
++// - extracts bare jid (for hook)
++// - jumps to window if not quiet
++// - unsets resource (for hook)
++// - prepares message for hook
++// - sends message
++// - checks for encryption error
++// - calls hook
++// So, we can make 'activeresource' checker, that will eliminate most of the checks,
++// we can move online check to caller space, we can do chatmode things only when not
++// quiet. That essentially leaves only send_message_to. However that causes mcabber
++// not enter chat mode, when on wrong buddy (status/group).
++// Add '--to' and '--subject' to commands.
++
  static int send_message_to(const char *fjid, const char *msg, const char *subj,
 -                           LmMessageSubType type_overwrite, bool quiet)
 +                           msgtype_t msg_type, bool quiet)
  {
    char *bare_jid, *rp;
    char *hmsg;
-@@ -1285,6 +2000,7 @@
+@@ -1285,6 +2050,7 @@
    gint retval = 0;
    int isroom;
    gpointer xep184 = NULL;
@@ -4363,7 +4419,7 @@
  
    if (!xmpp_is_online()) {
      scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
-@@ -1299,11 +2015,15 @@
+@@ -1299,11 +2065,15 @@
      return 1;
    }
    if (check_jid_syntax((char*)fjid)) {
@@ -4381,7 +4437,7 @@
    // We must use the bare jid in hk_message_out()
    rp = strchr(fjid, JID_RESOURCE_SEPARATOR);
    if (rp)
-@@ -1354,8 +2074,7 @@
+@@ -1354,8 +2124,7 @@
  //  send_message(msg, subj, type_overwrite)
  // Write the message in the buddy's window and send the message on
  // the network.
@@ -4391,7 +4447,7 @@
  {
    const char *bjid;
    char *jid;
-@@ -1378,34 +2097,13 @@
+@@ -1378,34 +2147,13 @@
    else
      jid = g_strdup(bjid);
  
@@ -4428,7 +4484,7 @@
  
    scr_set_chatmode(TRUE);
    scr_show_buddy_window();
-@@ -1424,135 +2122,190 @@
+@@ -1424,135 +2172,195 @@
    }
  
    buddy_setflags(bud, ROSTER_FLAG_LOCK, TRUE);
@@ -4441,7 +4497,7 @@
  
 -static void do_say(char *arg) {
 -  say_cmd(arg, 1);
-+static gchar *do_say (cmdopts_t *command, cmdarg_value_t *values);
++static gchar *do_say (const cmdopts_t *command, cmdarg_value_t *values);
 +
 +typedef enum {
 +  pos_say_msg     = 0,
@@ -4454,19 +4510,23 @@
 +  NULL,
 +  do_say,
 +  (cmdopt_t[4]){
-+    {'n', "normal",   {"normal",   pos_say_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_normal}},
-+    {'h', "headline", {"headline", pos_say_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_headline}},
-+    {'d', "default",  {"default",  pos_say_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_not_set}},
++    { 'n', "normal",   { "normal",   pos_say_msgtype, cmdarg_switch, NULL, NULL,
++                                     NULL, (gpointer)msgtype_normal}},
++    { 'h', "headline", { "headline", pos_say_msgtype, cmdarg_switch, NULL, NULL,
++                                     NULL, (gpointer)msgtype_headline } },
++    { 'd', "default",  { "default",  pos_say_msgtype, cmdarg_switch, NULL, NULL,
++                                     NULL, (gpointer)msgtype_not_set } },
 +    {0}
 +  },
 +  (cmdarg_t[2]){
-+    {"message", pos_say_msg, cmdarg_eol | cmdarg_chreq, NULL, &cmdarg_type_nonspace},
++    { "message", pos_say_msg, cmdarg_eol | cmdarg_chreq, NULL,
++                                     &cmdarg_type_nonspace },
 +    {NULL}
 +  },
 +  NULL,
 +};
 +
-+static gchar *do_say (cmdopts_t *options, cmdarg_value_t *values)
++static gchar *do_say (const cmdopts_t *options, cmdarg_value_t *values)
 +{
 +  say_cmd(values[pos_say_msg].value.arg,
 +          (msgtype_t) (values[pos_say_msgtype].src -> userdata));
@@ -4478,7 +4538,7 @@
 +//  /msay
 +//
 +
-+static gchar *do_msay (cmdopts_t *command, cmdarg_value_t *values);
++static gchar *do_msay (const cmdopts_t *command, cmdarg_value_t *values);
 +
 +typedef enum {
 +  scmd_msay_begin, scmd_msay_verbatim,
@@ -4512,8 +4572,7 @@
 +      (cmdarg_t[2]){{"subject", pos_msay_subject, cmdarg_eol, NULL, &cmdarg_type_nonspace}, {NULL}},
 +      NULL, (gpointer)scmd_msay_verbatim },
 +    { "send", cmd_default, NULL, NULL,
-+      (cmdopt_t[5]){
-+        {'t', "to",       {"jid",      pos_msay_jid,     cmdarg_required, NULL, &cmdarg_type_fjid}},
++      (cmdopt_t[4]){
 +        {'n', "normal",   {"normal",   pos_msay_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_normal}},
 +        {'h', "headline", {"headline", pos_msay_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_headline}},
 +        {'d', "default",  {"default",  pos_msay_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_not_set}},
@@ -4535,7 +4594,7 @@
 +  },
 +};
 +
-+static gchar *do_msay (cmdopts_t *command, cmdarg_value_t *values)
++static gchar *do_msay (const cmdopts_t *command, cmdarg_value_t *values)
  {
 -  /* Parameters: begin verbatim abort send send_to */
 -  char **paramlst;
@@ -4552,9 +4611,8 @@
 -    scr_LogPrint(LPRINT_NORMAL, "(Use \"%s begin\" to enter "
 -                 "multi-line mode...)", mkcmdstr("msay"));
 -    goto do_msay_return;
-+  const char *msg;
-+
-+  subcmd = (scmd_msay_t) (values[pos_msay_scmd].src -> userdata);
++  const char  *msg;
++  scmd_msay_t subcmd = (scmd_msay_t) (values[pos_msay_scmd].src -> userdata);
 +
 +  if (subcmd == scmd_msay_toggle) {
 +    if (scr_get_multimode())
@@ -4709,11 +4767,14 @@
 +  return NULL;
  }
  
-+#if 0
++//
++//  /say_to
++//
++
  //  load_message_from_file(filename)
  // Read the whole content of a file.
  // The data are converted to UTF8, they should be freed by the caller after
-@@ -1566,7 +2319,7 @@
+@@ -1566,7 +2374,7 @@
    char *next_utf8_char;
    size_t len;
  
@@ -4722,9 +4783,45 @@
  
    if (!fd || fstat(fileno(fd), &buf)) {
      scr_LogPrint(LPRINT_LOGNORM, "Cannot open message file (%s)", filename);
-@@ -1634,130 +2387,103 @@
- 
- static void do_say_to(char *arg)
+@@ -1632,134 +2440,90 @@
+   return msgbuf_utf8;
+ }
+ 
+-static void do_say_to(char *arg)
++static gchar *do_say_to (const cmdopts_t *command, cmdarg_value_t *values);
++
++typedef enum {
++  pos_sayto_jid     = 0,
++  pos_sayto_msg     = 1,
++  pos_sayto_msgtype = 2,
++  pos_sayto_quiet   = 3,
++  pos_sayto_esc     = 4,
++  pos_sayto_file    = 5,
++} pos_sayto_t;
++
++cmdopts_t options = {
++  "say_to",
++  cmd_default,
++  cmd_check_online,
++  do_say_to,
++  (cmdopt_t[7]){
++    {'n', "normal",   {"normal",   pos_sayto_msgtype, cmdarg_switch,   NULL, NULL, NULL, (gpointer)msgtype_normal}},
++    {'h', "headline", {"headline", pos_sayto_msgtype, cmdarg_switch,   NULL, NULL, NULL, (gpointer)msgtype_headline}},
++    {'d', "default",  {"default",  pos_sayto_msgtype, cmdarg_switch,   NULL, NULL, NULL, (gpointer)msgtype_not_set}},
++    {'q', "quiet",    {"quiet",    pos_sayto_quiet,   cmdarg_trigger,  NULL, NULL}},
++    {'e', "escapes",  {"escapes",  pos_sayto_esc,     cmdarg_trigger,  NULL, NULL}},
++    {'f', "file",     {"filename", pos_sayto_file,    cmdarg_required, NULL, &cmdarg_type_filename}},
++    {0}
++  },
++  (cmdarg_t[3]){
++    {"jid",     pos_sayto_jid, cmdarg_chreq, ".",  &cmdarg_type_fjid},
++    {"message", pos_sayto_msg, cmdarg_eol,   NULL, &cmdarg_type_nonspace},
++    {NULL}
++  },
++  NULL,
++};
++
++static gchar *do_say_to (const cmdopts_t *command, cmdarg_value_t *values)
  {
 -  char **paramlst;
 -  char *fjid, *msg_utf8;
@@ -4735,41 +4832,19 @@
 -  LmMessageSubType msg_type = LM_MESSAGE_SUB_TYPE_NOT_SET;
 -  bool quiet = FALSE;
 -  bool eval = FALSE;
-+  cmdopts_t options = {
-+    "say_to",
-+    (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]){
-+      // jid
-+      { CMDOPT_REQUIRED,                              { .arg = NULL } },
-+      // message
-+      { CMDOPT_LAST | CMDOPT_PLAIN | CMDOPT_CATCHALL, { .arg = NULL } },
-+    },
-+    NULL,
-+  };
-+  char *fjid, *msg, *file;
-+  gchar *freeme  = NULL; // fjid
-+  gchar *freeme2 = NULL; // msg
-+  msgtype_t msg_type = msgtype_not_set;
- 
-   if (!xmpp_is_online()) {
-     scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
-     return;
-   }
- 
+-
+-  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);
-+  if (cmdopts_parse(arg, &options))
-     return;
+-    return;
 -  }
 -
 -  // Check for an option parameter
@@ -4811,36 +4886,29 @@
 -  fjid = *paramlst;
 -  msg = *(paramlst+1);
 -
-+
-+  if (options.opts[0].value.swc) // n
-+    msg_type = msgtype_normal;
-+  else if (options.opts[1].value.swc) // h
-+    msg_type = msgtype_headline;
-+
-+  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') {
+-  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);
+-    } 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);
+-      g_free(res_utf8);
 -    } else
 -      fjid = to_utf8(fjid);
 -  } else
 -    fjid = to_utf8(fjid);
 -
-+    }
-+  }
-+
-+  // ditto
++  char *fjid, *msg, *file;
++  gchar *freeme  = NULL; // fjid
++  gchar *freeme2 = NULL; // msg
++  msgtype_t msg_type = (msgtype_t) (values[pos_sayto_msgtype].src -> userdata);
++
++  fjid = values[pos_sayto_jid].value.arg;
++  msg  = values[pos_sayto_msg].value.arg;
++  file = values[pos_sayto_file].value.arg;
++
++  // XXX this is not yet in default fjid checker. should we add it there?
    if (!strchr(fjid, JID_DOMAIN_SEPARATOR)) {
      const gchar *append_server = settings_opt_get("default_server");
      if (append_server) {
@@ -4857,22 +4925,20 @@
      }
    }
  
-+  // as well
-   if (check_jid_syntax(fjid)) {
-     scr_LogPrint(LPRINT_NORMAL, "Please specify a valid Jabber ID.");
+-  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;
-   }
- 
+-    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) {
++    if (values[pos_sayto_esc].value.swc) {
 +      freeme2 = ut_unescape_tabs_cr(msg);
        // We must not free() if the original string was returned
 -      if (unescaped_msg == msg_utf8)
@@ -4884,14 +4950,14 @@
      }
 -    msg = (unescaped_msg ? unescaped_msg : msg_utf8);
    } else {
-     char *filename_xp;
+-    char *filename_xp;
      if (msg)
        scr_LogPrint(LPRINT_NORMAL, "say_to: extra parameter ignored.");
-     filename_xp = expand_filename(file);
+-    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(filename_xp);
 -    g_free(file);
++    freeme2 = msg = load_message_from_file(values[pos_sayto_file].value.arg);
    }
  
 -  send_message_to(fjid, msg, NULL, msg_type, quiet);
@@ -4901,15 +4967,19 @@
 -  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);
++  send_message_to(fjid, msg, NULL, msg_type, values[pos_sayto_quiet].value.swc);
++
 +  g_free(freeme);
 +  g_free(freeme2);
++
++  return NULL;
  }
  
++#if 0
  //  buffer_updown(updown, nblines)
-@@ -1775,27 +2501,10 @@
+ // updown: -1=up, +1=down
+ inline static void buffer_updown(int updown, char *nlines)
+@@ -1775,27 +2539,10 @@
      scr_buffer_scroll_up_down(updown, nblines);
  }
  
@@ -4937,7 +5007,7 @@
    t = from_iso8601(date, 0);
    if (t)
      scr_buffer_date(t);
-@@ -1804,98 +2513,156 @@
+@@ -1804,98 +2551,156 @@
                   "not correctly formatted or invalid.");
  }
  
@@ -5176,7 +5246,7 @@
  }
  
  static void do_info(char *arg)
-@@ -2033,29 +2800,20 @@
+@@ -2033,29 +2838,20 @@
    }
  }
  
@@ -5215,7 +5285,7 @@
  
    // Enter chat mode
    scr_set_chatmode(TRUE);
-@@ -2075,12 +2833,12 @@
+@@ -2075,12 +2871,12 @@
      rstatus = buddy_getstatus(bud, p_res->data);
      rst_msg = buddy_getstatusmsg(bud, p_res->data);
  
@@ -5230,7 +5300,7 @@
          enum imrole role = buddy_getrole(bud, p_res->data);
          enum imaffiliation affil = buddy_getaffil(bud, p_res->data);
          bool showaffil = (affil != affil_none);
-@@ -2096,12 +2854,12 @@
+@@ -2096,12 +2892,12 @@
        snprintf(buffer, 4095, "[%c] %s", imstatus2char[rstatus],
                 (char*)p_res->data);
        scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
@@ -5245,7 +5315,7 @@
          enum imrole role = buddy_getrole(bud, p_res->data);
          enum imaffiliation affil = buddy_getaffil(bud, p_res->data);
  
-@@ -2145,16 +2903,69 @@
+@@ -2145,16 +2941,69 @@
  
  static void do_rename(char *arg)
  {
@@ -5320,7 +5390,7 @@
    bjid   = buddy_getjid(bud);
    group  = buddy_getgroupname(bud);
    type   = buddy_gettype(bud);
-@@ -2162,11 +2973,13 @@
+@@ -2162,11 +3011,13 @@
  
    if (type & ROSTER_TYPE_SPECIAL) {
      scr_LogPrint(LPRINT_NORMAL, "You can't rename this item.");
@@ -5335,7 +5405,7 @@
      return;
    }
  
-@@ -2181,90 +2994,117 @@
+@@ -2181,90 +3032,117 @@
    //  }
    //}
  
@@ -5484,7 +5554,7 @@
      } else {
        // This is a local item, we move it without adding to roster.
        guint msgflag;
-@@ -2276,7 +3116,7 @@
+@@ -2276,7 +3154,7 @@
        msgflag = buddy_getflags(bud) & ROSTER_FLAG_MSG;
        if (msgflag)
          roster_msg_setflag(bjid, FALSE, FALSE);
@@ -5493,7 +5563,7 @@
        if (msgflag)
          roster_msg_setflag(bjid, FALSE, TRUE);
        if ((type & ROSTER_TYPE_ROOM) && xmpp_is_bookmarked(bjid) &&
-@@ -2285,8 +3125,7 @@
+@@ -2285,8 +3163,7 @@
      }
    }
  
@@ -5503,7 +5573,7 @@
    update_roster = TRUE;
  }
  
-@@ -2468,50 +3307,33 @@
+@@ -2468,50 +3345,33 @@
  
  static void do_rawxml(char *arg)
  {
@@ -5574,7 +5644,7 @@
  }
  
  //  check_room_subcommand(arg, param_needed, buddy_must_be_a_room)
-@@ -2815,6 +3637,8 @@
+@@ -2815,6 +3675,8 @@
    free_arg_lst(paramlst);
  }
  
@@ -5583,7 +5653,7 @@
  void cmd_room_leave(gpointer bud, char *arg)
  {
    gchar *roomid, *desc;
-@@ -2833,6 +3657,8 @@
+@@ -2833,6 +3695,8 @@
    g_free(roomid);
  }
  
@@ -5592,7 +5662,7 @@
  static void room_nick(gpointer bud, char *arg)
  {
    if (!buddy_getinsideroom(bud)) {
-@@ -2874,7 +3700,7 @@
+@@ -2874,7 +3738,7 @@
    fjid_utf8 = g_strdup_printf("%s/%s", buddy_getjid(bud), nick_utf8);
    g_free (nick_utf8);
    msg = to_utf8(arg);
@@ -5601,7 +5671,7 @@
    g_free(fjid_utf8);
    g_free(msg);
    free_arg_lst(paramlst);
-@@ -3052,6 +3878,8 @@
+@@ -3052,6 +3916,8 @@
    free_arg_lst(paramlst);
  }
  
@@ -5610,7 +5680,7 @@
  //  cmd_room_whois(..)
  // If interactive is TRUE, chatmode can be enabled.
  // Please note that usernick is expected in UTF-8 locale iff interactive is
-@@ -3146,6 +3974,8 @@
+@@ -3146,6 +4012,8 @@
      free_arg_lst(paramlst);
  }
  
@@ -5619,7 +5689,7 @@
  static void room_bookmark(gpointer bud, char *arg)
  {
    const char *roomid;
-@@ -3290,6 +4120,207 @@
+@@ -3290,6 +4158,207 @@
  
  static void do_room(char *arg)
  {
@@ -5827,7 +5897,7 @@
    char **paramlst;
    char *subcmd;
    gpointer bud;
-@@ -3347,7 +4378,7 @@
+@@ -3347,7 +4416,7 @@
        cmd_room_leave(bud, arg);
    } else if (!strcasecmp(subcmd, "names"))  {
      if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
@@ -5836,7 +5906,7 @@
    } else if (!strcasecmp(subcmd, "nick"))  {
      if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
        room_nick(bud, arg);
-@@ -4162,5 +5193,6 @@
+@@ -4162,5 +5231,6 @@
    }
    mcabber_set_terminate_ui();
  }
@@ -5845,8 +5915,8 @@
  /* vim: set expandtab cindent cinoptions=>2\:2(0 sw=2 ts=2:  For Vim users... */
 diff -r 1b0b563a81e6 mcabber/mcabber/commands.h
 --- a/mcabber/mcabber/commands.h	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/mcabber/commands.h	Fri Mar 22 01:56:17 2013 +0200
-@@ -5,32 +5,345 @@
++++ b/mcabber/mcabber/commands.h	Sat Mar 23 03:49:50 2013 +0200
+@@ -5,32 +5,346 @@
  
  #include <mcabber/config.h>
  
@@ -5954,10 +6024,10 @@
 +
 +// Command execution environment check function.
 +// Note: This is called before options are parsed, but values are already allocated.
-+typedef gchar *(*cmd_checker_t)(cmdopts_t *command, cmdarg_value_t *args);
++typedef gchar *(*cmd_checker_t)(const cmdopts_t *command, cmdarg_value_t *args);
 +// Command function itself.
 +// Command definition is provided for userdata access, should not be modified.
-+typedef gchar *(*cmd_handler_t)(cmdopts_t *command, cmdarg_value_t *args);
++typedef gchar *(*cmd_handler_t)(const cmdopts_t *command, cmdarg_value_t *args);
 +// Should check value -> value.arg and replace, if needed.
 +// Can set cmdarg_freeme flag to request type destructor call.
 +// Can access argument definition via value -> src (but not modify it).
@@ -5989,6 +6059,7 @@
 +  cmdarg_eol      = 0x0003, // catchall + plain
 +  cmdarg_chreq    = 0x000C, // check + required
 +  cmdarg_special  = 0x0030, // subcmd + switch
++  cmdarg_trigger  = 0x0024, // switch + check
 +} cmdarg_flags_t;
 +// argument value flags (internal)
 +typedef enum {
@@ -6033,20 +6104,20 @@
 +};
 +// argument value
 +struct cmdarg_value_struct {
-+  cmdarg_t       *src;           // source of value
++  const cmdarg_t *src;           // source of value
 +  cmdval_flags_t flags;          // visited, freeme
 +  union {                        // value:
-+    guint        uint;           // - unsigned integer
-+    gint         sint;           // - signed integer
-+    guint        swc;            // - switch count
-+    const gchar  *roarg;         // - XXX default value
-+    gchar        *arg;           // - string argument
-+    cmdopts_t    *cmd;           // - subcommand
++    guint           uint;        // - unsigned integer
++    gint            sint;        // - signed integer
++    guint           swc;         // - switch count
++    const gchar     *roarg;      // - XXX default value
++    gchar           *arg;        // - string argument
++    const cmdopts_t *cmd;        // - subcommand
 +    struct {                     // - roster jid:
-+      gpointer   bud;            //   - buddy struct
-+      gchar      *resource;      //   - resource (optional)
++      gpointer      bud;         //   - buddy struct
++      gchar         *resource;   //   - resource (optional)
 +    } rjid;                      // 
-+    gpointer     ptr;            // - anything else
++    gpointer        ptr;         // - anything else
 +  } value;                       //
 +};
 +
@@ -6105,7 +6176,7 @@
 +//
 +
 +// checks if connection is available
-+gchar *cmd_check_online (cmdopts_t *command, cmdarg_value_t *values);
++gchar *cmd_check_online (const cmdopts_t *command, cmdarg_value_t *values);
 +
 +//
 +//  Standard argument types
@@ -6177,23 +6248,23 @@
 +
 +#if 0
 +// return highest index for value, used in command
-+size_t cmdopts_count_values (cmdopts_t *command);
++size_t cmdopts_count_values (const cmdopts_t *command);
 +
 +// allocate values array to store arguments
-+cmdarg_value_t *cmdopts_allocate_values (cmdopts_t *command);
++cmdarg_value_t *cmdopts_allocate_values (const cmdopts_t *command);
 +
 +//  error cmdopts_parse_internal ( startptr, endptr, commanddef, values )
 +// Parses command arguments according to command definition.
 +// Parsed string MUST be writable. Regardless of success or error, input
 +// string should be considered corrupted by parsing process.
-+gchar *cmdopts_parse_internal(gchar **pr, gchar **er, cmdopts_t *command, cmdarg_value_t *values);
++gchar *cmdopts_parse_internal (gchar **pr, gchar **er, const cmdopts_t *command, cmdarg_value_t *values);
 +
 +// perform type checking/conversion on parsed values
-+gchar *cmdopts_check_values (cmdopts_t *command, cmdarg_value_t *values);
++gchar *cmdopts_check_values (const cmdopts_t *command, cmdarg_value_t *values);
 +
 +//  cmdopts_free_values ( commanddef, values )
 +// Free allocated by checkers resources and values array.
-+void cmdopts_free_values(cmdopts_t *command, cmdarg_value_t *values);
++void cmdopts_free_values (const cmdopts_t *command, cmdarg_value_t *values);
 +
 +typedef enum {
 +  msgtype_not_set,
@@ -6214,7 +6285,7 @@
  
 diff -r 1b0b563a81e6 mcabber/mcabber/hooks.c
 --- a/mcabber/mcabber/hooks.c	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/mcabber/hooks.c	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/mcabber/hooks.c	Sat Mar 23 03:49:50 2013 +0200
 @@ -638,10 +638,9 @@
  
    scr_LogPrint(LPRINT_LOGNORM, "Running hook-post-connect...");
@@ -6243,7 +6314,7 @@
  
 diff -r 1b0b563a81e6 mcabber/mcabber/roster.c
 --- a/mcabber/mcabber/roster.c	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/mcabber/roster.c	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/mcabber/roster.c	Sat Mar 23 03:49:50 2013 +0200
 @@ -1586,13 +1586,14 @@
  // Look for a buddy whose name or jid contains string.
  // Search begins at current_buddy; if no match is found in the the buddylist,
@@ -6284,7 +6355,7 @@
      }
 diff -r 1b0b563a81e6 mcabber/mcabber/screen.c
 --- a/mcabber/mcabber/screen.c	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/mcabber/screen.c	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/mcabber/screen.c	Sat Mar 23 03:49:50 2013 +0200
 @@ -3630,7 +3630,7 @@
  {
    scr_check_auto_away(TRUE);
@@ -6354,7 +6425,7 @@
    }
 diff -r 1b0b563a81e6 mcabber/mcabber/settings.c
 --- a/mcabber/mcabber/settings.c	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/mcabber/settings.c	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/mcabber/settings.c	Sat Mar 23 03:49:50 2013 +0200
 @@ -183,28 +183,12 @@
      if ((*line == '\n') || (*line == '\0') || (*line == '#'))
        continue;
@@ -6391,7 +6462,7 @@
    fclose(fp);
 diff -r 1b0b563a81e6 mcabber/mcabber/xmpp_iq.c
 --- a/mcabber/mcabber/xmpp_iq.c	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/mcabber/xmpp_iq.c	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/mcabber/xmpp_iq.c	Sat Mar 23 03:49:50 2013 +0200
 @@ -71,20 +71,20 @@
  struct adhoc_status {
    char *name;   // the name used by adhoc
@@ -6440,12 +6511,12 @@
                                                "Status has been changed");
 diff -r 1b0b563a81e6 mcabber/modules/beep/beep.c
 --- a/mcabber/modules/beep/beep.c	Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/modules/beep/beep.c	Fri Mar 22 01:56:17 2013 +0200
++++ b/mcabber/modules/beep/beep.c	Sat Mar 23 03:49:50 2013 +0200
 @@ -31,6 +31,7 @@
  
  static void beep_init   (void);
  static void beep_uninit (void);
-+static gchar *do_beep (cmdopts_t *command, cmdarg_value_t *values);
++static gchar *do_beep (const cmdopts_t *command, cmdarg_value_t *values);
  
  /* Module description */
  module_info_t info_beep = {
@@ -6494,7 +6565,7 @@
 +
  /* beep command handler */
 -static void do_beep(char *args)
-+static gchar *do_beep(cmdopts_t *command, cmdarg_value_t *values)
++static gchar *do_beep(const cmdopts_t *command, cmdarg_value_t *values)
  {
    /* Check arguments, and if recognized,
     * set mcabber option accordingly */
--- a/docs/cmdopts.mdwn	Fri Mar 22 02:09:13 2013 +0200
+++ b/docs/cmdopts.mdwn	Sat Mar 23 03:53:27 2013 +0200
@@ -16,12 +16,12 @@
  * Try to still be lightweight.
  * Try to still be readable.
 
-It is built around static structure, "command description". User can add or
-remove these structures to list of commands. FIXME more
+It is built around static structure, "command description".  User can add or
+remove these structures to list of commands.  *FIXME* more
 
 ## Command description struct, 'cmdopts_t'
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 typedef struct cmdopts_struct cmdopts_t;
 
@@ -42,52 +42,55 @@
     size_t              valno;
 };
 
-// -------------------------------------------------------------      """     ]]
+// --------------------------------------------------------------     """     ]]
 
 This struct describes command as a whole and links to argument descriptions.
 This struct is also used to describe individual subcommands, as they are quite
 similar to normal command, because they can have their own options, arguments
-and subcommands. The fields of this struct:
+and subcommands.  The fields of this struct:
 
  * 'name' - name of the command or subcommand.
 
  * 'flags' - currently there's only one flag:
 
     + 'cmd_safe' -  command is safe to execute in main mcabberrc during
-      initialization. Have no meaning for subcommands.
+      initialization.  Have no meaning for subcommands.
     + 'cmd_default' - default value of no flags enabled.
  
- * 'check' - execution environment checker for command. This callback is used to
-   do general checks before even parsing command line. You can write your own
-   checker or use standard ones, for example - 'cmd_check_online', that checks,
-   if you are currently online.
+ * 'check' - execution environment checker for command.  This callback is used
+   to do general checks before even parsing command line.  You can write your
+   own checker or use standard ones, for example - 'cmd_check_online', that
+   checks, if you are currently online.
 
- * 'handle' - command function. It is executed only if command line was
-   successfully parsed and argument values passed the type checking. Unused in
+ * 'handle' - command function.  It is executed only if command line was
+   successfully parsed and argument values passed the type checking.  Unused in
    subcommands.
 
  * 'opts' - pointer to the array of 'cmdopt_t' structs, describing command-line
-   options ("-f bar") and switches ("-x"), that this command accepts.
+   options ("-f bar") and switches ("-x"), that this command accepts.  Array
+   must end with option, that have 0 as short option character.
  
  * 'args' - similarly, pointer to the array of 'cmdarg_t' structs, that describe
-   command-line positional arguments (in order).
+   command-line positional arguments (in order).  Array must end with argument,
+   that have NULL name.
  
  * 'cmds' - pointer to the array of subcommands of this command (or subcommand).
-   How parser switches to subcommands we will describe later.
+   How parser switches to subcommands we will describe later.  Array must end
+   with subcommand, that have NULL name.
  
  * 'userdata' - arbitrary pointer, where you can put some data, that should
-   accompany this command or subcommand. Unused by parser.
+   accompany this command or subcommand.  Unused by parser.
 
  * 'valno' - this is internal value, that is initialized at command definition
-   time, you should not modify it. Currently unused in subcommands.
+   time, you should not modify it.  Currently unused in subcommands.
 
 ## Command function, 'cmd_handler_t'
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 typedef gchar *(*cmd_handler_t) (cmdopts_t *command, cmdarg_value_t *values);
 
-// -------------------------------------------------------------      """     ]]
+// --------------------------------------------------------------     """     ]]
 
 Command function is passed it's command definition struct (mainly to give it
 access to userdata) and dynamically allocated array of parsed argument values.
@@ -101,7 +104,7 @@
 
 ## Option description struct, 'cmdopt_t'
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 typedef struct {
     const char stortopt;
@@ -109,14 +112,14 @@
     cmdarg_t   arg;
 } cmdopt_t;
 
-// -------------------------------------------------------------      """     ]]
+// --------------------------------------------------------------     """     ]]
 
 This struct just adds short option character and long option name to generic
 argument struct, that we'll look at right now.
 
 ## Argument description struct, 'cmdarg_t'
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 typedef struct cmdarg_struct cmdarg_t;
 
@@ -131,6 +134,7 @@
     cmdarg_eol      = 0x0003, // catchall + plain
     cmdarg_chreq    = 0x000C, // check + required
     cmdarg_special  = 0x0030, // subcmd + switch
+    cmdarg_trigger  = 0x0024, // switch + check
 } cmdarg_flags_t;
 
 struct cmdarg_struct {
@@ -143,10 +147,10 @@
     gconstpointer        userdata;
 };
 
-// -------------------------------------------------------------      """     ]]
+// --------------------------------------------------------------     """     ]]
 
 This struct stores information about mapping between command-line entity
-(switch, option, argument, subcommand) and element in 'values' array. First,
+(switch, option, argument, subcommand) and element in 'values' array.  First,
 let's briefly describe fields, and then walk through their use in different
 entities.
 
@@ -178,7 +182,7 @@
  
  * 'defval' - default value for argument in "unchecked" form - i.e., in the form
    of string, as it appears on command line (we'll discuss type checkers and
-   what can they do to value later). Before parsing command line, parser will
+   what can they do to value later).  Before parsing command line, parser will
    assign this value to corresponding value structure.
 
  * 'type' - pointer to structure, describing argument type.
@@ -186,47 +190,47 @@
  * 'chkdata' - if type needs some additional info, it is a place to supply it.
 
  * 'userdata' - place for arbitrary info, that should accompany this argument or
-   option. Unused by parser.
+   option.  Unused by parser.
 
 Now, let's discuss general case - option with argument or positional argument.
 
 When parser encounters such argument, it checks 'catchall' and 'plain' flags and
 crops argument value from command line accordingly, then it assigns it to the
 'value.arg' field of 'cmdarg_value_t' struct in array 'values' with index, given
-in 'pos'. Also it marks such value as 'visited' and puts a link to argument
-description into value's 'src' field. More about effect of these actions later,
+in 'pos'.  Also it marks such value as 'visited' and puts a link to argument
+description into value's 'src' field.  More about effect of these actions later,
 in 'cmdarg_value_t' section.
 
 However, if argument struct is a part of option description struct, and have
-flag 'switch' set, parser will not try to parse value. Instead it will increase
-the count in 'value.swc' in corresponding 'cmdarg_value_t' struct. Argument name
-for switches is essentially ignored, but for safety sake it is recommended to
-duplicate switch long option name here. Flags 'catchall' and 'plain' obviously
-have no effect. Flag 'check' makes switch a trigger, that flips between 'on' and
-'off' for every occurence of flag on command line. Flags 'required' and 'subcmd'
-also have no effect for obvious reasons. Default value is ignored for switches,
-they always start with count 0 (off). Since switch is internal type, argument
-type field is ignored as well. Flags and source fields of value are updated as
-usual.
+flag 'switch' set, parser will not try to parse value.  Instead it will increase
+the count in 'value.swc' in corresponding 'cmdarg_value_t' struct.  Argument
+name for switches is essentially ignored, but for safety sake it is recommended
+to duplicate switch long option name here.  Flags 'catchall' and 'plain'
+obviously have no effect.  Flag 'check' makes switch a trigger, that flips
+between 'on' and 'off' for every occurence of flag on command line.  Flags
+'required' and 'subcmd' also have no effect for obvious reasons.  Default value
+is ignored for switches, they always start with count 0 (off).  Since switch is
+internal type, argument type field is ignored as well.  Flags and source fields
+of value are updated as usual.
 
 If flag 'subcmd' is set for positional argument, parser crops argument value
 according to flags as usual, but instead of assigning it, walks through list of
 subcommands in command description struct and compares obtained value to
-subcommand names. If it finds corresponding subcommand, it assigns pointer to
+subcommand names.  If it finds corresponding subcommand, it assigns pointer to
 subcommand description struct to 'value.cmd' field of corresponding
-'cmdarg_value_t' struct and updates it's source and flags. Then, instead of
+'cmdarg_value_t' struct and updates it's source and flags.  Then, instead of
 proceeding with parsing process, it recursively calls parser on remaining part
-of command line, passing subparser subcommand description. Note, that if
+of command line, passing subparser subcommand description.  Note, that if
 subcommand parser will end parsing before hitting end of command line, parser
-will proceed with parsing arguments for main command. Default value and argument
-type fields are ignored for subcommands.
+will proceed with parsing arguments for main command.  Default value and
+argument type fields are ignored for subcommands.
 
 Now let's take a look at value structure, that you'll be dealing with the most
 in the actual code.
 
 ## Argument value structure, 'cmdarg_value_t'
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 typedef struct cmdarg_value_struct cmdarg_value_t;
 
@@ -237,29 +241,29 @@
 } cmdval_flags_t;
 
 struct cmdarg_value_struct {
-    cmdarg_t       *src;
+    const cmdarg_t *src;
     cmdval_flags_t flags;
     union {
-        guint        uint;
-        gint         sint;
-        guint        swc;
-        const gchar  *roarg;
-        gchar        *arg;
-        cmdopts_t    *cmd;
+        guint           uint;
+        gint            sint;
+        guint           swc;
+        const gchar     *roarg;
+        gchar           *arg;
+        const cmdopts_t *cmd;
         struct {
-            gpointer   bud;
-            gchar      *resource;
+            gpointer    bud;
+            gchar       *resource;
         } rjid;
-        gpointer     ptr;
+        gpointer        ptr;
     } value;
 };
 
-// -------------------------------------------------------------      """     ]]
+// --------------------------------------------------------------     """     ]]
 
 Command may happen to be called recursively - i.e., something in command may
 cause the event, that will cause another call to the same command, thus we
 cannot store actual values in command/argument definition struct, and have to
-allocate dynamic memory for them. This struct is designed exactly for this.
+allocate dynamic memory for them.  This struct is designed exactly for this.
 Let's take a look at it's fields:
 
  * 'src' - this points to the argument description, from which this struct is
@@ -291,56 +295,57 @@
 
 Parser starts by allocating memory for values array, and then initializing it by
 walking through command description, looking at options and arguments and
-assigning default values to corresponding entries in array. It also puts pointer
-to the argument description into value's 'src' field. Thus, all used in command
-description values will have this field initialized, even if they were not
-specified on command line. This comes handly later, when checking for reqired
-value presence. For switches parser just sets the counter to zero. Note, that
-parser does not descend into subcommands at this stage. It does the same
-procedure for subcommand, but later, when it already knows which subcommand is
-selected. Also note, that if several arguments have the same value index, parser
-will use latest encountered one to initialize the value. This is used for
-default value in "argument clustering", that I'll show you later.
+assigning default values to corresponding entries in array.  It also puts
+pointer to the argument description into value's 'src' field.  Thus, all used in
+command description values will have this field initialized, even if they were
+not specified on command line.  This comes handly later, when checking for
+reqired value presence.  For switches parser just sets the counter to zero.
+Note, that parser does not descend into subcommands at this stage.  It does the
+same procedure for subcommand, but later, when it already knows which subcommand
+is selected.  Also note, that if several arguments have the same value index,
+parser will use latest encountered one to initialize the value.  This is used
+for default value in "argument clustering", that I'll show you later.
 
 Then parser calls command environment checker callback (if present), and if it
-returns error - terminates the process right now. Note, that subcommands can
+returns error - terminates the process right now.  Note, that subcommands can
 also have checkers.
 
-Next parser does its job of parsing command line. Each time it extracts argument
-value, it into 'value.arg' field of corresponding value entry and pointer to
-argument description struct into 'src' field. Also it sets 'visited' flag on
-value. At this stage value is still just unchecked string, except for special
-argument types. For switch occurence count in 'value.swc' gets increased each
-time argument was specified. Note however, that if several switches use the same
-value index ("clustered switches"), counter gets reset, when switches change one
-another in sequence - i.e. "-e -s -s -s" will count as three "-s", but "-s -s -e
--s" will count as only one "-s". For subcommands parser checks for corresponding
-subcommand in 'cmds' list, assigns it to 'value.cmd' and recursively passes the
-end of command line to be parsed with subcommand description. Note, that for
-subcommands parser does "checking on the spot" - if parsed argument value does
-not match any subcommand, and argument have 'required' flag set, it raises error
-immediately (if flag is not set, it merely assigns NULL and proceeds parsing
-according to current command description).
+Next parser does its job of parsing command line.  Each time it extracts
+argument value, it into 'value.arg' field of corresponding value entry and
+pointer to argument description struct into 'src' field.  Also it sets 'visited'
+flag on value.  At this stage value is still just unchecked string, except for
+special argument types.  For switch occurence count in 'value.swc' gets
+increased each time argument was specified.  Note however, that if several
+switches use the same value index ("clustered switches"), counter gets reset,
+when switches change one another in sequence - i.e. "-e -s -s -s" will count as
+three "-s", but "-s -s -e -s" will count as only one "-s".  For subcommands
+parser checks for corresponding subcommand in 'cmds' list, assigns it to
+'value.cmd' and recursively passes the end of command line to be parsed with
+subcommand description.  Note, that for subcommands parser does "checking on the
+spot" - if parsed argument value does not match any subcommand, and argument
+have 'required' flag set, it raises error immediately (if flag is not set, it
+merely assigns NULL and proceeds parsing according to current command
+description).
 
-Then parser walks through array of values and performs value checking. Note,
+Then parser walks through array of values and performs value checking.  Note,
 that all values, that need checking at this point should have 'src' field
 initialized - either set at default value assignment step, or during parsing,
-so, parser knows properties of value's argument. Parser only pays attention to
+so, parser knows properties of value's argument.  Parser only pays attention to
 the values, that either have 'visited' flag set (i.e. provided by user) or that
 have 'check' flag in argument description (useful for mandatory arguments or
-default values, that need convesion). If value corresponds to a switch, and
+default values, that need convesion).  If value corresponds to a switch, and
 argument have 'check' flag set, switch occurence count is replaced by remainder
-of division it by 2 (this way switch behaves like trigger). If it is a
+of division it by 2 (this way switch behaves like trigger).  If it is a
 subcommand, and it have 'required' flag set, parser checks, if it have non-NULL
-value. If it is usual argument (option or positional), and it does have 'type',
+value.  If it is usual argument (option or positional), and it does have 'type',
 that have 'check' callback set, parser calls this checker, passing it value
 structure (again, value structure contains pointer to argument description, so,
-checker can access 'chkdata' field, supplied by user). If checker returns error
-string and argument have 'required' flag set, parser raises error. If flag is
+checker can access 'chkdata' field, supplied by user).  If checker returns error
+string and argument have 'required' flag set, parser raises error.  If flag is
 not set, parser just prints warning and proceeds with checking.
 
 If checking was successful, parser calls command function, providing it with
-command description and values array. This function can also return error, but
+command description and values array.  This function can also return error, but
 at this stage it does not change process, only causes error message to be
 printed.
 
@@ -350,7 +355,7 @@
 
 ## Argument type, 'cmdarg_type_t'
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 typedef struct cmdarg_type_struct cmdarg_type_t;
 
@@ -365,7 +370,7 @@
     cmdarg_completor_t  complete;
 };
 
-// -------------------------------------------------------------      """     ]]
+// --------------------------------------------------------------     """     ]]
 
 As you can see, argument type is nothing more than a set of callbacks:
 
@@ -377,38 +382,38 @@
    should be set to corresponding function, and each time checker really needs
    value to be freed, it should set flag 'freeme' on value.
 
- * 'complete' - FIXME not yet designed callback, that will return list of
+ * 'complete' - *FIXME* not yet designed callback, that will return list of
    possible completions according to given prefix.
 
 After parsing command line parser performs argument value checking, that's where
-it calls 'check' callbacks.  Checker is given pointer to value structure, that
-it needs to check. Checker can modify value string (except when it is default
+it calls 'check' callbacks.   Checker is given pointer to value structure, that
+it needs to check.  Checker can modify value string (except when it is default
 value, but you have to supply your default values so, that they do not need
 modifying) or completely replace it with another string or even non-string
-object. If checker uses some resources (eg. allocates memory for replacement
+object.  If checker uses some resources (eg.  allocates memory for replacement
 value), it can set the flag 'freeme' on value to request call to value
-destructor, when values array will be freed. If checker needs some additional
+destructor, when values array will be freed.  If checker needs some additional
 data (eg. it is some generic checker, that needs list of valid values or other
-parameters), these data can be supplied in 'chkdata' field. Checker function
+parameters), these data can be supplied in 'chkdata' field.  Checker function
 should return NULL on success or error string, that will be g_free()'d by
-parser. Take note, that if argument does not have 'reqired' flag set, parser
+parser.  Take note, that if argument does not have 'reqired' flag set, parser
 will ignore checker error, so, it is recommended to nullify invalid value before
 returning error (but it is not required).
 
 # Examples
 
 When writing description for a command, first thing, you have to do - is to
-determine, which values your command can get from user. You don't have to be
+determine, which values your command can get from user.  You don't have to be
 shy - new interface is designed to encourage commands to be as flexible and
-option-rich as possible. 
+option-rich as possible.  
 
 Second - consider, which ones are to be specified as positional arguments, and
 which should become options or switches.
 
 Next you will want to decide, which checks and restrictions should you put on
-values. Essentially, determine value type.
+values.  Essentially, determine value type.
 
-And then you can begin writing command definition. So, let's start with
+And then you can begin writing command definition.  So, let's start with
 something simple.
 
 ## Single-argument no-checks command
@@ -420,10 +425,10 @@
 
 Definition for such command will look like:
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 // command function predeclaration
-gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values);
+gchar *do_ex1 (const cmdopts_t *command, cmdarg_value_t *values);
 
 // command arguments definition
 cmdopts_t def_ex1 = {
@@ -449,8 +454,8 @@
 };
 
 // Command function gets shown above command description (we don't need it) and
-// argument value list. Returns error message or NULL.
-gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values)
+// argument value list.  Returns error message or NULL.
+gchar *do_ex1 (const cmdopts_t *command, cmdarg_value_t *values)
 {
     gchar *message = values[0].value.arg;
     // now do something with message:
@@ -472,22 +477,22 @@
 cmd_undef (&def_ex1);
 ...
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 A lot of things to do to achieve a simple goal - does not look quite appealing
-so far. Still, let's tweak our example a bit.
+so far.  Still, let's tweak our example a bit.
 
 Remember the third step - decide, which checks should apply to our argument.
 Now, look at our command - we check, if message is NULL or if message is empty.
 But imagine, that user has given us a message " " - it's of no big use to us,
 so, probably, we should also strip leading/trailing spaces before doing the
-check. That's where argument types come into play. We can write argument
+check.  That's where argument types come into play.  We can write argument
 checker for that! But luckily, we already have built-in standard checker, that
-does exactly what we need - checks if string contains non-space characters. All
+does exactly what we need - checks if string contains non-space characters.  All
 we need to do - to specify '&cmdarg_type_nonspace' as argument type and remove
 our check inside of the command:
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 ...
 cmdopts_t def_ex1 = {
@@ -518,7 +523,7 @@
     NULL,
 };
 
-gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values)
+gchar *do_ex1 (const cmdopts_t *command, cmdarg_value_t *values)
 {
     scr_log_print (LPRINT_NORMAL, "Got the message: \"%s\".",
                    values[0].value.arg);
@@ -526,17 +531,17 @@
 }
 ...
 
-// -------------------------------------------------------------      """     ]]
+// --------------------------------------------------------------     """     ]]
 
-Ok, that's a little bit better. Now let's move on to something more complex.
+Ok, that's a little bit better.  Now let's move on to something more complex.
 
 ## Switches
 
 Let's add switches '-s' and '-l', that will define, where to print the message
-to - to log or to screen. For that we will need another two value indices - one
+to - to log or to screen.  For that we will need another two value indices - one
 for each switch.
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 ...
 cmdopts_t def_ex1 = {
@@ -570,7 +575,7 @@
     NULL,
 };
 
-gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values)
+gchar *do_ex1 (const cmdopts_t *command, cmdarg_value_t *values)
 {
     // default value
     guint whereto = LPRINT_NORMAL;
@@ -583,21 +588,21 @@
 }
 ...
 
-// -------------------------------------------------------------      """     ]]
+// --------------------------------------------------------------     """     ]]
 
 Ok, that works, but what if user have aliases, and wants last specified option
 to override the value? Currently, if -s was once specified, -l will not have any
-effect, regardless of count or position in command line. Not that good. Let's
-use the trick, that I call "argument clustering". We'll specify the same value
-index for both switches. Since 'value' struct have the pointer to the argument,
+effect, regardless of count or position in command line.  Not that good.  Let's
+use the trick, that I call "argument clustering".  We'll specify the same value
+index for both switches.  Since 'value' struct have the pointer to the argument,
 it was initialized from last time, we can recognize, which switch was used last.
 By default this pointer points to the last argument with this index in command
-definition - we can use that to specify default value. Now, to identify switches
-we can use argument names, but 'argument' struct contains userdata field, where
-we can put our LPRINT_* constants and just use it directly. So, with clustered
-switches, we will have:
+definition - we can use that to specify default value.  Now, to identify
+switches we can use argument names, but 'argument' struct contains userdata
+field, where we can put our LPRINT_* constants and just use it directly.  So,
+with clustered switches, we will have:
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 ...
 cmdopts_t def_ex1 = {
@@ -607,7 +612,7 @@
     do_ex1,
     (cmdopt_t[3]){
         // Set both argument indices to 1, specify our constants in userdata
-        // field. Screen is default value, thus, it goes last.
+        // field.  Screen is default value, thus, it goes last.
         { 'l', "log",    { "log",    1, cmdarg_switch, NULL, NULL, NULL,
                              (gpointer)LPRINT_LOG    } },
         { 's', "screen", { "screen", 1, cmdarg_switch, NULL, NULL, NULL,
@@ -622,7 +627,7 @@
     NULL,
 };
 
-gchar *do_ex1 (cmdopts_t *command, cmdarg_value_t *values)
+gchar *do_ex1 (const cmdopts_t *command, cmdarg_value_t *values)
 {
     scr_log_print ((guint)values[1].src -> userdata,
                    "Got the message: \"%s\".", values[0].value.arg);
@@ -630,9 +635,9 @@
 }
 ...
 
-// -------------------------------------------------------------      """     ]]
+// --------------------------------------------------------------     """     ]]
 
-That's much better. This trick may be quite useful not only with switches, but
+That's much better.  This trick may be quite useful not only with switches, but
 also with options, sometimes even clustering options with arguments can be
 handy.
 
@@ -642,33 +647,33 @@
 'check' and 'required' mostly only in combination with default value - otherwise
 it defeats the purpose - to be optional.
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 // TODO:
 //   example (not really used as of now - were too complex to deal using old
 //   interface).
 
-// -------------------------------------------------------------      """     ]]
+// --------------------------------------------------------------     """     ]]
 
 ## Subcommands
 
-Now, let's discuss another internal argument type - subcommand. Since
+Now, let's discuss another internal argument type - subcommand.  Since
 subcommands are quite common in mcabber, and since they have quite big impact on
 parsing process, they were made a part of parser.
 
-Currently, only positional arguments can be subcommands. You can have options or
+Currently, only positional arguments can be subcommands.  You can have options or
 other arguments precede them, though in practice there's no examples of that so
 far.
 
-So, to indicate, that argument is a subcommand, you just add flag 'subcmd'. When
-parser will encounter such argument, it will look up command structure with
+So, to indicate, that argument is a subcommand, you just add flag 'subcmd'.
+When parser will encounter such argument, it will look up command structure with
 specified name in the list 'cmds' of command definition and proceed parsing,
-using that command definition instead of main one. A good example of command
+using that command definition instead of main one.  A good example of command
 with several completely different subcommands would be '/color', so, let's look:
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
-static gchar *do_color (cmdopts_t *command, cmdarg_value_t *values);
+static gchar *do_color (const cmdopts_t *command, cmdarg_value_t *values);
 
 // We will put these values in subcommand definition 'userdata' fields
 // to simplify the task of determining, which subcommand was actually selected.
@@ -751,7 +756,7 @@
     },
 };
 
-static gchar *do_color (cmdopts_t *options, cmdarg_value_t *values)
+static gchar *do_color (const cmdopts_t *options, cmdarg_value_t *values)
 {
     scmd_color_t subcmd =
                   (scmd_color_t) (values[pos_color_scmd].value.cmd -> userdata);
@@ -784,7 +789,7 @@
     return NULL;
 }
 
-// -------------------------------------------------------------      """     ]]
+// --------------------------------------------------------------     """     ]]
 
 Here you also see a lot of new types:
 
@@ -810,7 +815,7 @@
 
 Let's take a look at simple checker, that we've encountered first - 'nonspace':
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 // Checker gets parsed value string in 'value.arg', argument description in
 // 'src' and returns error string or NULL.
@@ -859,11 +864,11 @@
     NULL,
 };
 
-// -------------------------------------------------------------      """     ]]
+// --------------------------------------------------------------     """     ]]
 
-Quite simple, I hope. Now, let's look at more complex type - 'fjid':
+Quite simple, I hope.  Now, let's look at more complex type - 'fjid':
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 // This checker checks syntax of fjid and expands "current-buddy" expressions
 // "." and "./resource".
@@ -923,13 +928,13 @@
     NULL,
 };
 
-// -------------------------------------------------------------      """     ]]
+// --------------------------------------------------------------     """     ]]
 
 If possible, you are encouraged to re-use existing checkers - for example, bjid
 checker uses fjid checker to expand "current-buddy" expressions and check
 syntax, and only strips resource afterwards:
 
-[[!format c """ // -------------------------------------------------------------
+[[!format c """// --------------------------------------------------------------
 
 gchar *cmdarg_check_bjid (cmdarg_value_t *arg)
 {
@@ -953,15 +958,15 @@
     NULL,
 };
 
-// -------------------------------------------------------------      """     ]]
+// --------------------------------------------------------------     """     ]]
 
-So far we've only modified string in value. But checkers are not limited to
+So far we've only modified string in value.  But checkers are not limited to
 this, for example, uint checker performs atoi() on value and assigns resulting
-number to value.uint. Take a look at definition of cmdarg_value_t struct - value
-is actually a union of different types of value. If you need something different
-from existing - you can always allocate your own struct and use value.ptr.
-However, if you think, that your case is generic enough - contact mcabber
-developers, we'll consider adding more variants there. Maybe we'll even add your
-argument type to built-in types.
+number to value.uint.  Take a look at definition of cmdarg_value_t struct -
+value is actually a union of different types of value.  If you need something
+different from existing - you can always allocate your own struct and use
+value.ptr.  However, if you think, that your case is generic enough - contact
+mcabber developers, we'll consider adding more variants there.  Maybe we'll even
+add your argument type to built-in types.
 
 <!-- vim: se ts=4 sw=4 et filetype=markdown tw=80: -->