Browse Source

hostname complition: refactoring: use GPtrArray.

Andrew Borodin 11 months ago
parent
commit
4929248f30
3 changed files with 106 additions and 45 deletions
  1. 75 0
      lib/glibcompat.c
  2. 5 0
      lib/glibcompat.h
  3. 26 45
      lib/widget/input_complete.c

+ 75 - 0
lib/glibcompat.c

@@ -44,12 +44,87 @@
 
 /*** file scope variables ************************************************************************/
 
+/* --------------------------------------------------------------------------------------------- */
 /*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+#if ! GLIB_CHECK_VERSION (2, 54, 0)
+/**
+ * g_direct_equal:
+ * @v1: (nullable): a key
+ * @v2: (nullable): a key to compare with @v1
+ *
+ * Compares two #gpointer arguments and returns %TRUE if they are equal.
+ * It can be passed to g_hash_table_new() as the @key_equal_func
+ * parameter, when using opaque pointers compared by pointer value as
+ * keys in a #GHashTable.
+ *
+ * This equality function is also appropriate for keys that are integers
+ * stored in pointers, such as `GINT_TO_POINTER (n)`.
+ *
+ * Returns: %TRUE if the two keys match.
+ */
+
+static gboolean
+g_direct_equal (gconstpointer v1, gconstpointer v2)
+{
+    return v1 == v2;
+}
+#endif /* ! GLIB_CHECK_VERSION (2, 54, 0) */
 
 /* --------------------------------------------------------------------------------------------- */
 /*** public functions ****************************************************************************/
 /* --------------------------------------------------------------------------------------------- */
 
+#if ! GLIB_CHECK_VERSION (2, 54, 0)
+/**
+ * g_ptr_array_find_with_equal_func: (skip)
+ * @haystack: pointer array to be searched
+ * @needle: pointer to look for
+ * @equal_func: (nullable): the function to call for each element, which should
+ *    return %TRUE when the desired element is found; or %NULL to use pointer
+ *    equality
+ * @index_: (optional) (out): return location for the index of
+ *    the element, if found
+ *
+ * Checks whether @needle exists in @haystack, using the given @equal_func.
+ * If the element is found, %TRUE is returned and the element^A^A^As index is
+ * returned in @index_ (if non-%NULL). Otherwise, %FALSE is returned and @index_
+ * is undefined. If @needle exists multiple times in @haystack, the index of
+ * the first instance is returned.
+ *
+ * @equal_func is called with the element from the array as its first parameter,
+ * and @needle as its second parameter. If @equal_func is %NULL, pointer
+ * equality is used.
+ *
+ * Returns: %TRUE if @needle is one of the elements of @haystack
+ * Since: 2.54
+ */
+gboolean
+g_ptr_array_find_with_equal_func (GPtrArray * haystack, gconstpointer needle, GEqualFunc equal_func,
+                                  guint * index_)
+{
+    guint i;
+
+    g_return_val_if_fail (haystack != NULL, FALSE);
+
+    if (equal_func == NULL)
+        equal_func = g_direct_equal;
+
+    for (i = 0; i < haystack->len; i++)
+        if (equal_func (g_ptr_array_index (haystack, i), needle))
+        {
+            if (index_ != NULL)
+                *index_ = i;
+            return TRUE;
+        }
+
+    return FALSE;
+}
+#endif /* ! GLIB_CHECK_VERSION (2, 54, 0) */
+
+/* --------------------------------------------------------------------------------------------- */
+
 #if ! GLIB_CHECK_VERSION (2, 63, 3)
 /**
  * g_clear_slist: (skip)

+ 5 - 0
lib/glibcompat.h

@@ -16,6 +16,11 @@
 
 /*** declarations of public functions ************************************************************/
 
+#if ! GLIB_CHECK_VERSION (2, 54, 0)
+gboolean g_ptr_array_find_with_equal_func (GPtrArray * haystack, gconstpointer needle,
+                                           GEqualFunc equal_func, guint * index_);
+#endif /* ! GLIB_CHECK_VERSION (2, 54, 0) */
+
 #if ! GLIB_CHECK_VERSION (2, 63, 3)
 void g_clear_slist (GSList ** slist_ptr, GDestroyNotify destroy);
 void g_clear_list (GList ** list_ptr, GDestroyNotify destroy);

+ 26 - 45
lib/widget/input_complete.c

@@ -93,10 +93,6 @@ void complete_engine_fill_completions (WInput * in);
 
 /*** file scope variables ************************************************************************/
 
-static char **hosts = NULL;
-static char **hosts_p = NULL;
-static int hosts_alloclen = 0;
-
 static WInput *input;
 static int min_end;
 static int start = 0;
@@ -394,8 +390,16 @@ variable_completion_function (const char *text, int state, input_complete_t flag
 
 /* --------------------------------------------------------------------------------------------- */
 
+static gboolean
+host_equal_func (gconstpointer a, gconstpointer b)
+{
+    return (strcmp ((const char *) a, (const char *) b) == 0);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
 static void
-fetch_hosts (const char *filename)
+fetch_hosts (const char *filename, GPtrArray * hosts)
 {
     FILE *file;
     char buffer[256];
@@ -433,7 +437,7 @@ fetch_hosts (const char *filename)
                 str_next_char (&t);
             *t = '\0';
 
-            fetch_hosts (includefile);
+            fetch_hosts (includefile, hosts);
             continue;
         }
 
@@ -455,32 +459,10 @@ fetch_hosts (const char *filename)
                 continue;
 
             name = g_strndup (lc_start, bi - lc_start);
-
-            {
-                char **host_p;
-                int j;
-
-                j = hosts_p - hosts;
-
-                if (j >= hosts_alloclen)
-                {
-                    hosts_alloclen += 30;
-                    hosts = g_renew (char *, hosts, hosts_alloclen + 1);
-                    hosts_p = hosts + j;
-                }
-
-                for (host_p = hosts; host_p < hosts_p; host_p++)
-                    if (strcmp (name, *host_p) == 0)
-                        break;  /* We do not want any duplicates */
-
-                if (host_p == hosts_p)
-                {
-                    *(hosts_p++) = name;
-                    *hosts_p = NULL;
-                }
-                else
-                    g_free (name);
-            }
+            if (!g_ptr_array_find_with_equal_func (hosts, name, host_equal_func, NULL))
+                g_ptr_array_add (hosts, name);
+            else
+                g_free (name);
         }
     }
 
@@ -492,7 +474,8 @@ fetch_hosts (const char *filename)
 static char *
 hostname_completion_function (const char *text, int state, input_complete_t flags)
 {
-    static char **host_p = NULL;
+    static GPtrArray *hosts = NULL;
+    static unsigned int host_p = 0;
     static size_t textstart = 0;
     static size_t textlen = 0;
 
@@ -503,29 +486,27 @@ hostname_completion_function (const char *text, int state, input_complete_t flag
     {                           /* Initialization stuff */
         const char *p;
 
-        g_strfreev (hosts);
-        hosts_alloclen = 30;
-        hosts = g_new (char *, hosts_alloclen + 1);
-        *hosts = NULL;
-        hosts_p = hosts;
+        if (hosts != NULL)
+            g_ptr_array_free (hosts, TRUE);
+        hosts = g_ptr_array_new_with_free_func (g_free);
         p = getenv ("HOSTFILE");
-        fetch_hosts (p != NULL ? p : "/etc/hosts");
-        host_p = hosts;
+        fetch_hosts (p != NULL ? p : "/etc/hosts", hosts);
+        host_p = 0;
         textstart = (*text == '@') ? 1 : 0;
         textlen = strlen (text + textstart);
     }
 
-    for (; *host_p != NULL; host_p++)
+    for (; host_p < hosts->len; host_p++)
     {
         if (textlen == 0)
             break;              /* Match all of them */
-        if (strncmp (text + textstart, *host_p, textlen) == 0)
+        if (strncmp (text + textstart, g_ptr_array_index (hosts, host_p), textlen) == 0)
             break;
     }
 
-    if (*host_p == NULL)
+    if (host_p == hosts->len)
     {
-        g_strfreev (hosts);
+        g_ptr_array_free (hosts, TRUE);
         hosts = NULL;
         return NULL;
     }
@@ -537,7 +518,7 @@ hostname_completion_function (const char *text, int state, input_complete_t flag
 
         if (textstart != 0)
             g_string_append_c (temp, '@');
-        g_string_append (temp, *host_p);
+        g_string_append (temp, g_ptr_array_index (hosts, host_p));
         host_p++;
 
         return g_string_free (temp, FALSE);