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