/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 |