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