glib/libglib/src/gcompletion.c
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 /* GLIB - Library of useful routines for C programming
       
     2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
       
     3  * Portions copyright (c) 2006 Nokia Corporation.  All rights reserved.
       
     4  *
       
     5  * This library is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU Lesser General Public
       
     7  * License as published by the Free Software Foundation; either
       
     8  * version 2 of the License, or (at your option) any later version.
       
     9  *
       
    10  * This library is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
       
    13  * Lesser General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU Lesser General Public
       
    16  * License along with this library; if not, write to the
       
    17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    18  * Boston, MA 02111-1307, USA.
       
    19  */
       
    20 
       
    21 /*
       
    22  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
       
    23  * file for a list of people on the GLib Team.  See the ChangeLog
       
    24  * files for a list of changes.  These files are distributed with
       
    25  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
       
    26  */
       
    27 
       
    28 /* 
       
    29  * MT safe
       
    30  */
       
    31 
       
    32 #include "config.h"
       
    33 
       
    34 #include <string.h>
       
    35 
       
    36 #include "glib.h"
       
    37 #include "galias.h"
       
    38 
       
    39 static void completion_check_cache (GCompletion* cmp,
       
    40 				    gchar**	 new_prefix);
       
    41 
       
    42 EXPORT_C GCompletion* 
       
    43 g_completion_new (GCompletionFunc func)
       
    44 {
       
    45   GCompletion* gcomp;
       
    46   gcomp = g_new (GCompletion, 1);
       
    47   gcomp->items = NULL;
       
    48   gcomp->cache = NULL;
       
    49   gcomp->prefix = NULL;
       
    50   gcomp->func = func;
       
    51   gcomp->strncmp_func = strncmp;
       
    52 
       
    53   return gcomp;
       
    54 }
       
    55 
       
    56 EXPORT_C void 
       
    57 g_completion_add_items (GCompletion* cmp,
       
    58 			GList*	     items)
       
    59 {
       
    60   GList* it;
       
    61   
       
    62   g_return_if_fail (cmp != NULL);
       
    63   
       
    64   /* optimize adding to cache? */
       
    65   if (cmp->cache)
       
    66     {
       
    67       g_list_free (cmp->cache);
       
    68       cmp->cache = NULL;
       
    69     }
       
    70 
       
    71   if (cmp->prefix)
       
    72     {
       
    73       g_free (cmp->prefix);
       
    74       cmp->prefix = NULL;
       
    75     }
       
    76   
       
    77   it = items;
       
    78   while (it)
       
    79     {
       
    80       cmp->items = g_list_prepend (cmp->items, it->data);
       
    81       it = it->next;
       
    82     }
       
    83 }
       
    84 
       
    85 EXPORT_C void 
       
    86 g_completion_remove_items (GCompletion* cmp,
       
    87 			   GList*	items)
       
    88 {
       
    89   #ifndef __SYMBIAN32__
       
    90   
       
    91   GList* it;
       
    92   
       
    93   g_return_if_fail (cmp != NULL);
       
    94   
       
    95   it = items;
       
    96   while (cmp->items && it)
       
    97     {
       
    98       cmp->items = g_list_remove (cmp->items, it->data);
       
    99       it = it->next;
       
   100     }
       
   101 
       
   102   it = items;
       
   103   while (cmp->cache && it)
       
   104     {
       
   105       cmp->cache = g_list_remove(cmp->cache, it->data);
       
   106       it = it->next;
       
   107     }
       
   108     
       
   109   #else
       
   110   
       
   111   GList *it;
       
   112   gpointer *data;
       
   113   
       
   114   g_return_if_fail (cmp != NULL);
       
   115   
       
   116   it = items;
       
   117   while (cmp->items && it)
       
   118     {
       
   119       data = it->data;
       
   120       it = it->next;
       
   121       cmp->items = g_list_remove (cmp->items, data);
       
   122     }
       
   123 
       
   124   it = items;
       
   125   while (cmp->cache && it)
       
   126     {
       
   127       data = it->data;
       
   128       it = it->next;
       
   129       cmp->cache = g_list_remove(cmp->cache, data);
       
   130     }
       
   131   
       
   132   #endif /* __SYMBIAN32__ */
       
   133 }
       
   134 
       
   135 EXPORT_C void 
       
   136 g_completion_clear_items (GCompletion* cmp)
       
   137 {
       
   138   g_return_if_fail (cmp != NULL);
       
   139   
       
   140   g_list_free (cmp->items);
       
   141   cmp->items = NULL;
       
   142   g_list_free (cmp->cache);
       
   143   cmp->cache = NULL;
       
   144   g_free (cmp->prefix);
       
   145   cmp->prefix = NULL;
       
   146 }
       
   147 
       
   148 static void   
       
   149 completion_check_cache (GCompletion* cmp,
       
   150 			gchar**	     new_prefix)
       
   151 {
       
   152   register GList* list;
       
   153   register gsize len;  
       
   154   register gsize i;
       
   155   register gsize plen;
       
   156   gchar* postfix;
       
   157   gchar* s;
       
   158   
       
   159   if (!new_prefix)
       
   160     return;
       
   161   if (!cmp->cache)
       
   162     {
       
   163       *new_prefix = NULL;
       
   164       return;
       
   165     }
       
   166   
       
   167   len = strlen(cmp->prefix);
       
   168   list = cmp->cache;
       
   169   s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
       
   170   postfix = s + len;
       
   171   plen = strlen (postfix);
       
   172   list = list->next;
       
   173   
       
   174   while (list && plen)
       
   175     {
       
   176       s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
       
   177       s += len;
       
   178       for (i = 0; i < plen; ++i)
       
   179 	{
       
   180 	  if (postfix[i] != s[i])
       
   181 	    break;
       
   182 	}
       
   183       plen = i;
       
   184       list = list->next;
       
   185     }
       
   186   *new_prefix = g_new0 (gchar, len + plen + 1);
       
   187   strncpy (*new_prefix, cmp->prefix, len);
       
   188   strncpy (*new_prefix + len, postfix, plen);
       
   189 }
       
   190 
       
   191 /**
       
   192  * g_completion_complete_utf8:
       
   193  * @cmp: the #GCompletion
       
   194  * @prefix: the prefix string, typically used by the user, which is compared
       
   195  *    with each of the items
       
   196  * @new_prefix: if non-%NULL, returns the longest prefix which is common to all
       
   197  *    items that matched @prefix, or %NULL if no items matched @prefix.
       
   198  *    This string should be freed when no longer needed.
       
   199  *
       
   200  * Attempts to complete the string @prefix using the #GCompletion target items.
       
   201  * In contrast to g_completion_complete(), this function returns the largest common
       
   202  * prefix that is a valid UTF-8 string, omitting a possible common partial 
       
   203  * character.
       
   204  *
       
   205  * You should use this function instead of g_completion_complete() if your 
       
   206  * items are UTF-8 strings.
       
   207  *
       
   208  * Return value: the list of items whose strings begin with @prefix. This should
       
   209  * not be changed.
       
   210  *
       
   211  * Since: 2.4
       
   212  **/
       
   213 EXPORT_C GList*
       
   214 g_completion_complete_utf8 (GCompletion  *cmp,
       
   215 			    const gchar  *prefix,
       
   216 			    gchar       **new_prefix)
       
   217 {
       
   218   GList *list;
       
   219   gchar *p, *q;
       
   220 
       
   221   list = g_completion_complete (cmp, prefix, new_prefix);
       
   222 
       
   223   if (new_prefix && *new_prefix)
       
   224     {
       
   225       p = *new_prefix + strlen (*new_prefix);
       
   226       q = g_utf8_find_prev_char (*new_prefix, p);
       
   227       
       
   228       switch (g_utf8_get_char_validated (q, p - q))
       
   229 	{
       
   230 	case (gunichar)-2:
       
   231 	case (gunichar)-1:
       
   232 	  *q = 0;
       
   233 	  break;
       
   234 	default: ;
       
   235 	}
       
   236 
       
   237     }
       
   238 
       
   239   return list;
       
   240 }
       
   241 
       
   242 EXPORT_C GList* 
       
   243 g_completion_complete (GCompletion* cmp,
       
   244 		       const gchar* prefix,
       
   245 		       gchar**	    new_prefix)
       
   246 {
       
   247   gsize plen, len;
       
   248   gboolean done = FALSE;
       
   249   GList* list;
       
   250   
       
   251   g_return_val_if_fail (cmp != NULL, NULL);
       
   252   g_return_val_if_fail (prefix != NULL, NULL);
       
   253   
       
   254   len = strlen (prefix);
       
   255   if (cmp->prefix && cmp->cache)
       
   256     {
       
   257       plen = strlen (cmp->prefix);
       
   258       if (plen <= len && ! cmp->strncmp_func (prefix, cmp->prefix, plen))
       
   259 	{ 
       
   260 	  /* use the cache */
       
   261 	  list = cmp->cache;
       
   262 	  while (list)
       
   263 	    {
       
   264 	      GList *next = list->next;
       
   265 	      
       
   266 	      if (cmp->strncmp_func (prefix,
       
   267 				     cmp->func ? cmp->func (list->data) : (gchar*) list->data,
       
   268 				     len))
       
   269 		cmp->cache = g_list_delete_link (cmp->cache, list);
       
   270 
       
   271 	      list = next;
       
   272 	    }
       
   273 	  done = TRUE;
       
   274 	}
       
   275     }
       
   276   
       
   277   if (!done)
       
   278     {
       
   279       /* normal code */
       
   280       g_list_free (cmp->cache);
       
   281       cmp->cache = NULL;
       
   282       list = cmp->items;
       
   283       while (*prefix && list)
       
   284 	{
       
   285 	  if (!cmp->strncmp_func (prefix,
       
   286 			cmp->func ? cmp->func (list->data) : (gchar*) list->data,
       
   287 			len))
       
   288 	    cmp->cache = g_list_prepend (cmp->cache, list->data);
       
   289 	  list = list->next;
       
   290 	}
       
   291     }
       
   292   if (cmp->prefix)
       
   293     {
       
   294       g_free (cmp->prefix);
       
   295       cmp->prefix = NULL;
       
   296     }
       
   297   if (cmp->cache)
       
   298     cmp->prefix = g_strdup (prefix);
       
   299   completion_check_cache (cmp, new_prefix);
       
   300   
       
   301   return *prefix ? cmp->cache : cmp->items;
       
   302 }
       
   303 
       
   304 EXPORT_C void 
       
   305 g_completion_free (GCompletion* cmp)
       
   306 {
       
   307   g_return_if_fail (cmp != NULL);
       
   308   
       
   309   g_completion_clear_items (cmp);
       
   310   g_free (cmp);
       
   311 }
       
   312 
       
   313 EXPORT_C void
       
   314 g_completion_set_compare(GCompletion *cmp,
       
   315 			 GCompletionStrncmpFunc strncmp_func)
       
   316 {
       
   317   cmp->strncmp_func = strncmp_func;
       
   318 }
       
   319 
       
   320 #ifdef TEST_COMPLETION
       
   321 #include <stdio.h>
       
   322 int
       
   323 main (int   argc,
       
   324       char* argv[])
       
   325 {
       
   326   FILE *file;
       
   327   gchar buf[1024];
       
   328   GList *list;
       
   329   GList *result;
       
   330   GList *tmp;
       
   331   GCompletion *cmp;
       
   332   gint i;
       
   333   gchar *longp = NULL;
       
   334   
       
   335   if (argc < 3)
       
   336     {
       
   337       g_warning ("Usage: %s filename prefix1 [prefix2 ...]\n", argv[0]);
       
   338       return 1;
       
   339     }
       
   340   
       
   341   file = fopen (argv[1], "r");
       
   342   if (!file)
       
   343     {
       
   344       g_warning ("Cannot open %s\n", argv[1]);
       
   345       return 1;
       
   346     }
       
   347   
       
   348   cmp = g_completion_new (NULL);
       
   349   list = g_list_alloc ();
       
   350   while (fgets (buf, 1024, file))
       
   351     {
       
   352       list->data = g_strdup (buf);
       
   353       g_completion_add_items (cmp, list);
       
   354     }
       
   355   fclose (file);
       
   356   
       
   357   for (i = 2; i < argc; ++i)
       
   358     {
       
   359       printf ("COMPLETING: %s\n", argv[i]);
       
   360       result = g_completion_complete (cmp, argv[i], &longp);
       
   361       g_list_foreach (result, (GFunc) printf, NULL);
       
   362       printf ("LONG MATCH: %s\n", longp);
       
   363       g_free (longp);
       
   364       longp = NULL;
       
   365     }
       
   366   
       
   367   g_list_foreach (cmp->items, (GFunc) g_free, NULL);
       
   368   g_completion_free (cmp);
       
   369   g_list_free (list);
       
   370   
       
   371   return 0;
       
   372 }
       
   373 #endif
       
   374 
       
   375 #define __G_COMPLETION_C__
       
   376 #include "galiasdef.c"