Coverage Report

Created: 2025-12-28 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gstreamer/subprojects/glib-2.86.3/glib/deprecated/gcompletion.c
Line
Count
Source
1
/* GLIB - Library of useful routines for C programming
2
 * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
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
/* we know we are deprecated here, no need for warnings */
34
#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
35
#define GLIB_DISABLE_DEPRECATION_WARNINGS
36
#endif
37
38
#include "gcompletion.h"
39
40
#include <glib/gstrfuncs.h>
41
#include <glib/gmessages.h>
42
#include <glib/gstdio.h>
43
#include <glib/gunicode.h>
44
45
#include <string.h>
46
47
/**
48
 * GCompletion:
49
 * @items: list of target items (strings or data structures).
50
 * @func: function which is called to get the string associated with a
51
 *        target item. It is %NULL if the target items are strings.
52
 * @prefix: the last prefix passed to g_completion_complete() or
53
 *          g_completion_complete_utf8().
54
 * @cache: the list of items which begin with @prefix.
55
 * @strncmp_func: The function to use when comparing strings.  Use
56
 *                g_completion_set_compare() to modify this function.
57
 *
58
 * `GCompletion` provides support for automatic completion of a string
59
 * using any group of target strings. It is typically used for file
60
 * name completion as is common in many UNIX shells.
61
 *
62
 * A `GCompletion` is created using [func@GLib.Completion.new]. Target items are
63
 * added and removed with [method@GLib.Completion.add_items],
64
 * [method@GLib.Completion.remove_items] and
65
 * [method@GLib.Completion.clear_items]. A completion attempt is requested with
66
 * [method@GLib.Completion.complete] or [method@GLib.Completion.complete_utf8].
67
 * When no longer needed, the `GCompletion` is freed with
68
 * [method@GLib.Completion.free].
69
 *
70
 * Items in the completion can be simple strings (e.g. filenames), or
71
 * pointers to arbitrary data structures. If data structures are used
72
 * you must provide a [type@GLib.CompletionFunc] in [func@GLib.Completion.new],
73
 * which retrieves the item’s string from the data structure. You can change
74
 * the way in which strings are compared by setting a different
75
 * [type@GLib.CompletionStrncmpFunc] in [method@GLib.Completion.set_compare].
76
 *
77
 * `GCompletion` has been marked as deprecated, since this API is rarely
78
 * used and not very actively maintained.
79
 *
80
 * Deprecated: 2.26: Rarely used API
81
 **/
82
83
/**
84
 * GCompletionFunc:
85
 * @item: the completion item.
86
 *
87
 * Specifies the type of the function passed to g_completion_new(). It
88
 * should return the string corresponding to the given target item.
89
 * This is used when you use data structures as #GCompletion items.
90
 *
91
 * Returns: the string corresponding to the item.
92
 * Deprecated: 2.26: Rarely used API
93
 **/
94
95
/**
96
 * GCompletionStrncmpFunc:
97
 * @s1: string to compare with @s2.
98
 * @s2: string to compare with @s1.
99
 * @n: maximal number of bytes to compare.
100
 *
101
 * Specifies the type of the function passed to
102
 * g_completion_set_compare(). This is used when you use strings as
103
 * #GCompletion items.
104
 *
105
 * Returns: an integer less than, equal to, or greater than zero if
106
 *          the first @n bytes of @s1 is found, respectively, to be
107
 *          less than, to match, or to be greater than the first @n
108
 *          bytes of @s2.
109
 * Deprecated: 2.26: Rarely used API
110
 **/
111
112
static void completion_check_cache (GCompletion* cmp,
113
            gchar**  new_prefix);
114
115
/**
116
 * g_completion_new:
117
 * @func: the function to be called to return the string representing
118
 *        an item in the #GCompletion, or %NULL if strings are going to
119
 *        be used as the #GCompletion items.
120
 *
121
 * Creates a new #GCompletion.
122
 *
123
 * Returns: the new #GCompletion.
124
 * Deprecated: 2.26: Rarely used API
125
 **/
126
GCompletion* 
127
g_completion_new (GCompletionFunc func)
128
0
{
129
0
  GCompletion* gcomp;
130
  
131
0
  gcomp = g_new (GCompletion, 1);
132
0
  gcomp->items = NULL;
133
0
  gcomp->cache = NULL;
134
0
  gcomp->prefix = NULL;
135
0
  gcomp->func = func;
136
0
  gcomp->strncmp_func = strncmp;
137
138
0
  return gcomp;
139
0
}
140
141
/**
142
 * g_completion_add_items:
143
 * @cmp: the #GCompletion.
144
 * @items: (transfer none): the list of items to add.
145
 *
146
 * Adds items to the #GCompletion.
147
 *
148
 * Deprecated: 2.26: Rarely used API
149
 **/
150
void 
151
g_completion_add_items (GCompletion* cmp,
152
      GList*       items)
153
0
{
154
0
  GList* it;
155
  
156
0
  g_return_if_fail (cmp != NULL);
157
  
158
  /* optimize adding to cache? */
159
0
  if (cmp->cache)
160
0
    {
161
0
      g_list_free (cmp->cache);
162
0
      cmp->cache = NULL;
163
0
    }
164
165
0
  if (cmp->prefix)
166
0
    {
167
0
      g_free (cmp->prefix);
168
0
      cmp->prefix = NULL;
169
0
    }
170
  
171
0
  it = items;
172
0
  while (it)
173
0
    {
174
0
      cmp->items = g_list_prepend (cmp->items, it->data);
175
0
      it = it->next;
176
0
    }
177
0
}
178
179
/**
180
 * g_completion_remove_items:
181
 * @cmp: the #GCompletion.
182
 * @items: (transfer none): the items to remove.
183
 *
184
 * Removes items from a #GCompletion. The items are not freed, so if the memory
185
 * was dynamically allocated, free @items with g_list_free_full() after calling
186
 * this function.
187
 *
188
 * Deprecated: 2.26: Rarely used API
189
 **/
190
void 
191
g_completion_remove_items (GCompletion* cmp,
192
         GList* items)
193
0
{
194
0
  GList* it;
195
  
196
0
  g_return_if_fail (cmp != NULL);
197
  
198
0
  it = items;
199
0
  while (cmp->items && it)
200
0
    {
201
0
      cmp->items = g_list_remove (cmp->items, it->data);
202
0
      it = it->next;
203
0
    }
204
205
0
  it = items;
206
0
  while (cmp->cache && it)
207
0
    {
208
0
      cmp->cache = g_list_remove(cmp->cache, it->data);
209
0
      it = it->next;
210
0
    }
211
0
}
212
213
/**
214
 * g_completion_clear_items:
215
 * @cmp: the #GCompletion.
216
 *
217
 * Removes all items from the #GCompletion. The items are not freed, so if the
218
 * memory was dynamically allocated, it should be freed after calling this
219
 * function.
220
 *
221
 * Deprecated: 2.26: Rarely used API
222
 **/
223
void 
224
g_completion_clear_items (GCompletion* cmp)
225
0
{
226
0
  g_return_if_fail (cmp != NULL);
227
  
228
0
  g_list_free (cmp->items);
229
0
  cmp->items = NULL;
230
0
  g_list_free (cmp->cache);
231
0
  cmp->cache = NULL;
232
0
  g_free (cmp->prefix);
233
0
  cmp->prefix = NULL;
234
0
}
235
236
static void   
237
completion_check_cache (GCompletion* cmp,
238
      gchar**      new_prefix)
239
0
{
240
0
  GList* list;
241
0
  gsize len;
242
0
  gsize i;
243
0
  gsize plen;
244
0
  gchar* postfix;
245
0
  gchar* s;
246
  
247
0
  if (!new_prefix)
248
0
    return;
249
0
  if (!cmp->cache)
250
0
    {
251
0
      *new_prefix = NULL;
252
0
      return;
253
0
    }
254
  
255
0
  len = strlen(cmp->prefix);
256
0
  list = cmp->cache;
257
0
  s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
258
0
  postfix = s + len;
259
0
  plen = strlen (postfix);
260
0
  list = list->next;
261
  
262
0
  while (list && plen)
263
0
    {
264
0
      s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
265
0
      s += len;
266
0
      for (i = 0; i < plen; ++i)
267
0
  {
268
0
    if (postfix[i] != s[i])
269
0
      break;
270
0
  }
271
0
      plen = i;
272
0
      list = list->next;
273
0
    }
274
  
275
0
  *new_prefix = g_new0 (gchar, len + plen + 1);
276
0
  strncpy (*new_prefix, cmp->prefix, len);
277
0
  strncpy (*new_prefix + len, postfix, plen);
278
0
}
279
280
/**
281
 * g_completion_complete_utf8:
282
 * @cmp: the #GCompletion
283
 * @prefix: the prefix string, typically used by the user, which is compared
284
 *    with each of the items
285
 * @new_prefix: if non-%NULL, returns the longest prefix which is common to all
286
 *    items that matched @prefix, or %NULL if no items matched @prefix.
287
 *    This string should be freed when no longer needed.
288
 *
289
 * Attempts to complete the string @prefix using the #GCompletion target items.
290
 * In contrast to g_completion_complete(), this function returns the largest common
291
 * prefix that is a valid UTF-8 string, omitting a possible common partial 
292
 * character.
293
 *
294
 * You should use this function instead of g_completion_complete() if your 
295
 * items are UTF-8 strings.
296
 *
297
 * Returns: (element-type utf8) (transfer none): the list of items whose strings begin with @prefix. This should
298
 * not be changed.
299
 *
300
 * Since: 2.4
301
 *
302
 * Deprecated: 2.26: Rarely used API
303
 **/
304
GList*
305
g_completion_complete_utf8 (GCompletion  *cmp,
306
          const gchar  *prefix,
307
          gchar       **new_prefix)
308
0
{
309
0
  GList *list;
310
0
  gchar *p, *q;
311
312
0
  list = g_completion_complete (cmp, prefix, new_prefix);
313
314
0
  if (new_prefix && *new_prefix)
315
0
    {
316
0
      p = *new_prefix + strlen (*new_prefix);
317
0
      q = g_utf8_find_prev_char (*new_prefix, p);
318
      
319
0
      switch (g_utf8_get_char_validated (q, p - q))
320
0
  {
321
0
  case (gunichar)-2:
322
0
  case (gunichar)-1:
323
0
    *q = 0;
324
0
    break;
325
0
  default: ;
326
0
  }
327
328
0
    }
329
330
0
  return list;
331
0
}
332
333
/**
334
 * g_completion_complete:
335
 * @cmp: the #GCompletion.
336
 * @prefix: the prefix string, typically typed by the user, which is
337
 *          compared with each of the items.
338
 * @new_prefix: if non-%NULL, returns the longest prefix which is
339
 *              common to all items that matched @prefix, or %NULL if
340
 *              no items matched @prefix.  This string should be freed
341
 *              when no longer needed.
342
 *
343
 * Attempts to complete the string @prefix using the #GCompletion
344
 * target items.
345
 *
346
 * Returns: (transfer none): the list of items whose strings begin with
347
 *          @prefix. This should not be changed.
348
 *
349
 * Deprecated: 2.26: Rarely used API
350
 **/
351
GList* 
352
g_completion_complete (GCompletion* cmp,
353
           const gchar* prefix,
354
           gchar**      new_prefix)
355
0
{
356
0
  gsize plen, len;
357
0
  gboolean done = FALSE;
358
0
  GList* list;
359
  
360
0
  g_return_val_if_fail (cmp != NULL, NULL);
361
0
  g_return_val_if_fail (prefix != NULL, NULL);
362
  
363
0
  len = strlen (prefix);
364
0
  if (cmp->prefix && cmp->cache)
365
0
    {
366
0
      plen = strlen (cmp->prefix);
367
0
      if (plen <= len && ! cmp->strncmp_func (prefix, cmp->prefix, plen))
368
0
  { 
369
    /* use the cache */
370
0
    list = cmp->cache;
371
0
    while (list)
372
0
      {
373
0
        GList *next = list->next;
374
        
375
0
        if (cmp->strncmp_func (prefix,
376
0
             cmp->func ? cmp->func (list->data) : (gchar*) list->data,
377
0
             len))
378
0
    cmp->cache = g_list_delete_link (cmp->cache, list);
379
380
0
        list = next;
381
0
      }
382
0
    done = TRUE;
383
0
  }
384
0
    }
385
  
386
0
  if (!done)
387
0
    {
388
      /* normal code */
389
0
      g_list_free (cmp->cache);
390
0
      cmp->cache = NULL;
391
0
      list = cmp->items;
392
0
      while (*prefix && list)
393
0
  {
394
0
    if (!cmp->strncmp_func (prefix,
395
0
      cmp->func ? cmp->func (list->data) : (gchar*) list->data,
396
0
      len))
397
0
      cmp->cache = g_list_prepend (cmp->cache, list->data);
398
0
    list = list->next;
399
0
  }
400
0
    }
401
0
  if (cmp->prefix)
402
0
    {
403
0
      g_free (cmp->prefix);
404
0
      cmp->prefix = NULL;
405
0
    }
406
0
  if (cmp->cache)
407
0
    cmp->prefix = g_strdup (prefix);
408
0
  completion_check_cache (cmp, new_prefix);
409
  
410
0
  return *prefix ? cmp->cache : cmp->items;
411
0
}
412
413
/**
414
 * g_completion_free:
415
 * @cmp: the #GCompletion.
416
 *
417
 * Frees all memory used by the #GCompletion. The items are not freed, so if
418
 * the memory was dynamically allocated, it should be freed after calling this
419
 * function.
420
 *
421
 * Deprecated: 2.26: Rarely used API
422
 **/
423
void 
424
g_completion_free (GCompletion* cmp)
425
0
{
426
0
  g_return_if_fail (cmp != NULL);
427
  
428
0
  g_completion_clear_items (cmp);
429
0
  g_free (cmp);
430
0
}
431
432
/**
433
 * g_completion_set_compare:
434
 * @cmp: a #GCompletion.
435
 * @strncmp_func: the string comparison function.
436
 *
437
 * Sets the function to use for string comparisons. The default string
438
 * comparison function is strncmp().
439
 *
440
 * Deprecated: 2.26: Rarely used API
441
 **/
442
void
443
g_completion_set_compare(GCompletion *cmp,
444
       GCompletionStrncmpFunc strncmp_func)
445
0
{
446
0
  cmp->strncmp_func = strncmp_func;
447
0
}
448
449
#ifdef TEST_COMPLETION
450
#include <stdio.h>
451
int
452
main (int   argc,
453
      char* argv[])
454
{
455
  FILE *file;
456
  gchar buf[1024];
457
  GList *list;
458
  GList *result;
459
  GList *tmp;
460
  GCompletion *cmp;
461
  gint i;
462
  gchar *longp = NULL;
463
  
464
  if (argc < 3)
465
    {
466
      g_warning ("Usage: %s filename prefix1 [prefix2 ...]",
467
                 (argc > 0) ? argv[0] : "gcompletion");
468
      return 1;
469
    }
470
  
471
  file = g_fopen (argv[1], "re");
472
  if (!file)
473
    {
474
      g_warning ("Cannot open %s", argv[1]);
475
      return 1;
476
    }
477
  
478
  cmp = g_completion_new (NULL);
479
  list = g_list_alloc ();
480
  while (fgets (buf, 1024, file))
481
    {
482
      list->data = g_strdup (buf);
483
      g_completion_add_items (cmp, list);
484
    }
485
  fclose (file);
486
  
487
  for (i = 2; i < argc; ++i)
488
    {
489
      printf ("COMPLETING: %s\n", argv[i]);
490
      result = g_completion_complete (cmp, argv[i], &longp);
491
      g_list_foreach (result, (GFunc) printf, NULL);
492
      printf ("LONG MATCH: %s\n", longp);
493
      g_free (longp);
494
      longp = NULL;
495
    }
496
  
497
  g_list_foreach (cmp->items, (GFunc) g_free, NULL);
498
  g_completion_free (cmp);
499
  g_list_free (list);
500
  
501
  return 0;
502
}
503
#endif