fixed failing to load argument to --uri
[uzbl-mobile] / uzbl.c
diff --git a/uzbl.c b/uzbl.c
index ea60fb1..43178e9 100644 (file)
--- a/uzbl.c
+++ b/uzbl.c
@@ -129,7 +129,7 @@ make_var_to_name_hash() {
 static GOptionEntry entries[] =
 {
     { "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.", "VERBOSE" },
+    { "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 (this is pretty much equivalent to uzbl < FILE )", "FILE" },
     { NULL,      0, 0, 0, NULL, NULL, NULL }
@@ -149,7 +149,14 @@ itos(int val) {
 
 static char *
 str_replace (const char* search, const char* replace, const char* string) {
-    return g_strjoinv (replace, g_strsplit (string, search, -1));
+    gchar **buf;
+    char *ret;
+
+    buf = g_strsplit (string, search, -1);
+    ret = g_strjoinv (replace, buf);
+    g_strfreev(buf);
+
+    return ret;
 }
 
 static sigfunc*
@@ -411,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                  }
 };
@@ -452,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;
@@ -470,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);
     }
@@ -483,7 +491,7 @@ 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);
     }
@@ -493,17 +501,27 @@ search_text (WebKitWebView *page, const char *param) {
         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);
@@ -615,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);
@@ -630,14 +650,18 @@ 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:
-                     g_string_append(ret,
-                         uzbl.state.selected_url?
-                         g_markup_printf_escaped("%s", uzbl.state.selected_url):"");
+                     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);
@@ -646,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,
@@ -764,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);
 }
 
@@ -805,10 +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("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);
     }
@@ -864,6 +917,7 @@ 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)
@@ -892,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);
@@ -910,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);
@@ -938,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? */
@@ -1094,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;
     }
 
@@ -1120,22 +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;
 
-    if (condition & G_IO_HUP) {
-        ret = g_io_channel_shutdown (gio, FALSE, NULL);
-        return FALSE;
-    }
-
-    ret = g_io_channel_read_line(gio, &ctl_line, &ctl_line_len, NULL, NULL);
+    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;
 
@@ -1262,25 +1310,39 @@ 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) {
     Behaviour *b = &uzbl.behave;
+    gchar *parsed;
 
     if (b->show_status) {
-        gchar *statln;
-        gtk_window_set_title (GTK_WINDOW(uzbl.gui.main_window), expand_template(b->title_format_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), expand_template(b->title_format_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);
+        }
     }
 }
 
@@ -1402,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 ());
@@ -1428,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);
@@ -1461,11 +1519,9 @@ add_binding (const gchar *key, const gchar *act) {
     //Debug:
     if (uzbl.state.verbose)
         printf ("Binding %-10s : %s\n", key, act);
-    action = new_action(parts[0], parts[1]);
 
-    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);
 }
@@ -1475,16 +1531,15 @@ get_xdg_var (XDG_Var xdg) {
     const gchar* actual_value = getenv (xdg.environmental);
     const gchar* home         = getenv ("HOME");
 
-    gchar* return_value = str_replace ("~", home, g_strdup (actual_value));
+    gchar* return_value = str_replace ("~", home, actual_value);
 
     if (! actual_value || strcmp (actual_value, "") == 0) {
         if (xdg.default_value) {
-            return_value = str_replace ("~", home, g_strdup (xdg.default_value));
+            return_value = str_replace ("~", home, xdg.default_value);
         } else {
             return_value = NULL;
         }
     }
-
     return return_value;
 }
 
@@ -1494,33 +1549,21 @@ find_xdg_file (int xdg_type, char* filename) {
        xdg_type = 1 => data
        xdg_type = 2 => cache*/
 
-    gchar* xdg_config_home  = get_xdg_var (XDG[0]);
-    gchar* xdg_data_home    = get_xdg_var (XDG[1]);
-    gchar* xdg_cache_home   = get_xdg_var (XDG[2]);
-    gchar* xdg_config_dirs  = get_xdg_var (XDG[3]);
-    gchar* xdg_data_dirs    = get_xdg_var (XDG[4]);
-    gchar* temporary_file   = (char *)malloc (1024);
+    gchar* temporary_file   = malloc (1024);
     gchar* temporary_string = NULL;
     char*  saveptr;
+    char*  buf;
 
-    if (xdg_type == 0)
-        strcpy (temporary_file, xdg_config_home);
-
-    if (xdg_type == 1)
-        strcpy (temporary_file, xdg_data_home);
-
-    if (xdg_type == 2)
-        strcpy (temporary_file, xdg_cache_home);
-
+    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) {
-        if (xdg_type == 0)
-            temporary_string = (char *) strtok_r (xdg_config_dirs, ":", &saveptr);
-        
-        if (xdg_type == 1)
-            temporary_string = (char *) strtok_r (xdg_data_dirs, ":", &saveptr);
-        
+        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);
@@ -1543,7 +1586,7 @@ settings_init () {
     uzbl.behave.reset_command_mode = 1;
 
     if (!s->config_file) {
-        s->config_file = g_strdup (find_xdg_file (0, "/uzbl/config"));
+        s->config_file = find_xdg_file (0, "/uzbl/config");
     }
 
     if (s->config_file) {
@@ -1571,11 +1614,11 @@ settings_init () {
             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)
-        uzbl.behave.title_format_long = g_strdup(TITLE_LONG_DEFAULT);
+        set_var_value("title_format_long", TITLE_LONG_DEFAULT);
     if (!uzbl.behave.title_format_short)
-        uzbl.behave.title_format_short = g_strdup(TITLE_SHORT_DEFAULT);
+        set_var_value("title_format_short", TITLE_SHORT_DEFAULT);
 
 
     g_signal_connect(n->soup_session, "request-queued", G_CALLBACK(handle_cookies), NULL);
@@ -1640,6 +1683,7 @@ main (int argc, char* argv[]) {
     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, 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);
 
@@ -1672,7 +1716,6 @@ 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);
@@ -1700,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();