--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dynamic-layout.diff Wed Aug 08 12:30:46 2012 +0300
@@ -0,0 +1,65 @@
+# HG changeset patch
+# Parent ebe29230ffb5572d2c37ab811d34ae970d6293ca
+[work-in-progress] Allow user to specify top to bottom window order
+
+diff -r ebe29230ffb5 mcabber/mcabber/utils.c
+--- a/mcabber/mcabber/utils.c Wed Aug 01 23:44:09 2012 +0300
++++ b/mcabber/mcabber/utils.c Fri Aug 03 14:35:36 2012 +0300
+@@ -650,6 +650,42 @@
+ g_free(arglst);
+ }
+
++// parse_list(arg, cb, udata)
++// Calls cb for every element in space/semicolon/comma-separated list.
++// Designed to work in-place, so, no escapes, quoting etc.
++// Terminates parsing if callback returns false.
++void parse_list(const char *arg, parse_list_cb_t cb, void *udata)
++{
++ const char *p, *start;
++ enum {
++ in_space,
++ in_string,
++ } state;
++
++ if (!arg)
++ return;
++
++ state = in_space;
++ while ( *p ) {
++ if ( *p == ' ' || *p == ';' || *p == ',' ) {
++ if ( state == in_string ) {
++ if ( ! cb ( start, p, udata ) )
++ return;
++ state = in_space;
++ }
++ } else {
++ if ( state == in_space ) {
++ start = p;
++ state = in_string;
++ }
++ }
++ p ++;
++ }
++
++ if ( state == in_string )
++ cb ( start, p, udata );
++}
++
+ // replace_nl_with_dots(bufstr)
+ // Replace '\n' with "(...)" (or with a NUL if the string is too short)
+ void replace_nl_with_dots(char *bufstr)
+diff -r ebe29230ffb5 mcabber/mcabber/utils.h
+--- a/mcabber/mcabber/utils.h Wed Aug 01 23:44:09 2012 +0300
++++ b/mcabber/mcabber/utils.h Fri Aug 03 14:35:36 2012 +0300
+@@ -43,6 +43,11 @@
+ char **split_arg(const char *arg, unsigned int n, int dontstriplast);
+ void free_arg_lst(char **arglst);
+
++/* fast in-place string split on space/semicolon/comma
++ * stops processing if callback returns false value */
++typedef int (*parse_list_cb_t)(const char *start, const char *end, void *udata);
++void parse_list(const char *arg, parse_list_cb_t cb, void *udata);
++
+ void replace_nl_with_dots(char *bufstr);
+ char *ut_expand_tabs(const char *text);
+