~ubuntu-branches/ubuntu/utopic/glib2.0/utopic

« back to all changes in this revision

Viewing changes to glib/gcompletion.c

Tags: upstream-2.12.12
ImportĀ upstreamĀ versionĀ 2.12.12

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "config.h"
 
32
 
 
33
#include <string.h>
 
34
 
 
35
#include "glib.h"
 
36
#include "galias.h"
 
37
 
 
38
static void completion_check_cache (GCompletion* cmp,
 
39
                                    gchar**      new_prefix);
 
40
 
 
41
GCompletion* 
 
42
g_completion_new (GCompletionFunc func)
 
43
{
 
44
  GCompletion* gcomp;
 
45
  
 
46
  gcomp = g_new (GCompletion, 1);
 
47
  gcomp->items = NULL;
 
48
  gcomp->cache = NULL;
 
49
  gcomp->prefix = NULL;
 
50
  gcomp->func = func;
 
51
  gcomp->strncmp_func = strncmp;
 
52
 
 
53
  return gcomp;
 
54
}
 
55
 
 
56
void 
 
57
g_completion_add_items (GCompletion* cmp,
 
58
                        GList*       items)
 
59
{
 
60
  GList* it;
 
61
  
 
62
  g_return_if_fail (cmp != NULL);
 
63
  
 
64
  /* optimize adding to cache? */
 
65
  if (cmp->cache)
 
66
    {
 
67
      g_list_free (cmp->cache);
 
68
      cmp->cache = NULL;
 
69
    }
 
70
 
 
71
  if (cmp->prefix)
 
72
    {
 
73
      g_free (cmp->prefix);
 
74
      cmp->prefix = NULL;
 
75
    }
 
76
  
 
77
  it = items;
 
78
  while (it)
 
79
    {
 
80
      cmp->items = g_list_prepend (cmp->items, it->data);
 
81
      it = it->next;
 
82
    }
 
83
}
 
84
 
 
85
void 
 
86
g_completion_remove_items (GCompletion* cmp,
 
87
                           GList*       items)
 
88
{
 
89
  GList* it;
 
90
  
 
91
  g_return_if_fail (cmp != NULL);
 
92
  
 
93
  it = items;
 
94
  while (cmp->items && it)
 
95
    {
 
96
      cmp->items = g_list_remove (cmp->items, it->data);
 
97
      it = it->next;
 
98
    }
 
99
 
 
100
  it = items;
 
101
  while (cmp->cache && it)
 
102
    {
 
103
      cmp->cache = g_list_remove(cmp->cache, it->data);
 
104
      it = it->next;
 
105
    }
 
106
}
 
107
 
 
108
void 
 
109
g_completion_clear_items (GCompletion* cmp)
 
110
{
 
111
  g_return_if_fail (cmp != NULL);
 
112
  
 
113
  g_list_free (cmp->items);
 
114
  cmp->items = NULL;
 
115
  g_list_free (cmp->cache);
 
116
  cmp->cache = NULL;
 
117
  g_free (cmp->prefix);
 
118
  cmp->prefix = NULL;
 
119
}
 
120
 
 
121
static void   
 
122
completion_check_cache (GCompletion* cmp,
 
123
                        gchar**      new_prefix)
 
124
{
 
125
  register GList* list;
 
126
  register gsize len;  
 
127
  register gsize i;
 
128
  register gsize plen;
 
129
  gchar* postfix;
 
130
  gchar* s;
 
131
  
 
132
  if (!new_prefix)
 
133
    return;
 
134
  if (!cmp->cache)
 
135
    {
 
136
      *new_prefix = NULL;
 
137
      return;
 
138
    }
 
139
  
 
140
  len = strlen(cmp->prefix);
 
141
  list = cmp->cache;
 
142
  s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
 
143
  postfix = s + len;
 
144
  plen = strlen (postfix);
 
145
  list = list->next;
 
146
  
 
147
  while (list && plen)
 
148
    {
 
149
      s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
 
150
      s += len;
 
151
      for (i = 0; i < plen; ++i)
 
152
        {
 
153
          if (postfix[i] != s[i])
 
154
            break;
 
155
        }
 
156
      plen = i;
 
157
      list = list->next;
 
158
    }
 
159
  
 
160
  *new_prefix = g_new0 (gchar, len + plen + 1);
 
161
  strncpy (*new_prefix, cmp->prefix, len);
 
162
  strncpy (*new_prefix + len, postfix, plen);
 
163
}
 
164
 
 
165
/**
 
166
 * g_completion_complete_utf8:
 
167
 * @cmp: the #GCompletion
 
168
 * @prefix: the prefix string, typically used by the user, which is compared
 
169
 *    with each of the items
 
170
 * @new_prefix: if non-%NULL, returns the longest prefix which is common to all
 
171
 *    items that matched @prefix, or %NULL if no items matched @prefix.
 
172
 *    This string should be freed when no longer needed.
 
173
 *
 
174
 * Attempts to complete the string @prefix using the #GCompletion target items.
 
175
 * In contrast to g_completion_complete(), this function returns the largest common
 
176
 * prefix that is a valid UTF-8 string, omitting a possible common partial 
 
177
 * character.
 
178
 *
 
179
 * You should use this function instead of g_completion_complete() if your 
 
180
 * items are UTF-8 strings.
 
181
 *
 
182
 * Return value: the list of items whose strings begin with @prefix. This should
 
183
 * not be changed.
 
184
 *
 
185
 * Since: 2.4
 
186
 **/
 
187
GList*
 
188
g_completion_complete_utf8 (GCompletion  *cmp,
 
189
                            const gchar  *prefix,
 
190
                            gchar       **new_prefix)
 
191
{
 
192
  GList *list;
 
193
  gchar *p, *q;
 
194
 
 
195
  list = g_completion_complete (cmp, prefix, new_prefix);
 
196
 
 
197
  if (new_prefix && *new_prefix)
 
198
    {
 
199
      p = *new_prefix + strlen (*new_prefix);
 
200
      q = g_utf8_find_prev_char (*new_prefix, p);
 
201
      
 
202
      switch (g_utf8_get_char_validated (q, p - q))
 
203
        {
 
204
        case (gunichar)-2:
 
205
        case (gunichar)-1:
 
206
          *q = 0;
 
207
          break;
 
208
        default: ;
 
209
        }
 
210
 
 
211
    }
 
212
 
 
213
  return list;
 
214
}
 
215
 
 
216
GList* 
 
217
g_completion_complete (GCompletion* cmp,
 
218
                       const gchar* prefix,
 
219
                       gchar**      new_prefix)
 
220
{
 
221
  gsize plen, len;
 
222
  gboolean done = FALSE;
 
223
  GList* list;
 
224
  
 
225
  g_return_val_if_fail (cmp != NULL, NULL);
 
226
  g_return_val_if_fail (prefix != NULL, NULL);
 
227
  
 
228
  len = strlen (prefix);
 
229
  if (cmp->prefix && cmp->cache)
 
230
    {
 
231
      plen = strlen (cmp->prefix);
 
232
      if (plen <= len && ! cmp->strncmp_func (prefix, cmp->prefix, plen))
 
233
        { 
 
234
          /* use the cache */
 
235
          list = cmp->cache;
 
236
          while (list)
 
237
            {
 
238
              GList *next = list->next;
 
239
              
 
240
              if (cmp->strncmp_func (prefix,
 
241
                                     cmp->func ? cmp->func (list->data) : (gchar*) list->data,
 
242
                                     len))
 
243
                cmp->cache = g_list_delete_link (cmp->cache, list);
 
244
 
 
245
              list = next;
 
246
            }
 
247
          done = TRUE;
 
248
        }
 
249
    }
 
250
  
 
251
  if (!done)
 
252
    {
 
253
      /* normal code */
 
254
      g_list_free (cmp->cache);
 
255
      cmp->cache = NULL;
 
256
      list = cmp->items;
 
257
      while (*prefix && list)
 
258
        {
 
259
          if (!cmp->strncmp_func (prefix,
 
260
                        cmp->func ? cmp->func (list->data) : (gchar*) list->data,
 
261
                        len))
 
262
            cmp->cache = g_list_prepend (cmp->cache, list->data);
 
263
          list = list->next;
 
264
        }
 
265
    }
 
266
  if (cmp->prefix)
 
267
    {
 
268
      g_free (cmp->prefix);
 
269
      cmp->prefix = NULL;
 
270
    }
 
271
  if (cmp->cache)
 
272
    cmp->prefix = g_strdup (prefix);
 
273
  completion_check_cache (cmp, new_prefix);
 
274
  
 
275
  return *prefix ? cmp->cache : cmp->items;
 
276
}
 
277
 
 
278
void 
 
279
g_completion_free (GCompletion* cmp)
 
280
{
 
281
  g_return_if_fail (cmp != NULL);
 
282
  
 
283
  g_completion_clear_items (cmp);
 
284
  g_free (cmp);
 
285
}
 
286
 
 
287
void
 
288
g_completion_set_compare(GCompletion *cmp,
 
289
                         GCompletionStrncmpFunc strncmp_func)
 
290
{
 
291
  cmp->strncmp_func = strncmp_func;
 
292
}
 
293
 
 
294
#ifdef TEST_COMPLETION
 
295
#include <stdio.h>
 
296
int
 
297
main (int   argc,
 
298
      char* argv[])
 
299
{
 
300
  FILE *file;
 
301
  gchar buf[1024];
 
302
  GList *list;
 
303
  GList *result;
 
304
  GList *tmp;
 
305
  GCompletion *cmp;
 
306
  gint i;
 
307
  gchar *longp = NULL;
 
308
  
 
309
  if (argc < 3)
 
310
    {
 
311
      g_warning ("Usage: %s filename prefix1 [prefix2 ...]\n", argv[0]);
 
312
      return 1;
 
313
    }
 
314
  
 
315
  file = fopen (argv[1], "r");
 
316
  if (!file)
 
317
    {
 
318
      g_warning ("Cannot open %s\n", argv[1]);
 
319
      return 1;
 
320
    }
 
321
  
 
322
  cmp = g_completion_new (NULL);
 
323
  list = g_list_alloc ();
 
324
  while (fgets (buf, 1024, file))
 
325
    {
 
326
      list->data = g_strdup (buf);
 
327
      g_completion_add_items (cmp, list);
 
328
    }
 
329
  fclose (file);
 
330
  
 
331
  for (i = 2; i < argc; ++i)
 
332
    {
 
333
      printf ("COMPLETING: %s\n", argv[i]);
 
334
      result = g_completion_complete (cmp, argv[i], &longp);
 
335
      g_list_foreach (result, (GFunc) printf, NULL);
 
336
      printf ("LONG MATCH: %s\n", longp);
 
337
      g_free (longp);
 
338
      longp = NULL;
 
339
    }
 
340
  
 
341
  g_list_foreach (cmp->items, (GFunc) g_free, NULL);
 
342
  g_completion_free (cmp);
 
343
  g_list_free (list);
 
344
  
 
345
  return 0;
 
346
}
 
347
#endif
 
348
 
 
349
#define __G_COMPLETION_C__
 
350
#include "galiasdef.c"