pools of 128 items instead of 1024 items.
[platform/upstream/glib.git] / 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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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  * MT safe
22  */
23
24 #include "glib.h"
25 #include <string.h>
26
27 static void completion_check_cache (GCompletion* cmp,
28                                     gchar**      new_prefix);
29
30 GCompletion* 
31 g_completion_new (GCompletionFunc func)
32 {
33   GCompletion* gcomp;
34   
35   gcomp = g_new (GCompletion, 1);
36   gcomp->items = NULL;
37   gcomp->cache = NULL;
38   gcomp->prefix = NULL;
39   gcomp->func = func;
40
41   return gcomp;
42 }
43
44 void 
45 g_completion_add_items (GCompletion* cmp,
46                         GList*       items)
47 {
48   GList* it;
49   
50   g_return_if_fail (cmp != NULL);
51   g_return_if_fail (items != NULL);
52   
53   /* optimize adding to cache? */
54   if (cmp->cache)
55     {
56       g_list_free (cmp->cache);
57       cmp->cache = NULL;
58     }
59
60   if (cmp->prefix)
61     {
62       g_free (cmp->prefix);
63       cmp->prefix = NULL;
64     }
65   
66   it = items;
67   while (it)
68     {
69       cmp->items = g_list_prepend (cmp->items, it->data);
70       it = it->next;
71     }
72 }
73
74 void 
75 g_completion_remove_items (GCompletion* cmp,
76                            GList*       items)
77 {
78   GList* it;
79   
80   g_return_if_fail (cmp != NULL);
81   g_return_if_fail (items != NULL);
82   
83   it = items;
84   while (cmp->items && it)
85     {
86       cmp->items = g_list_remove (cmp->items, it->data);
87       it = it->next;
88     }
89
90   it = items;
91   while (cmp->cache && it)
92     {
93       cmp->cache = g_list_remove(cmp->cache, it->data);
94       it = it->next;
95     }
96 }
97
98 void 
99 g_completion_clear_items (GCompletion* cmp)
100 {
101   g_return_if_fail (cmp != NULL);
102   
103   g_list_free (cmp->items);
104   cmp->items = NULL;
105   g_list_free (cmp->cache);
106   cmp->cache = NULL;
107   g_free (cmp->prefix);
108   cmp->prefix = NULL;
109 }
110
111 static void   
112 completion_check_cache (GCompletion* cmp,
113                         gchar**      new_prefix)
114 {
115   register GList* list;
116   register gint len;
117   register gint i;
118   register gint plen;
119   gchar* postfix=NULL;
120   gchar* s;
121   
122   if (!new_prefix)
123     return;
124   if (!cmp->cache)
125     {
126       *new_prefix = NULL;
127       return;
128     }
129   
130   len = strlen(cmp->prefix);
131   list = cmp->cache;
132   s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
133   postfix = s + len;
134   plen = strlen (postfix);
135   list = list->next;
136   
137   while (list && plen)
138     {
139       s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
140       s += len;
141       for (i = 0; i < plen; ++i)
142         {
143           if (postfix[i] != s[i])
144             break;
145         }
146       plen = i;
147       list = list->next;
148     }
149   
150   *new_prefix = g_new0 (gchar, len + plen + 1);
151   strncpy (*new_prefix, cmp->prefix, len);
152   strncpy (*new_prefix + len, postfix, plen);
153 }
154
155 GList* 
156 g_completion_complete (GCompletion* cmp,
157                        gchar*       prefix,
158                        gchar**      new_prefix)
159 {
160   gint plen, len;
161   gint done = 0;
162   GList* list;
163   
164   g_return_val_if_fail (cmp != NULL, NULL);
165   g_return_val_if_fail (prefix != NULL, NULL);
166   
167   len = strlen (prefix);
168   if (cmp->prefix && cmp->cache)
169     {
170       plen = strlen (cmp->prefix);
171       if (plen <= len && !strncmp (prefix, cmp->prefix, plen))
172         { 
173           /* use the cache */
174           list = cmp->cache;
175           while (list)
176             {
177               if (strncmp (prefix,
178                            cmp->func ? cmp->func (list->data) : (gchar*) list->data,
179                            len))
180                 {
181                   list = g_list_remove_link (cmp->cache, list);
182                   if (list != cmp->cache)
183                     cmp->cache = list;
184                 }
185               else
186                 list = list->next;
187             }
188           done = 1;
189         }
190     }
191   
192   if (!done)
193     {
194       /* normal code */
195       g_list_free (cmp->cache);
196       cmp->cache = NULL;
197       list = cmp->items;
198       while (*prefix && list)
199         {
200           if (!strncmp (prefix,
201                         cmp->func ? cmp->func (list->data) : (gchar*) list->data,
202                         len))
203             cmp->cache = g_list_prepend (cmp->cache, list->data);
204           list = list->next;
205         }
206     }
207   if (cmp->prefix)
208     {
209       g_free (cmp->prefix);
210       cmp->prefix = NULL;
211     }
212   if (cmp->cache)
213     cmp->prefix = g_strdup (prefix);
214   completion_check_cache (cmp, new_prefix);
215   
216   return *prefix ? cmp->cache : cmp->items;
217 }
218
219 void 
220 g_completion_free (GCompletion* cmp)
221 {
222   g_return_if_fail (cmp != NULL);
223   
224   g_completion_clear_items (cmp);
225   g_free (cmp);
226 }
227
228 #ifdef TEST_COMPLETION
229 #include <stdio.h>
230 int
231 main (int   argc,
232       char* argv[])
233 {
234   FILE *file;
235   gchar buf[1024];
236   GList *list;
237   GList *result;
238   GList *tmp;
239   GCompletion *cmp;
240   gint i;
241   gchar *longp = NULL;
242   
243   if (argc < 3)
244     {
245       g_warning ("Usage: %s filename prefix1 [prefix2 ...]\n", argv[0]);
246       return 1;
247     }
248   
249   file = fopen (argv[1], "r");
250   if (!file)
251     {
252       g_warning ("Cannot open %s\n", argv[1]);
253       return 1;
254     }
255   
256   cmp = g_completion_new (NULL);
257   list = g_list_alloc ();
258   while (fgets (buf, 1024, file))
259     {
260       list->data = g_strdup (buf);
261       g_completion_add_items (cmp, list);
262     }
263   fclose (file);
264   
265   for (i = 2; i < argc; ++i)
266     {
267       printf ("COMPLETING: %s\n", argv[i]);
268       result = g_completion_complete (cmp, argv[i], &longp);
269       g_list_foreach (result, (GFunc) printf, NULL);
270       printf ("LONG MATCH: %s\n", longp);
271       g_free (longp);
272       longp = NULL;
273     }
274   
275   g_list_foreach (cmp->items, (GFunc) g_free, NULL);
276   g_completion_free (cmp);
277   g_list_free (list);
278   
279   return 0;
280 }
281 #endif