Break some long lines.
[platform/upstream/glib.git] / glib / 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  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
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 #include <string.h>
34
35 #include "glib.h"
36 #include "galias.h"
37
38 static void completion_check_cache (GCompletion* cmp,
39                                     gchar**      new_prefix);
40
41 GCompletion* 
42 g_completion_new (GCompletionFunc func)
43 {
44   GCompletion* gcomp;
45   
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 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 void 
86 g_completion_remove_items (GCompletion* cmp,
87                            GList*       items)
88 {
89   GList* it;
90   
91   g_return_if_fail (cmp != NULL);
92   
93   it = items;
94   while (cmp->items && it)
95     {
96       cmp->items = g_list_remove (cmp->items, it->data);
97       it = it->next;
98     }
99
100   it = items;
101   while (cmp->cache && it)
102     {
103       cmp->cache = g_list_remove(cmp->cache, it->data);
104       it = it->next;
105     }
106 }
107
108 void 
109 g_completion_clear_items (GCompletion* cmp)
110 {
111   g_return_if_fail (cmp != NULL);
112   
113   g_list_free (cmp->items);
114   cmp->items = NULL;
115   g_list_free (cmp->cache);
116   cmp->cache = NULL;
117   g_free (cmp->prefix);
118   cmp->prefix = NULL;
119 }
120
121 static void   
122 completion_check_cache (GCompletion* cmp,
123                         gchar**      new_prefix)
124 {
125   register GList* list;
126   register gsize len;  
127   register gsize i;
128   register gsize plen;
129   gchar* postfix;
130   gchar* s;
131   
132   if (!new_prefix)
133     return;
134   if (!cmp->cache)
135     {
136       *new_prefix = NULL;
137       return;
138     }
139   
140   len = strlen(cmp->prefix);
141   list = cmp->cache;
142   s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
143   postfix = s + len;
144   plen = strlen (postfix);
145   list = list->next;
146   
147   while (list && plen)
148     {
149       s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
150       s += len;
151       for (i = 0; i < plen; ++i)
152         {
153           if (postfix[i] != s[i])
154             break;
155         }
156       plen = i;
157       list = list->next;
158     }
159   
160   *new_prefix = g_new0 (gchar, len + plen + 1);
161   strncpy (*new_prefix, cmp->prefix, len);
162   strncpy (*new_prefix + len, postfix, plen);
163 }
164
165 /**
166  * g_completion_complete_utf8:
167  * @cmp: the #GCompletion
168  * @prefix: the prefix string, typically used by the user, which is compared
169  *    with each of the items
170  * @new_prefix: if non-%NULL, returns the longest prefix which is common to all
171  *    items that matched @prefix, or %NULL if no items matched @prefix.
172  *    This string should be freed when no longer needed.
173  *
174  * Attempts to complete the string @prefix using the #GCompletion target items.
175  * In contrast to g_completion_complete(), this function returns the largest common
176  * prefix that is a valid UTF-8 string, omitting a possible common partial 
177  * character.
178  *
179  * You should use this function instead of g_completion_complete() if your 
180  * items are UTF-8 strings.
181  *
182  * Return value: the list of items whose strings begin with @prefix. This should
183  * not be changed.
184  *
185  * Since: 2.4
186  **/
187 GList*
188 g_completion_complete_utf8 (GCompletion  *cmp,
189                             const gchar  *prefix,
190                             gchar       **new_prefix)
191 {
192   GList *list;
193   gchar *p, *q;
194
195   list = g_completion_complete (cmp, prefix, new_prefix);
196
197   if (*new_prefix)
198     {
199       p = *new_prefix + strlen (*new_prefix);
200       q = g_utf8_find_prev_char (*new_prefix, p);
201       
202       switch (g_utf8_get_char_validated (q, p - q))
203         {
204         case (gunichar)-2:
205         case (gunichar)-1:
206           *q = 0;
207           break;
208         default: ;
209         }
210
211     }
212
213   return list;
214 }
215
216 GList* 
217 g_completion_complete (GCompletion* cmp,
218                        const gchar* prefix,
219                        gchar**      new_prefix)
220 {
221   gsize plen, len;
222   gboolean done = FALSE;
223   GList* list;
224   
225   g_return_val_if_fail (cmp != NULL, NULL);
226   g_return_val_if_fail (prefix != NULL, NULL);
227   
228   len = strlen (prefix);
229   if (cmp->prefix && cmp->cache)
230     {
231       plen = strlen (cmp->prefix);
232       if (plen <= len && ! cmp->strncmp_func (prefix, cmp->prefix, plen))
233         { 
234           /* use the cache */
235           list = cmp->cache;
236           while (list)
237             {
238               GList *next = list->next;
239               
240               if (cmp->strncmp_func (prefix,
241                                      cmp->func ? cmp->func (list->data) : (gchar*) list->data,
242                                      len))
243                 cmp->cache = g_list_delete_link (cmp->cache, list);
244
245               list = next;
246             }
247           done = TRUE;
248         }
249     }
250   
251   if (!done)
252     {
253       /* normal code */
254       g_list_free (cmp->cache);
255       cmp->cache = NULL;
256       list = cmp->items;
257       while (*prefix && list)
258         {
259           if (!cmp->strncmp_func (prefix,
260                         cmp->func ? cmp->func (list->data) : (gchar*) list->data,
261                         len))
262             cmp->cache = g_list_prepend (cmp->cache, list->data);
263           list = list->next;
264         }
265     }
266   if (cmp->prefix)
267     {
268       g_free (cmp->prefix);
269       cmp->prefix = NULL;
270     }
271   if (cmp->cache)
272     cmp->prefix = g_strdup (prefix);
273   completion_check_cache (cmp, new_prefix);
274   
275   return *prefix ? cmp->cache : cmp->items;
276 }
277
278 void 
279 g_completion_free (GCompletion* cmp)
280 {
281   g_return_if_fail (cmp != NULL);
282   
283   g_completion_clear_items (cmp);
284   g_free (cmp);
285 }
286
287 void
288 g_completion_set_compare(GCompletion *cmp,
289                          GCompletionStrncmpFunc strncmp_func)
290 {
291   cmp->strncmp_func = strncmp_func;
292 }
293
294 #ifdef TEST_COMPLETION
295 #include <stdio.h>
296 int
297 main (int   argc,
298       char* argv[])
299 {
300   FILE *file;
301   gchar buf[1024];
302   GList *list;
303   GList *result;
304   GList *tmp;
305   GCompletion *cmp;
306   gint i;
307   gchar *longp = NULL;
308   
309   if (argc < 3)
310     {
311       g_warning ("Usage: %s filename prefix1 [prefix2 ...]\n", argv[0]);
312       return 1;
313     }
314   
315   file = fopen (argv[1], "r");
316   if (!file)
317     {
318       g_warning ("Cannot open %s\n", argv[1]);
319       return 1;
320     }
321   
322   cmp = g_completion_new (NULL);
323   list = g_list_alloc ();
324   while (fgets (buf, 1024, file))
325     {
326       list->data = g_strdup (buf);
327       g_completion_add_items (cmp, list);
328     }
329   fclose (file);
330   
331   for (i = 2; i < argc; ++i)
332     {
333       printf ("COMPLETING: %s\n", argv[i]);
334       result = g_completion_complete (cmp, argv[i], &longp);
335       g_list_foreach (result, (GFunc) printf, NULL);
336       printf ("LONG MATCH: %s\n", longp);
337       g_free (longp);
338       longp = NULL;
339     }
340   
341   g_list_foreach (cmp->items, (GFunc) g_free, NULL);
342   g_completion_free (cmp);
343   g_list_free (list);
344   
345   return 0;
346 }
347 #endif
348
349 #define __G_COMPLETION_C__
350 #include "galiasdef.c"