source: trunk/third/glib/gcompletion.c @ 14807

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