fixed failing to load argument to --uri
[uzbl-mobile] / uzbl.c
diff --git a/uzbl.c b/uzbl.c
index c029363..43178e9 100644 (file)
--- a/uzbl.c
+++ b/uzbl.c
@@ -69,6 +69,8 @@ const struct {
     { "status_top",         (void *)&uzbl.behave.status_top         },
     { "status_format",      (void *)&uzbl.behave.status_format      },
     { "status_background",  (void *)&uzbl.behave.status_background  },
+    { "title_format_long",  (void *)&uzbl.behave.title_format_long  },
+    { "title_format_short", (void *)&uzbl.behave.title_format_short },
     { "insert_mode",        (void *)&uzbl.behave.insert_mode        },
     { "always_insert_mode", (void *)&uzbl.behave.always_insert_mode },
     { "reset_command_mode", (void *)&uzbl.behave.reset_command_mode },
@@ -126,19 +128,15 @@ make_var_to_name_hash() {
 /* commandline arguments (set initial values for the state variables) */
 static GOptionEntry entries[] =
 {
-    { "uri",     'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,           "Uri to load", "URI" },
+    { "uri",     'u', 0, G_OPTION_ARG_STRING, &uzbl.state.uri,           "Uri to load at startup (equivalent to 'set uri = URI')", "URI" },
+    { "verbose", 'v', 0, G_OPTION_ARG_NONE,   &uzbl.state.verbose,       "Whether to print all messages or just errors.", NULL },
     { "name",    'n', 0, G_OPTION_ARG_STRING, &uzbl.state.instance_name, "Name of the current instance (defaults to Xorg window id)", "NAME" },
-    { "config",  'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,   "Config file", "FILE" },
+    { "config",  'c', 0, G_OPTION_ARG_STRING, &uzbl.state.config_file,   "Config file (this is pretty much equivalent to uzbl < FILE )", "FILE" },
     { NULL,      0, 0, 0, NULL, NULL, NULL }
 };
 
 typedef void (*Command)(WebKitWebView*, const char *);
 
-/* XDG stuff */
-static char *XDG_CONFIG_HOME_default[256];
-static char *XDG_CONFIG_DIRS_default = "/etc/xdg";
-
-
 /* --- UTILITY FUNCTIONS --- */
 
 char *
@@ -149,6 +147,18 @@ itos(int val) {
     return g_strdup(tmp);
 }
 
+static char *
+str_replace (const char* search, const char* replace, const char* string) {
+    gchar **buf;
+    char *ret;
+
+    buf = g_strsplit (string, search, -1);
+    ret = g_strjoinv (replace, buf);
+    g_strfreev(buf);
+
+    return ret;
+}
+
 static sigfunc*
 setup_signal(int signr, sigfunc *shandler) {
     struct sigaction nh, oh;
@@ -201,7 +211,8 @@ new_window_cb (WebKitWebView *web_view, WebKitWebFrame *frame, WebKitNetworkRequ
     (void) policy_decision;
     (void) user_data;
     const gchar* uri = webkit_network_request_get_uri (request);
-    printf("New window requested -> %s \n", uri);
+    if (uzbl.state.verbose)
+        printf("New window requested -> %s \n", uri);
     new_window_load_uri(uri);
     return (FALSE);
 }
@@ -212,10 +223,12 @@ create_web_view_cb (WebKitWebView  *web_view, WebKitWebFrame *frame, gpointer us
     (void) frame;
     (void) user_data;
     if (uzbl.state.selected_url[0]!=0) {
-        printf("\nNew web view -> %s\n",uzbl.state.selected_url);
+        if (uzbl.state.verbose)
+            printf("\nNew web view -> %s\n",uzbl.state.selected_url);
         new_window_load_uri(uzbl.state.selected_url);
     } else {
-        printf("New web view -> %s\n","Nothing to open, exiting");
+        if (uzbl.state.verbose)
+            printf("New web view -> %s\n","Nothing to open, exiting");
     }
     return (NULL);
 }
@@ -226,7 +239,8 @@ download_cb (WebKitWebView *web_view, GObject *download, gpointer user_data) {
     (void) user_data;
     if (uzbl.behave.download_handler) {
         const gchar* uri = webkit_download_get_uri ((WebKitDownload*)download);
-        printf("Download -> %s\n",uri);
+        if (uzbl.state.verbose)
+            printf("Download -> %s\n",uri);
         run_command(uzbl.behave.download_handler, uri, FALSE, NULL);
     }
     return (FALSE);
@@ -296,7 +310,7 @@ link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpoin
     (void) page;
     (void) title;
     (void) data;
-    //ADD HOVER URL TO WINDOW TITLE
+    //Set selected_url state variable
     uzbl.state.selected_url[0] = '\0';
     if (link) {
         strcpy (uzbl.state.selected_url, link);
@@ -404,7 +418,8 @@ static struct {char *name; Command command;} cmdlist[] =
     { "spawn",            spawn                   },
     { "sh",               spawn_sh                },
     { "exit",             close_uzbl              },
-    { "search",           search_text             },
+    { "search",           search_forward_text     },
+    { "search_reverse",   search_reverse_text     },
     { "insert_mode",      set_insert_mode         },
     { "runcmd",           runcmd                  }
 };
@@ -445,10 +460,10 @@ new_action(const gchar *name, const gchar *param) {
 
 static bool
 file_exists (const char * filename) {
-       return (access(filename, F_OK) == 0);
+    return (access(filename, F_OK) == 0);
 }
 
-void
+static void
 set_insert_mode(WebKitWebView *page, const gchar *param) {
     (void)page;
     (void)param;
@@ -463,7 +478,7 @@ load_uri (WebKitWebView * web_view, const gchar *param) {
         GString* newuri = g_string_new (param);
         if (g_strrstr (param, "://") == NULL)
             g_string_prepend (newuri, "http://");
-               /* if we do handle cookies, ask our handler for them */
+        /* if we do handle cookies, ask our handler for them */
         webkit_web_view_load_uri (web_view, newuri->str);
         g_string_free (newuri, TRUE);
     }
@@ -476,33 +491,45 @@ run_js (WebKitWebView * web_view, const gchar *param) {
 }
 
 static void
-search_text (WebKitWebView *page, const char *param) {
+search_text (WebKitWebView *page, const char *param, const gboolean forward) {
     if ((param) && (param[0] != '\0')) {
         strcpy(uzbl.state.searchtx, param);
     }
     if (uzbl.state.searchtx[0] != '\0') {
-        printf ("Searching: %s\n", uzbl.state.searchtx);
+        if (uzbl.state.verbose)
+            printf ("Searching: %s\n", uzbl.state.searchtx);
         webkit_web_view_unmark_text_matches (page);
         webkit_web_view_mark_text_matches (page, uzbl.state.searchtx, FALSE, 0);
         webkit_web_view_set_highlight_text_matches (page, TRUE);
-        webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, TRUE, TRUE);
+        webkit_web_view_search_text (page, uzbl.state.searchtx, FALSE, forward, TRUE);
     }
 }
 
 static void
+search_forward_text (WebKitWebView *page, const char *param) {
+    search_text(page, param, TRUE);
+}
+
+static void
+search_reverse_text (WebKitWebView *page, const char *param) {
+    search_text(page, param, FALSE);
+}
+
+static void
 new_window_load_uri (const gchar * uri) {
     GString* to_execute = g_string_new ("");
     g_string_append_printf (to_execute, "%s --uri '%s'", uzbl.state.executable_path, uri);
     int i;
     for (i = 0; entries[i].long_name != NULL; i++) {
-        if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0)) {
+        if ((entries[i].arg == G_OPTION_ARG_STRING) && (strcmp(entries[i].long_name,"uri")!=0) && (strcmp(entries[i].long_name,"name")!=0)) {
             gchar** str = (gchar**)entries[i].arg_data;
             if (*str!=NULL) {
                 g_string_append_printf (to_execute, " --%s '%s'", entries[i].long_name, *str);
             }
         }
     }
-    printf("\n%s\n", to_execute->str);
+    if (uzbl.state.verbose)
+        printf("\n%s\n", to_execute->str);
     g_spawn_command_line_async (to_execute->str, NULL);
     g_string_free (to_execute, TRUE);
 }
@@ -606,9 +633,11 @@ expand_template(const char *template) {
              sym = (int)g_scanner_cur_value(uzbl.scan).v_symbol;
              switch(sym) {
                  case SYM_URI:
-                     g_string_append(ret,
-                         uzbl.state.uri?
-                         g_markup_printf_escaped("%s", uzbl.state.uri):"");
+                     buf = uzbl.state.uri?
+                         g_markup_printf_escaped("%s", uzbl.state.uri) :
+                         g_strdup("");
+                     g_string_append(ret, buf);
+                     free(buf);
                      break;
                  case SYM_LOADPRGS:
                      buf = itos(uzbl.gui.sbar.load_progress);
@@ -621,10 +650,19 @@ expand_template(const char *template) {
                      g_free(buf);
                      break;
                  case SYM_TITLE:
-                     g_string_append(ret,
-                         uzbl.gui.main_title?
-                         g_markup_printf_escaped("%s", uzbl.gui.main_title):"");
+                     buf = uzbl.gui.main_title?
+                         g_markup_printf_escaped("%s", uzbl.gui.main_title) :
+                         g_strdup("");
+                     g_string_append(ret, buf);
+                     free(buf);
                      break;
+                 case SYM_SELECTED_URI:
+                     buf = uzbl.state.selected_url?
+                         g_markup_printf_escaped("%s", uzbl.state.selected_url) :
+                         g_strdup("");
+                     g_string_append(ret, buf);
+                     free(buf);
+                    break;
                  case SYM_NAME:
                      buf = itos(uzbl.xwin);
                      g_string_append(ret,
@@ -632,9 +670,11 @@ expand_template(const char *template) {
                      free(buf);
                      break;
                  case SYM_KEYCMD:
-                     g_string_append(ret,
-                         uzbl.state.keycmd->str ?
-                         g_markup_printf_escaped("%s", uzbl.state.keycmd->str):"");
+                     buf = uzbl.state.keycmd->str?
+                         g_markup_printf_escaped("%s", uzbl.state.keycmd->str) :
+                         g_strdup("");
+                     g_string_append(ret, buf);
+                     free(buf);
                      break;
                  case SYM_MODE:
                      g_string_append(ret,
@@ -708,31 +748,41 @@ expand_template(const char *template) {
 /* --End Statusbar functions-- */
 
 
-// make sure to put '' around args, so that if there is whitespace we can still keep arguments together.
+// make sure that the args string you pass can properly be interpreted (eg properly escaped against whitespace, quotes etc)
 static gboolean
 run_command (const char *command, const char *args, const gboolean sync, char **stdout) {
    //command <uzbl conf> <uzbl pid> <uzbl win id> <uzbl fifo file> <uzbl socket file> [args]
-    GString* to_execute = g_string_new ("");
+    GString *to_execute = g_string_new ("");
     GError *err = NULL;
-    gchar* cmd = g_strstrip(g_strdup(command));
+    gchar *cmd = g_strstrip(g_strdup(command));
+    gchar *qcfg = (uzbl.state.config_file ? g_shell_quote(uzbl.state.config_file) : g_strdup("''"));
+    gchar *qfifo = (uzbl.comm.fifo_path ? g_shell_quote(uzbl.comm.fifo_path) : g_strdup("''"));
+    gchar *qsock = (uzbl.comm.socket_path ? g_shell_quote(uzbl.comm.socket_path) : g_strdup("''"));
+    gchar *quri = (uzbl.state.uri ? g_shell_quote(uzbl.state.uri) : g_strdup("''"));
+    gchar *qtitle = (uzbl.gui.main_title ? g_shell_quote(uzbl.gui.main_title) : g_strdup("''"));
+
     gboolean result;
-    g_string_printf (to_execute, "%s '%s' '%i' '%i' '%s' '%s'",
-                     cmd, (uzbl.state.config_file ? uzbl.state.config_file : "(null)"),
-                     (int) getpid(), (int) uzbl.xwin, uzbl.comm.fifo_path,
-                     uzbl.comm.socket_path);
-    g_string_append_printf (to_execute, " '%s' '%s'",
-                    uzbl.state.uri, uzbl.gui.main_title);
+    g_string_printf (to_execute, "%s %s '%i' '%i' %s %s",
+                     cmd, qcfg, (int) getpid(), (int) uzbl.xwin, qfifo, qsock);
+    g_string_append_printf (to_execute, " %s %s", quri, qtitle);
     if(args) g_string_append_printf (to_execute, " %s", args);
 
     if (sync) {
         result = g_spawn_command_line_sync (to_execute->str, stdout, NULL, NULL, &err);
     } else result = g_spawn_command_line_async (to_execute->str, &err);
-    printf("Called %s.  Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
+    if (uzbl.state.verbose)
+        printf("Called %s.  Result: %s\n", to_execute->str, (result ? "TRUE" : "FALSE" ));
     g_string_free (to_execute, TRUE);
     if (err) {
         g_printerr("error on run_command: %s\n", err->message);
         g_error_free (err);
     }
+
+    g_free (qcfg);
+    g_free (qfifo);
+    g_free (qsock);
+    g_free (quri);
+    g_free (qtitle);
     g_free (cmd);
     return result;
 }
@@ -740,6 +790,20 @@ run_command (const char *command, const char *args, const gboolean sync, char **
 static void
 spawn(WebKitWebView *web_view, const char *param) {
     (void)web_view;
+/*
+   TODO: allow more control over argument order so that users can have some arguments before the default ones from run_command, and some after
+    gchar** cmd = g_strsplit(param, " ", 2);
+    gchar * args = NULL;
+    if (cmd[1]) {
+        args = g_shell_quote(cmd[1]);
+    }
+    if (cmd) {
+        run_command(cmd[0], args, FALSE, NULL);
+    }
+    if (args) {
+        g_free(args);
+    }
+*/
     run_command(param, NULL, FALSE, NULL);
 }
 
@@ -764,18 +828,16 @@ parse_command(const char *cmd, const char *param) {
 /* command parser */
 static void
 setup_regex() {
-    GError *err=NULL;
-
     uzbl.comm.get_regex  = g_regex_new("^[Gg][a-zA-Z]*\\s+([^ \\n]+)$",
-            G_REGEX_OPTIMIZE, 0, &err);
+            G_REGEX_OPTIMIZE, 0, NULL);
     uzbl.comm.set_regex  = g_regex_new("^[Ss][a-zA-Z]*\\s+([^ ]+)\\s*=\\s*([^\\n].*)$",
-            G_REGEX_OPTIMIZE, 0, &err);
+            G_REGEX_OPTIMIZE, 0, NULL);
     uzbl.comm.bind_regex = g_regex_new("^[Bb][a-zA-Z]*\\s+?(.*[^ ])\\s*?=\\s*([a-z][^\\n].+)$",
-            G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, &err);
+            G_REGEX_UNGREEDY|G_REGEX_OPTIMIZE, 0, NULL);
     uzbl.comm.act_regex = g_regex_new("^[Aa][a-zA-Z]*\\s+([^ \\n]+)\\s*([^\\n]*)?$",
-            G_REGEX_OPTIMIZE, 0, &err);
+            G_REGEX_OPTIMIZE, 0, NULL);
     uzbl.comm.keycmd_regex = g_regex_new("^[Kk][a-zA-Z]*\\s+([^\\n]+)$",
-            G_REGEX_OPTIMIZE, 0, &err);
+            G_REGEX_OPTIMIZE, 0, NULL);
 }
 
 static gboolean
@@ -783,8 +845,23 @@ get_var_value(gchar *name) {
     void **p = NULL;
 
     if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
-        if(var_is("status_format", name)
-           || var_is("useragent", name)) {
+        if(var_is("uri", name)
+           || var_is("status_message", name)
+           || var_is("status_format", name)
+           || var_is("status_background", name)
+           || var_is("title_format_short", name)
+           || var_is("title_format_long", name)
+           || var_is("modkey", name)
+           || var_is("load_finish_handler", name)
+           || var_is("history_handler", name)
+           || var_is("download_handler", name)
+           || var_is("cookie_handler", name)
+           || var_is("fifo_dir", name)
+           || var_is("socket_dir", name)
+           || var_is("shell_cmd", name)
+           || var_is("proxy_url", name)
+           || var_is("useragent", name))
+           {
             printf("VAR: %s VALUE: %s\n", name, (char *)*p);
         } else printf("VAR: %s VALUE: %d\n", name, (int)*p);
     }
@@ -840,11 +917,14 @@ static gboolean
 set_var_value(gchar *name, gchar *val) {
     void **p = NULL;
     char *endp = NULL;
+    char *buf=NULL;
 
     if( (p = g_hash_table_lookup(uzbl.comm.proto_var, name)) ) {
         if(var_is("status_message", name)
            || var_is("status_background", name)
            || var_is("status_format", name)
+           || var_is("title_format_long", name)
+           || var_is("title_format_short", name)
            || var_is("load_finish_handler", name)
            || var_is("history_handler", name)
            || var_is("download_handler", name)
@@ -866,11 +946,13 @@ set_var_value(gchar *name, gchar *val) {
         }
         else if(var_is("fifo_dir", name)) {
             if(*p) free(*p);
-            *p = init_fifo(g_strdup(val));
+            buf = init_fifo(val);
+            *p = buf?buf:g_strdup("");
         }
         else if(var_is("socket_dir", name)) {
             if(*p) free(*p);
-            *p = init_socket(g_strdup(val));
+            buf = init_socket(val);
+            *p = buf?buf:g_strdup("");
         }
         else if(var_is("modkey", name)) {
             if(*p) free(*p);
@@ -884,7 +966,8 @@ set_var_value(gchar *name, gchar *val) {
         }
         else if(var_is("useragent", name)) {
             if(*p) free(*p);
-            *p = set_useragent(g_strdup(val));
+            buf = set_useragent(val);
+            *p = buf?buf:g_strdup("");
         }
         else if(var_is("shell_cmd", name)) {
             if(*p) free(*p);
@@ -912,8 +995,6 @@ set_var_value(gchar *name, gchar *val) {
                              SOUP_SESSION_MAX_CONNS_PER_HOST, uzbl.net.max_conns_host, NULL);
             }
             else if (var_is("http_debug", name)) {
-                //soup_session_remove_feature
-                //    (uzbl.net.soup_session, uzbl.net.soup_logger);
                 soup_session_remove_feature
                     (uzbl.net.soup_session, SOUP_SESSION_FEATURE(uzbl.net.soup_logger));
                 /* do we leak if this doesn't get freed? why does it occasionally crash if freed? */
@@ -1034,7 +1115,8 @@ build_stream_name(int type, const gchar* dir) {
 
 static gboolean
 control_fifo(GIOChannel *gio, GIOCondition condition) {
-    printf("triggered\n");
+    if (uzbl.state.verbose)
+        printf("triggered\n");
     gchar *ctl_line;
     GIOStatus ret;
     GError *err = NULL;
@@ -1067,7 +1149,6 @@ init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
     }
 
     if (*dir == ' ') { /* space unsets the variable */
-        g_free(dir);
         return NULL;
     }
 
@@ -1081,7 +1162,8 @@ init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
             chan = g_io_channel_new_file(path, "r+", &error);
             if (chan) {
                 if (g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_fifo, NULL)) {
-                    printf ("init_fifo: created successfully as %s\n", path);
+                    if (uzbl.state.verbose)
+                        printf ("init_fifo: created successfully as %s\n", path);
                     uzbl.comm.fifo_path = path;
                     return dir;
                 } else g_warning ("init_fifo: could not add watch on %s\n", path);
@@ -1092,23 +1174,16 @@ init_fifo(gchar *dir) { /* return dir or, on error, free dir and return NULL */
     /* if we got this far, there was an error; cleanup */
     if (error) g_error_free (error);
     g_free(path);
-    g_free(dir);
     return NULL;
 }
 
 static gboolean
 control_stdin(GIOChannel *gio, GIOCondition condition) {
+    (void) condition;
     gchar *ctl_line = NULL;
-    gsize ctl_line_len = 0;
     GIOStatus ret;
-    GError *err = NULL;
 
-    if (condition & G_IO_HUP) {
-        ret = g_io_channel_shutdown (gio, FALSE, &err);
-        return FALSE;
-    }
-
-    ret = g_io_channel_read_line(gio, &ctl_line, &ctl_line_len, NULL, &err);
+    ret = g_io_channel_read_line(gio, &ctl_line, NULL, NULL, NULL);
     if ( (ret == G_IO_STATUS_ERROR) || (ret == G_IO_STATUS_EOF) )
         return FALSE;
 
@@ -1128,7 +1203,8 @@ create_stdin () {
         if (!g_io_add_watch(chan, G_IO_IN|G_IO_HUP, (GIOFunc) control_stdin, NULL)) {
             g_error ("Stdin: could not add watch\n");
         } else {
-            printf ("Stdin: watch added successfully\n");
+            if (uzbl.state.verbose)
+                printf ("Stdin: watch added successfully\n");
         }
     } else {
         g_error ("Stdin: Error while opening: %s\n", error->message);
@@ -1217,7 +1293,8 @@ init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL *
 
     len = strlen (local.sun_path) + sizeof (local.sun_family);
     if (bind (sock, (struct sockaddr *) &local, len) != -1) {
-        printf ("init_socket: opened in %s\n", path);
+        if (uzbl.state.verbose)
+            printf ("init_socket: opened in %s\n", path);
         listen (sock, 5);
 
         if( (chan = g_io_channel_unix_new(sock)) ) {
@@ -1233,60 +1310,40 @@ init_socket(gchar *dir) { /* return dir or, on error, free dir and return NULL *
     return NULL;
 }
 
+/*
+ NOTE: we want to keep variables like b->title_format_long in their "unprocessed" state
+ it will probably improve performance if we would "cache" the processed variant, but for now it works well enough...
+*/
+// this function may be called very early when the templates are not set (yet), hence the checks
 static void
 update_title (void) {
-    GString* string_long = g_string_new ("");
-    GString* string_short = g_string_new ("");
-    char* iname = NULL;
-    gchar *statln;
-    int iname_len;
-    State *s = &uzbl.state;
     Behaviour *b = &uzbl.behave;
-
-    if(s->instance_name) {
-            iname_len = strlen(s->instance_name)+4;
-            iname = malloc(iname_len);
-            snprintf(iname, iname_len, "<%s> ", s->instance_name);
-
-            g_string_prepend(string_long, iname);
-            g_string_prepend(string_short, iname);
-            free(iname);
-    }
-
-    g_string_append_printf(string_long, "%s ", s->keycmd->str);
-    if (!b->always_insert_mode)
-        g_string_append (string_long, (b->insert_mode ? "[I] " : "[C] "));
-    if (uzbl.gui.main_title) {
-        g_string_append (string_long, uzbl.gui.main_title);
-        g_string_append (string_short, uzbl.gui.main_title);
-    }
-    g_string_append (string_long, " - Uzbl browser");
-    g_string_append (string_short, " - Uzbl browser");
-    if (s->selected_url[0]!=0) {
-        g_string_append_printf (string_long, " -> (%s)", s->selected_url);
-    }
-
-    gchar* title_long = g_string_free (string_long, FALSE);
-    gchar* title_short = g_string_free (string_short, FALSE);
+    gchar *parsed;
 
     if (b->show_status) {
-        gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_short);
-        // TODO: we should probably not do this every time we want to update the title..?
-        statln = expand_template(uzbl.behave.status_format);
-        gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), statln);
+        if (b->title_format_short) {
+            parsed = expand_template(b->title_format_short);
+            gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
+            g_free(parsed);
+        }
+        if (b->status_format) {
+            parsed = expand_template(b->status_format);
+            gtk_label_set_markup(GTK_LABEL(uzbl.gui.mainbar_label), parsed);
+            g_free(parsed);
+        }
         if (b->status_background) {
             GdkColor color;
             gdk_color_parse (b->status_background, &color);
             //labels and hboxes do not draw their own background.  applying this on the window is ok as we the statusbar is the only affected widget.  (if not, we could also use GtkEventBox)
             gtk_widget_modify_bg (uzbl.gui.main_window, GTK_STATE_NORMAL, &color);
         }
-        g_free(statln);
     } else {
-        gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), title_long);
+        if (b->title_format_long) {
+            parsed = expand_template(b->title_format_long);
+            gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), parsed);
+            g_free(parsed);
+        }
     }
-
-    g_free (title_long);
-    g_free (title_short);
 }
 
 static gboolean
@@ -1407,7 +1464,6 @@ create_browser () {
     GUI *g = &uzbl.gui;
 
     GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
-    //main_window_ref = g_object_ref(scrolled_window);
     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
 
     g->web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
@@ -1433,9 +1489,6 @@ create_mainbar () {
 
     g->mainbar = gtk_hbox_new (FALSE, 0);
 
-    /* keep a reference to the bar so we can re-pack it at runtime*/
-    //sbar_ref = g_object_ref(g->mainbar);
-
     g->mainbar_label = gtk_label_new ("");
     gtk_label_set_selectable((GtkLabel *)g->mainbar_label, TRUE);
     gtk_label_set_ellipsize(GTK_LABEL(g->mainbar_label), PANGO_ELLIPSIZE_END);
@@ -1464,66 +1517,84 @@ add_binding (const gchar *key, const gchar *act) {
         return;
 
     //Debug:
-    printf ("Binding %-10s : %s\n", key, act);
-    action = new_action(parts[0], parts[1]);
+    if (uzbl.state.verbose)
+        printf ("Binding %-10s : %s\n", key, act);
 
-    if(g_hash_table_lookup(uzbl.bindings, key))
-        g_hash_table_remove(uzbl.bindings, key);
-    g_hash_table_insert(uzbl.bindings, g_strdup(key), action);
+    action = new_action(parts[0], parts[1]);
+    g_hash_table_replace(uzbl.bindings, g_strdup(key), action);
 
     g_strfreev(parts);
 }
 
+static gchar*
+get_xdg_var (XDG_Var xdg) {
+    const gchar* actual_value = getenv (xdg.environmental);
+    const gchar* home         = getenv ("HOME");
+
+    gchar* return_value = str_replace ("~", home, actual_value);
+
+    if (! actual_value || strcmp (actual_value, "") == 0) {
+        if (xdg.default_value) {
+            return_value = str_replace ("~", home, xdg.default_value);
+        } else {
+            return_value = NULL;
+        }
+    }
+    return return_value;
+}
+
+static gchar*
+find_xdg_file (int xdg_type, char* filename) {
+    /* xdg_type = 0 => config
+       xdg_type = 1 => data
+       xdg_type = 2 => cache*/
+
+    gchar* temporary_file   = malloc (1024);
+    gchar* temporary_string = NULL;
+    char*  saveptr;
+    char*  buf;
+
+    buf = get_xdg_var (XDG[xdg_type]);
+    strcpy (temporary_file, buf);
+    strcat (temporary_file, filename);
+    free(buf);
+
+    if (! file_exists (temporary_file) && xdg_type != 2) {
+        buf = get_xdg_var (XDG[3 + xdg_type]);
+        temporary_string = (char *) strtok_r (buf, ":", &saveptr);
+        free(buf);
+
+        while (temporary_string && ! file_exists (temporary_file)) {
+            strcpy (temporary_file, temporary_string);
+            strcat (temporary_file, filename);
+            temporary_string = (char * ) strtok_r (NULL, ":", &saveptr);
+        }
+    }
+
+    if (file_exists (temporary_file)) {
+        return temporary_file;
+    } else {
+        return NULL;
+    }
+}
+
 static void
 settings_init () {
-    char *saveptr;
     State *s = &uzbl.state;
     Network *n = &uzbl.net;
 
     uzbl.behave.reset_command_mode = 1;
 
     if (!s->config_file) {
-        const char* XDG_CONFIG_HOME = getenv ("XDG_CONFIG_HOME");
-        if (! XDG_CONFIG_HOME || ! strcmp (XDG_CONFIG_HOME, "")) {
-          XDG_CONFIG_HOME = (char*)XDG_CONFIG_HOME_default;
-        }
-        printf("XDG_CONFIG_HOME: %s\n", XDG_CONFIG_HOME);
-
-        strcpy (s->config_file_path, XDG_CONFIG_HOME);
-        strcat (s->config_file_path, "/uzbl/config");
-        if (file_exists (s->config_file_path)) {
-          printf ("Config file %s found.\n", s->config_file_path);
-          s->config_file = &s->config_file_path[0];
-        } else {
-            // Now we check $XDG_CONFIG_DIRS
-            char *XDG_CONFIG_DIRS = getenv ("XDG_CONFIG_DIRS");
-            if (! XDG_CONFIG_DIRS || ! strcmp (XDG_CONFIG_DIRS, ""))
-                XDG_CONFIG_DIRS = XDG_CONFIG_DIRS_default;
-
-            printf("XDG_CONFIG_DIRS: %s\n", XDG_CONFIG_DIRS);
-
-            char buffer[512];
-            strcpy (buffer, XDG_CONFIG_DIRS);
-            const gchar* dir = (char *) strtok_r (buffer, ":", &saveptr);
-            while (dir && ! file_exists (s->config_file_path)) {
-                strcpy (s->config_file_path, dir);
-                strcat (s->config_file_path, "/uzbl/config_file_pathig");
-                if (file_exists (s->config_file_path)) {
-                    printf ("Config file %s found.\n", s->config_file_path);
-                    s->config_file = &s->config_file_path[0];
-                }
-                dir = (char * ) strtok_r (NULL, ":", &saveptr);
-            }
-        }
+        s->config_file = find_xdg_file (0, "/uzbl/config");
     }
 
     if (s->config_file) {
         GIOChannel *chan = NULL;
-        GError *error = NULL;
         gchar *readbuf = NULL;
         gsize len;
 
-        chan = g_io_channel_new_file(s->config_file, "r", &error);
+        chan = g_io_channel_new_file(s->config_file, "r", NULL);
 
         if (chan) {
             while (g_io_channel_read_line(chan, &readbuf, &len, NULL, NULL)
@@ -1533,15 +1604,22 @@ settings_init () {
             }
 
             g_io_channel_unref (chan);
-            printf ("Config %s loaded\n", s->config_file);
+            if (uzbl.state.verbose)
+                printf ("Config %s loaded\n", s->config_file);
         } else {
             fprintf(stderr, "uzbl: error loading file%s\n", s->config_file);
         }
     } else {
-        printf ("No configuration file loaded.\n");
+        if (uzbl.state.verbose)
+            printf ("No configuration file loaded.\n");
     }
     if (!uzbl.behave.status_format)
-        uzbl.behave.status_format = g_strdup(STATUS_DEFAULT);
+        set_var_value("status_format", STATUS_DEFAULT);
+    if (!uzbl.behave.title_format_long)
+        set_var_value("title_format_long", TITLE_LONG_DEFAULT);
+    if (!uzbl.behave.title_format_short)
+        set_var_value("title_format_short", TITLE_SHORT_DEFAULT);
+
 
     g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
 }
@@ -1599,17 +1677,13 @@ main (int argc, char* argv[]) {
     if (!g_thread_supported ())
         g_thread_init (NULL);
 
-    printf("Uzbl start location: %s\n", argv[0]);
     strcpy(uzbl.state.executable_path,argv[0]);
 
-    strcat ((char *) XDG_CONFIG_HOME_default, getenv ("HOME"));
-    strcat ((char *) XDG_CONFIG_HOME_default, "/.config");
-
-    GError *error = NULL;
     GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
     g_option_context_add_main_entries (context, entries, NULL);
     g_option_context_add_group (context, gtk_get_option_group (TRUE));
-    g_option_context_parse (context, &argc, &argv, &error);
+    g_option_context_parse (context, &argc, &argv, NULL);
+    g_option_context_free(context);
     /* initialize hash table */
     uzbl.bindings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_action);
 
@@ -1642,14 +1716,17 @@ main (int argc, char* argv[]) {
     uzbl.gui.main_window = create_window ();
     gtk_container_add (GTK_CONTAINER (uzbl.gui.main_window), uzbl.gui.vbox);
 
-    load_uri (uzbl.gui.web_view, uzbl.state.uri); //TODO: is this needed?
 
     gtk_widget_grab_focus (GTK_WIDGET (uzbl.gui.web_view));
     gtk_widget_show_all (uzbl.gui.main_window);
     uzbl.xwin = GDK_WINDOW_XID (GTK_WIDGET (uzbl.gui.main_window)->window);
-    printf("window_id %i\n",(int) uzbl.xwin);
-    printf("pid %i\n", getpid ());
-    printf("name: %s\n", uzbl.state.instance_name);
+
+    if (uzbl.state.verbose) {
+        printf("Uzbl start location: %s\n", argv[0]);
+        printf("window_id %i\n",(int) uzbl.xwin);
+        printf("pid %i\n", getpid ());
+        printf("name: %s\n", uzbl.state.instance_name);
+    }
 
     uzbl.gui.scbar_v = (GtkScrollbar*) gtk_vscrollbar_new (NULL);
     uzbl.gui.bar_v = gtk_range_get_adjustment((GtkRange*) uzbl.gui.scbar_v);
@@ -1666,6 +1743,10 @@ main (int argc, char* argv[]) {
 
     create_stdin();
 
+    if(uzbl.state.uri)
+        load_uri (uzbl.gui.web_view, uzbl.state.uri);
+
+
     gtk_main ();
     clean_up();