(root)/
glib-2.79.0/
glib/
deprecated/
gcompletion.c
       1  /* GLIB - Library of useful routines for C programming
       2   * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
       3   *
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
      14   * Lesser General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Lesser General Public
      17   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   */
      19  
      20  /*
      21   * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
      22   * file for a list of people on the GLib Team.  See the ChangeLog
      23   * files for a list of changes.  These files are distributed with
      24   * GLib at ftp://ftp.gtk.org/pub/gtk/. 
      25   */
      26  
      27  /* 
      28   * MT safe
      29   */
      30  
      31  #include "config.h"
      32  
      33  /* we know we are deprecated here, no need for warnings */
      34  #ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
      35  #define GLIB_DISABLE_DEPRECATION_WARNINGS
      36  #endif
      37  
      38  #include "gcompletion.h"
      39  
      40  #include <glib/gstrfuncs.h>
      41  #include <glib/gmessages.h>
      42  #include <glib/gunicode.h>
      43  
      44  #include <string.h>
      45  
      46  /**
      47   * GCompletion:
      48   * @items: list of target items (strings or data structures).
      49   * @func: function which is called to get the string associated with a
      50   *        target item. It is %NULL if the target items are strings.
      51   * @prefix: the last prefix passed to g_completion_complete() or
      52   *          g_completion_complete_utf8().
      53   * @cache: the list of items which begin with @prefix.
      54   * @strncmp_func: The function to use when comparing strings.  Use
      55   *                g_completion_set_compare() to modify this function.
      56   *
      57   * `GCompletion` provides support for automatic completion of a string
      58   * using any group of target strings. It is typically used for file
      59   * name completion as is common in many UNIX shells.
      60   *
      61   * A `GCompletion` is created using [func@GLib.Completion.new]. Target items are
      62   * added and removed with [method@GLib.Completion.add_items],
      63   * [method@GLib.Completion.remove_items] and
      64   * [method@GLib.Completion.clear_items]. A completion attempt is requested with
      65   * [method@GLib.Completion.complete] or [method@GLib.Completion.complete_utf8].
      66   * When no longer needed, the `GCompletion` is freed with
      67   * [method@GLib.Completion.free].
      68   *
      69   * Items in the completion can be simple strings (e.g. filenames), or
      70   * pointers to arbitrary data structures. If data structures are used
      71   * you must provide a [type@GLib.CompletionFunc] in [func@GLib.Completion.new],
      72   * which retrieves the item’s string from the data structure. You can change
      73   * the way in which strings are compared by setting a different
      74   * [type@GLib.CompletionStrncmpFunc] in [method@GLib.Completion.set_compare].
      75   *
      76   * `GCompletion` has been marked as deprecated, since this API is rarely
      77   * used and not very actively maintained.
      78   *
      79   * Deprecated: 2.26: Rarely used API
      80   **/
      81  
      82  /**
      83   * GCompletionFunc:
      84   * @item: the completion item.
      85   *
      86   * Specifies the type of the function passed to g_completion_new(). It
      87   * should return the string corresponding to the given target item.
      88   * This is used when you use data structures as #GCompletion items.
      89   *
      90   * Returns: the string corresponding to the item.
      91   * Deprecated: 2.26: Rarely used API
      92   **/
      93  
      94  /**
      95   * GCompletionStrncmpFunc:
      96   * @s1: string to compare with @s2.
      97   * @s2: string to compare with @s1.
      98   * @n: maximal number of bytes to compare.
      99   *
     100   * Specifies the type of the function passed to
     101   * g_completion_set_compare(). This is used when you use strings as
     102   * #GCompletion items.
     103   *
     104   * Returns: an integer less than, equal to, or greater than zero if
     105   *          the first @n bytes of @s1 is found, respectively, to be
     106   *          less than, to match, or to be greater than the first @n
     107   *          bytes of @s2.
     108   * Deprecated: 2.26: Rarely used API
     109   **/
     110  
     111  static void completion_check_cache (GCompletion* cmp,
     112  				    gchar**	 new_prefix);
     113  
     114  /**
     115   * g_completion_new:
     116   * @func: the function to be called to return the string representing
     117   *        an item in the #GCompletion, or %NULL if strings are going to
     118   *        be used as the #GCompletion items.
     119   *
     120   * Creates a new #GCompletion.
     121   *
     122   * Returns: the new #GCompletion.
     123   * Deprecated: 2.26: Rarely used API
     124   **/
     125  GCompletion* 
     126  g_completion_new (GCompletionFunc func)
     127  {
     128    GCompletion* gcomp;
     129    
     130    gcomp = g_new (GCompletion, 1);
     131    gcomp->items = NULL;
     132    gcomp->cache = NULL;
     133    gcomp->prefix = NULL;
     134    gcomp->func = func;
     135    gcomp->strncmp_func = strncmp;
     136  
     137    return gcomp;
     138  }
     139  
     140  /**
     141   * g_completion_add_items:
     142   * @cmp: the #GCompletion.
     143   * @items: (transfer none): the list of items to add.
     144   *
     145   * Adds items to the #GCompletion.
     146   *
     147   * Deprecated: 2.26: Rarely used API
     148   **/
     149  void 
     150  g_completion_add_items (GCompletion* cmp,
     151  			GList*	     items)
     152  {
     153    GList* it;
     154    
     155    g_return_if_fail (cmp != NULL);
     156    
     157    /* optimize adding to cache? */
     158    if (cmp->cache)
     159      {
     160        g_list_free (cmp->cache);
     161        cmp->cache = NULL;
     162      }
     163  
     164    if (cmp->prefix)
     165      {
     166        g_free (cmp->prefix);
     167        cmp->prefix = NULL;
     168      }
     169    
     170    it = items;
     171    while (it)
     172      {
     173        cmp->items = g_list_prepend (cmp->items, it->data);
     174        it = it->next;
     175      }
     176  }
     177  
     178  /**
     179   * g_completion_remove_items:
     180   * @cmp: the #GCompletion.
     181   * @items: (transfer none): the items to remove.
     182   *
     183   * Removes items from a #GCompletion. The items are not freed, so if the memory
     184   * was dynamically allocated, free @items with g_list_free_full() after calling
     185   * this function.
     186   *
     187   * Deprecated: 2.26: Rarely used API
     188   **/
     189  void 
     190  g_completion_remove_items (GCompletion* cmp,
     191  			   GList*	items)
     192  {
     193    GList* it;
     194    
     195    g_return_if_fail (cmp != NULL);
     196    
     197    it = items;
     198    while (cmp->items && it)
     199      {
     200        cmp->items = g_list_remove (cmp->items, it->data);
     201        it = it->next;
     202      }
     203  
     204    it = items;
     205    while (cmp->cache && it)
     206      {
     207        cmp->cache = g_list_remove(cmp->cache, it->data);
     208        it = it->next;
     209      }
     210  }
     211  
     212  /**
     213   * g_completion_clear_items:
     214   * @cmp: the #GCompletion.
     215   *
     216   * Removes all items from the #GCompletion. The items are not freed, so if the
     217   * memory was dynamically allocated, it should be freed after calling this
     218   * function.
     219   *
     220   * Deprecated: 2.26: Rarely used API
     221   **/
     222  void 
     223  g_completion_clear_items (GCompletion* cmp)
     224  {
     225    g_return_if_fail (cmp != NULL);
     226    
     227    g_list_free (cmp->items);
     228    cmp->items = NULL;
     229    g_list_free (cmp->cache);
     230    cmp->cache = NULL;
     231    g_free (cmp->prefix);
     232    cmp->prefix = NULL;
     233  }
     234  
     235  static void   
     236  completion_check_cache (GCompletion* cmp,
     237  			gchar**	     new_prefix)
     238  {
     239    GList* list;
     240    gsize len;
     241    gsize i;
     242    gsize plen;
     243    gchar* postfix;
     244    gchar* s;
     245    
     246    if (!new_prefix)
     247      return;
     248    if (!cmp->cache)
     249      {
     250        *new_prefix = NULL;
     251        return;
     252      }
     253    
     254    len = strlen(cmp->prefix);
     255    list = cmp->cache;
     256    s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
     257    postfix = s + len;
     258    plen = strlen (postfix);
     259    list = list->next;
     260    
     261    while (list && plen)
     262      {
     263        s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
     264        s += len;
     265        for (i = 0; i < plen; ++i)
     266  	{
     267  	  if (postfix[i] != s[i])
     268  	    break;
     269  	}
     270        plen = i;
     271        list = list->next;
     272      }
     273    
     274    *new_prefix = g_new0 (gchar, len + plen + 1);
     275    strncpy (*new_prefix, cmp->prefix, len);
     276    strncpy (*new_prefix + len, postfix, plen);
     277  }
     278  
     279  /**
     280   * g_completion_complete_utf8:
     281   * @cmp: the #GCompletion
     282   * @prefix: the prefix string, typically used by the user, which is compared
     283   *    with each of the items
     284   * @new_prefix: if non-%NULL, returns the longest prefix which is common to all
     285   *    items that matched @prefix, or %NULL if no items matched @prefix.
     286   *    This string should be freed when no longer needed.
     287   *
     288   * Attempts to complete the string @prefix using the #GCompletion target items.
     289   * In contrast to g_completion_complete(), this function returns the largest common
     290   * prefix that is a valid UTF-8 string, omitting a possible common partial 
     291   * character.
     292   *
     293   * You should use this function instead of g_completion_complete() if your 
     294   * items are UTF-8 strings.
     295   *
     296   * Returns: (element-type utf8) (transfer none): the list of items whose strings begin with @prefix. This should
     297   * not be changed.
     298   *
     299   * Since: 2.4
     300   *
     301   * Deprecated: 2.26: Rarely used API
     302   **/
     303  GList*
     304  g_completion_complete_utf8 (GCompletion  *cmp,
     305  			    const gchar  *prefix,
     306  			    gchar       **new_prefix)
     307  {
     308    GList *list;
     309    gchar *p, *q;
     310  
     311    list = g_completion_complete (cmp, prefix, new_prefix);
     312  
     313    if (new_prefix && *new_prefix)
     314      {
     315        p = *new_prefix + strlen (*new_prefix);
     316        q = g_utf8_find_prev_char (*new_prefix, p);
     317        
     318        switch (g_utf8_get_char_validated (q, p - q))
     319  	{
     320  	case (gunichar)-2:
     321  	case (gunichar)-1:
     322  	  *q = 0;
     323  	  break;
     324  	default: ;
     325  	}
     326  
     327      }
     328  
     329    return list;
     330  }
     331  
     332  /**
     333   * g_completion_complete:
     334   * @cmp: the #GCompletion.
     335   * @prefix: the prefix string, typically typed by the user, which is
     336   *          compared with each of the items.
     337   * @new_prefix: if non-%NULL, returns the longest prefix which is
     338   *              common to all items that matched @prefix, or %NULL if
     339   *              no items matched @prefix.  This string should be freed
     340   *              when no longer needed.
     341   *
     342   * Attempts to complete the string @prefix using the #GCompletion
     343   * target items.
     344   *
     345   * Returns: (transfer none): the list of items whose strings begin with
     346   *          @prefix. This should not be changed.
     347   *
     348   * Deprecated: 2.26: Rarely used API
     349   **/
     350  GList* 
     351  g_completion_complete (GCompletion* cmp,
     352  		       const gchar* prefix,
     353  		       gchar**	    new_prefix)
     354  {
     355    gsize plen, len;
     356    gboolean done = FALSE;
     357    GList* list;
     358    
     359    g_return_val_if_fail (cmp != NULL, NULL);
     360    g_return_val_if_fail (prefix != NULL, NULL);
     361    
     362    len = strlen (prefix);
     363    if (cmp->prefix && cmp->cache)
     364      {
     365        plen = strlen (cmp->prefix);
     366        if (plen <= len && ! cmp->strncmp_func (prefix, cmp->prefix, plen))
     367  	{ 
     368  	  /* use the cache */
     369  	  list = cmp->cache;
     370  	  while (list)
     371  	    {
     372  	      GList *next = list->next;
     373  	      
     374  	      if (cmp->strncmp_func (prefix,
     375  				     cmp->func ? cmp->func (list->data) : (gchar*) list->data,
     376  				     len))
     377  		cmp->cache = g_list_delete_link (cmp->cache, list);
     378  
     379  	      list = next;
     380  	    }
     381  	  done = TRUE;
     382  	}
     383      }
     384    
     385    if (!done)
     386      {
     387        /* normal code */
     388        g_list_free (cmp->cache);
     389        cmp->cache = NULL;
     390        list = cmp->items;
     391        while (*prefix && list)
     392  	{
     393  	  if (!cmp->strncmp_func (prefix,
     394  			cmp->func ? cmp->func (list->data) : (gchar*) list->data,
     395  			len))
     396  	    cmp->cache = g_list_prepend (cmp->cache, list->data);
     397  	  list = list->next;
     398  	}
     399      }
     400    if (cmp->prefix)
     401      {
     402        g_free (cmp->prefix);
     403        cmp->prefix = NULL;
     404      }
     405    if (cmp->cache)
     406      cmp->prefix = g_strdup (prefix);
     407    completion_check_cache (cmp, new_prefix);
     408    
     409    return *prefix ? cmp->cache : cmp->items;
     410  }
     411  
     412  /**
     413   * g_completion_free:
     414   * @cmp: the #GCompletion.
     415   *
     416   * Frees all memory used by the #GCompletion. The items are not freed, so if
     417   * the memory was dynamically allocated, it should be freed after calling this
     418   * function.
     419   *
     420   * Deprecated: 2.26: Rarely used API
     421   **/
     422  void 
     423  g_completion_free (GCompletion* cmp)
     424  {
     425    g_return_if_fail (cmp != NULL);
     426    
     427    g_completion_clear_items (cmp);
     428    g_free (cmp);
     429  }
     430  
     431  /**
     432   * g_completion_set_compare:
     433   * @cmp: a #GCompletion.
     434   * @strncmp_func: the string comparison function.
     435   *
     436   * Sets the function to use for string comparisons. The default string
     437   * comparison function is strncmp().
     438   *
     439   * Deprecated: 2.26: Rarely used API
     440   **/
     441  void
     442  g_completion_set_compare(GCompletion *cmp,
     443  			 GCompletionStrncmpFunc strncmp_func)
     444  {
     445    cmp->strncmp_func = strncmp_func;
     446  }
     447  
     448  #ifdef TEST_COMPLETION
     449  #include <stdio.h>
     450  int
     451  main (int   argc,
     452        char* argv[])
     453  {
     454    FILE *file;
     455    gchar buf[1024];
     456    GList *list;
     457    GList *result;
     458    GList *tmp;
     459    GCompletion *cmp;
     460    gint i;
     461    gchar *longp = NULL;
     462    
     463    if (argc < 3)
     464      {
     465        g_warning ("Usage: %s filename prefix1 [prefix2 ...]",
     466                   (argc > 0) ? argv[0] : "gcompletion");
     467        return 1;
     468      }
     469    
     470    file = fopen (argv[1], "r");
     471    if (!file)
     472      {
     473        g_warning ("Cannot open %s", argv[1]);
     474        return 1;
     475      }
     476    
     477    cmp = g_completion_new (NULL);
     478    list = g_list_alloc ();
     479    while (fgets (buf, 1024, file))
     480      {
     481        list->data = g_strdup (buf);
     482        g_completion_add_items (cmp, list);
     483      }
     484    fclose (file);
     485    
     486    for (i = 2; i < argc; ++i)
     487      {
     488        printf ("COMPLETING: %s\n", argv[i]);
     489        result = g_completion_complete (cmp, argv[i], &longp);
     490        g_list_foreach (result, (GFunc) printf, NULL);
     491        printf ("LONG MATCH: %s\n", longp);
     492        g_free (longp);
     493        longp = NULL;
     494      }
     495    
     496    g_list_foreach (cmp->items, (GFunc) g_free, NULL);
     497    g_completion_free (cmp);
     498    g_list_free (list);
     499    
     500    return 0;
     501  }
     502  #endif