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