fix typo in last commit, cast to GTypeValueTable * to get rid of const
[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
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   g_return_if_fail (items != NULL);
64   
65   /* optimize adding to cache? */
66   if (cmp->cache)
67     {
68       g_list_free (cmp->cache);
69       cmp->cache = NULL;
70     }
71
72   if (cmp->prefix)
73     {
74       g_free (cmp->prefix);
75       cmp->prefix = NULL;
76     }
77   
78   it = items;
79   while (it)
80     {
81       cmp->items = g_list_prepend (cmp->items, it->data);
82       it = it->next;
83     }
84 }
85
86 void 
87 g_completion_remove_items (GCompletion* cmp,
88                            GList*       items)
89 {
90   GList* it;
91   
92   g_return_if_fail (cmp != NULL);
93   g_return_if_fail (items != 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
110 void 
111 g_completion_clear_items (GCompletion* cmp)
112 {
113   g_return_if_fail (cmp != NULL);
114   
115   g_list_free (cmp->items);
116   cmp->items = NULL;
117   g_list_free (cmp->cache);
118   cmp->cache = NULL;
119   g_free (cmp->prefix);
120   cmp->prefix = NULL;
121 }
122
123 static void   
124 completion_check_cache (GCompletion* cmp,
125                         gchar**      new_prefix)
126 {
127   register GList* list;
128   register gsize len;  
129   register gsize i;
130   register gsize plen;
131   gchar* postfix;
132   gchar* s;
133   
134   if (!new_prefix)
135     return;
136   if (!cmp->cache)
137     {
138       *new_prefix = NULL;
139       return;
140     }
141   
142   len = strlen(cmp->prefix);
143   list = cmp->cache;
144   s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
145   postfix = s + len;
146   plen = strlen (postfix);
147   list = list->next;
148   
149   while (list && plen)
150     {
151       s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
152       s += len;
153       for (i = 0; i < plen; ++i)
154         {
155           if (postfix[i] != s[i])
156             break;
157         }
158       plen = i;
159       list = list->next;
160     }
161   
162   *new_prefix = g_new0 (gchar, len + plen + 1);
163   strncpy (*new_prefix, cmp->prefix, len);
164   strncpy (*new_prefix + len, postfix, plen);
165 }
166
167 GList* 
168 g_completion_complete (GCompletion* cmp,
169                        const gchar* prefix,
170                        gchar**      new_prefix)
171 {
172   gsize plen, len;
173   gboolean done = FALSE;
174   GList* list;
175   
176   g_return_val_if_fail (cmp != NULL, NULL);
177   g_return_val_if_fail (prefix != NULL, NULL);
178   
179   len = strlen (prefix);
180   if (cmp->prefix && cmp->cache)
181     {
182       plen = strlen (cmp->prefix);
183       if (plen <= len && ! cmp->strncmp_func (prefix, cmp->prefix, plen))
184         { 
185           /* use the cache */
186           list = cmp->cache;
187           while (list)
188             {
189               GList *next = list->next;
190               
191               if (cmp->strncmp_func (prefix,
192                                      cmp->func ? cmp->func (list->data) : (gchar*) list->data,
193                                      len))
194                 cmp->cache = g_list_delete_link (cmp->cache, list);
195
196               list = next;
197             }
198           done = TRUE;
199         }
200     }
201   
202   if (!done)
203     {
204       /* normal code */
205       g_list_free (cmp->cache);
206       cmp->cache = NULL;
207       list = cmp->items;
208       while (*prefix && list)
209         {
210           if (!cmp->strncmp_func (prefix,
211                         cmp->func ? cmp->func (list->data) : (gchar*) list->data,
212                         len))
213             cmp->cache = g_list_prepend (cmp->cache, list->data);
214           list = list->next;
215         }
216     }
217   if (cmp->prefix)
218     {
219       g_free (cmp->prefix);
220       cmp->prefix = NULL;
221     }
222   if (cmp->cache)
223     cmp->prefix = g_strdup (prefix);
224   completion_check_cache (cmp, new_prefix);
225   
226   return *prefix ? cmp->cache : cmp->items;
227 }
228
229 void 
230 g_completion_free (GCompletion* cmp)
231 {
232   g_return_if_fail (cmp != NULL);
233   
234   g_completion_clear_items (cmp);
235   g_free (cmp);
236 }
237
238 void
239 g_completion_set_compare(GCompletion *cmp,
240                          GCompletionStrncmpFunc strncmp_func)
241 {
242   cmp->strncmp_func = strncmp_func;
243 }
244
245 #ifdef TEST_COMPLETION
246 #include <stdio.h>
247 int
248 main (int   argc,
249       char* argv[])
250 {
251   FILE *file;
252   gchar buf[1024];
253   GList *list;
254   GList *result;
255   GList *tmp;
256   GCompletion *cmp;
257   gint i;
258   gchar *longp = NULL;
259   
260   if (argc < 3)
261     {
262       g_warning ("Usage: %s filename prefix1 [prefix2 ...]\n", argv[0]);
263       return 1;
264     }
265   
266   file = fopen (argv[1], "r");
267   if (!file)
268     {
269       g_warning ("Cannot open %s\n", argv[1]);
270       return 1;
271     }
272   
273   cmp = g_completion_new (NULL);
274   list = g_list_alloc ();
275   while (fgets (buf, 1024, file))
276     {
277       list->data = g_strdup (buf);
278       g_completion_add_items (cmp, list);
279     }
280   fclose (file);
281   
282   for (i = 2; i < argc; ++i)
283     {
284       printf ("COMPLETING: %s\n", argv[i]);
285       result = g_completion_complete (cmp, argv[i], &longp);
286       g_list_foreach (result, (GFunc) printf, NULL);
287       printf ("LONG MATCH: %s\n", longp);
288       g_free (longp);
289       longp = NULL;
290     }
291   
292   g_list_foreach (cmp->items, (GFunc) g_free, NULL);
293   g_completion_free (cmp);
294   g_list_free (list);
295   
296   return 0;
297 }
298 #endif