From 2974c3715450fe426d18e9cfd07bf2b4f4f30b9f Mon Sep 17 00:00:00 2001 From: Jose Antonio Ortega Ruiz Date: Mon, 6 Jan 2014 04:29:29 +0100 Subject: Incorporating gcompletion (fixes #39817) --- mixlib/Makefile.am | 10 +- mixlib/completion.c | 503 +++++++++++++++++++++++++++++++++++++++++++++++ mixlib/completion.h | 73 +++++++ mixlib/mix_vm_command.c | 25 +-- mixlib/mix_vm_command.h | 3 +- mixlib/xmix_vm_command.h | 6 +- 6 files changed, 597 insertions(+), 23 deletions(-) create mode 100644 mixlib/completion.c create mode 100644 mixlib/completion.h diff --git a/mixlib/Makefile.am b/mixlib/Makefile.am index 8b7160e..b38af6d 100644 --- a/mixlib/Makefile.am +++ b/mixlib/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -# Copyright (C) 2000, 2001, 2006 Free Software Foundation, Inc. +# Copyright (C) 2000, 2001, 2006, 2014 Free Software Foundation, Inc. # # This file is free software; as a special exception the author gives # unlimited permission to copy and/or distribute it, with or without @@ -15,7 +15,9 @@ SUBDIRS = testsuite INCLUDES = -I$(includedir) -I$(top_srcdir) -DG_LOG_DOMAIN=\"libmix\" noinst_LIBRARIES = libmix.a -libmix_a_SOURCES = gettext.h mix.h mix.c \ +libmix_a_SOURCES = gettext.h \ + completion.h completion.c \ + mix.h mix.c \ mix_types.h mix_types.c \ mix_ins.h mix_ins.c \ mix_vm.h mix_vm.c xmix_vm.h xmix_vm.c \ @@ -35,7 +37,3 @@ libmix_a_SOURCES = gettext.h mix.h mix.c \ mix_config.c mix_config.h \ mix_predicate.c mix_predicate.h \ mix_predicate_list.c mix_predicate_list.h - - - - diff --git a/mixlib/completion.c b/mixlib/completion.c new file mode 100644 index 0000000..630708b --- /dev/null +++ b/mixlib/completion.c @@ -0,0 +1,503 @@ +/* Adapted from GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +/* + * Modified by Jose Antonio Ortega Ruiz 2014, for inclusion in MDK due + * to deprecation in new versions of Glib. Only changes are renaming + * GCompletion to Completion and g_completion to completion. + */ + +/* + * MT safe + */ + +#include "config.h" + +#include "completion.h" + +#include +#include + +/** + * SECTION:completion + * @title: Automatic String Completion + * @short_description: support for automatic completion using a group + * of target strings + * + * #Completion provides support for automatic completion of a string + * using any group of target strings. It is typically used for file + * name completion as is common in many UNIX shells. + * + * A #Completion is created using completion_new(). Target items are + * added and removed with completion_add_items(), + * completion_remove_items() and completion_clear_items(). A + * completion attempt is requested with completion_complete() or + * completion_complete_utf8(). When no longer needed, the + * #Completion is freed with completion_free(). + * + * Items in the completion can be simple strings (e.g. filenames), or + * pointers to arbitrary data structures. If data structures are used + * you must provide a #CompletionFunc in completion_new(), which + * retrieves the item's string from the data structure. You can change + * the way in which strings are compared by setting a different + * #CompletionStrncmpFunc in completion_set_compare(). + * + * Completion has been marked as deprecated, since this API is rarely + * used and not very actively maintained. + **/ + +/** + * Completion: + * @items: list of target items (strings or data structures). + * @func: function which is called to get the string associated with a + * target item. It is %NULL if the target items are strings. + * @prefix: the last prefix passed to completion_complete() or + * completion_complete_utf8(). + * @cache: the list of items which begin with @prefix. + * @strncmp_func: The function to use when comparing strings. Use + * completion_set_compare() to modify this function. + * + * The data structure used for automatic completion. + **/ + +/** + * CompletionFunc: + * @Param1: the completion item. + * + * Specifies the type of the function passed to completion_new(). It + * should return the string corresponding to the given target item. + * This is used when you use data structures as #Completion items. + * + * Returns: the string corresponding to the item. + **/ + +/** + * CompletionStrncmpFunc: + * @s1: string to compare with @s2. + * @s2: string to compare with @s1. + * @n: maximal number of bytes to compare. + * + * Specifies the type of the function passed to + * completion_set_compare(). This is used when you use strings as + * #Completion items. + * + * Returns: an integer less than, equal to, or greater than zero if + * the first @n bytes of @s1 is found, respectively, to be + * less than, to match, or to be greater than the first @n + * bytes of @s2. + **/ + +static void completion_check_cache (Completion* cmp, + gchar** new_prefix); + +/** + * completion_new: + * @func: the function to be called to return the string representing + * an item in the #Completion, or %NULL if strings are going to + * be used as the #Completion items. + * + * Creates a new #Completion. + * + * Returns: the new #Completion. + **/ +Completion* +completion_new (CompletionFunc func) +{ + Completion* gcomp; + + gcomp = g_new (Completion, 1); + gcomp->items = NULL; + gcomp->cache = NULL; + gcomp->prefix = NULL; + gcomp->func = func; + gcomp->strncmp_func = strncmp; + + return gcomp; +} + +/** + * completion_add_items: + * @cmp: the #Completion. + * @items: (transfer none): the list of items to add. + * + * Adds items to the #Completion. + * + * Deprecated: 2.26: Rarely used API + **/ +void +completion_add_items (Completion* cmp, + GList* items) +{ + GList* it; + + g_return_if_fail (cmp != NULL); + + /* optimize adding to cache? */ + if (cmp->cache) + { + g_list_free (cmp->cache); + cmp->cache = NULL; + } + + if (cmp->prefix) + { + g_free (cmp->prefix); + cmp->prefix = NULL; + } + + it = items; + while (it) + { + cmp->items = g_list_prepend (cmp->items, it->data); + it = it->next; + } +} + +/** + * completion_remove_items: + * @cmp: the #Completion. + * @items: (transfer none): the items to remove. + * + * Removes items from a #Completion. The items are not freed, so if the memory + * was dynamically allocated, free @items with g_list_free_full() after calling + * this function. + * + * Deprecated: 2.26: Rarely used API + **/ +void +completion_remove_items (Completion* cmp, + GList* items) +{ + GList* it; + + g_return_if_fail (cmp != NULL); + + it = items; + while (cmp->items && it) + { + cmp->items = g_list_remove (cmp->items, it->data); + it = it->next; + } + + it = items; + while (cmp->cache && it) + { + cmp->cache = g_list_remove(cmp->cache, it->data); + it = it->next; + } +} + +/** + * completion_clear_items: + * @cmp: the #Completion. + * + * Removes all items from the #Completion. The items are not freed, so if the + * memory was dynamically allocated, it should be freed after calling this + * function. + * + * Deprecated: 2.26: Rarely used API + **/ +void +completion_clear_items (Completion* cmp) +{ + g_return_if_fail (cmp != NULL); + + g_list_free (cmp->items); + cmp->items = NULL; + g_list_free (cmp->cache); + cmp->cache = NULL; + g_free (cmp->prefix); + cmp->prefix = NULL; +} + +static void +completion_check_cache (Completion* cmp, + gchar** new_prefix) +{ + register GList* list; + register gsize len; + register gsize i; + register gsize plen; + gchar* postfix; + gchar* s; + + if (!new_prefix) + return; + if (!cmp->cache) + { + *new_prefix = NULL; + return; + } + + len = strlen(cmp->prefix); + list = cmp->cache; + s = cmp->func ? cmp->func (list->data) : (gchar*) list->data; + postfix = s + len; + plen = strlen (postfix); + list = list->next; + + while (list && plen) + { + s = cmp->func ? cmp->func (list->data) : (gchar*) list->data; + s += len; + for (i = 0; i < plen; ++i) + { + if (postfix[i] != s[i]) + break; + } + plen = i; + list = list->next; + } + + *new_prefix = g_new0 (gchar, len + plen + 1); + strncpy (*new_prefix, cmp->prefix, len); + strncpy (*new_prefix + len, postfix, plen); +} + +/** + * completion_complete_utf8: + * @cmp: the #Completion + * @prefix: the prefix string, typically used by the user, which is compared + * with each of the items + * @new_prefix: if non-%NULL, returns the longest prefix which is common to all + * items that matched @prefix, or %NULL if no items matched @prefix. + * This string should be freed when no longer needed. + * + * Attempts to complete the string @prefix using the #Completion target items. + * In contrast to completion_complete(), this function returns the largest common + * prefix that is a valid UTF-8 string, omitting a possible common partial + * character. + * + * You should use this function instead of completion_complete() if your + * items are UTF-8 strings. + * + * Return value: (element-type utf8) (transfer none): the list of items whose strings begin with @prefix. This should + * not be changed. + * + * Since: 2.4 + * + * Deprecated: 2.26: Rarely used API + **/ +GList* +completion_complete_utf8 (Completion *cmp, + const gchar *prefix, + gchar **new_prefix) +{ + GList *list; + gchar *p, *q; + + list = completion_complete (cmp, prefix, new_prefix); + + if (new_prefix && *new_prefix) + { + p = *new_prefix + strlen (*new_prefix); + q = g_utf8_find_prev_char (*new_prefix, p); + + switch (g_utf8_get_char_validated (q, p - q)) + { + case (gunichar)-2: + case (gunichar)-1: + *q = 0; + break; + default: ; + } + + } + + return list; +} + +/** + * completion_complete: + * @cmp: the #Completion. + * @prefix: the prefix string, typically typed by the user, which is + * compared with each of the items. + * @new_prefix: if non-%NULL, returns the longest prefix which is + * common to all items that matched @prefix, or %NULL if + * no items matched @prefix. This string should be freed + * when no longer needed. + * + * Attempts to complete the string @prefix using the #Completion + * target items. + * + * Returns: (transfer none): the list of items whose strings begin with + * @prefix. This should not be changed. + * + * Deprecated: 2.26: Rarely used API + **/ +GList* +completion_complete (Completion* cmp, + const gchar* prefix, + gchar** new_prefix) +{ + gsize plen, len; + gboolean done = FALSE; + GList* list; + + g_return_val_if_fail (cmp != NULL, NULL); + g_return_val_if_fail (prefix != NULL, NULL); + + len = strlen (prefix); + if (cmp->prefix && cmp->cache) + { + plen = strlen (cmp->prefix); + if (plen <= len && ! cmp->strncmp_func (prefix, cmp->prefix, plen)) + { + /* use the cache */ + list = cmp->cache; + while (list) + { + GList *next = list->next; + + if (cmp->strncmp_func (prefix, + cmp->func ? cmp->func (list->data) : (gchar*) list->data, + len)) + cmp->cache = g_list_delete_link (cmp->cache, list); + + list = next; + } + done = TRUE; + } + } + + if (!done) + { + /* normal code */ + g_list_free (cmp->cache); + cmp->cache = NULL; + list = cmp->items; + while (*prefix && list) + { + if (!cmp->strncmp_func (prefix, + cmp->func ? cmp->func (list->data) : (gchar*) list->data, + len)) + cmp->cache = g_list_prepend (cmp->cache, list->data); + list = list->next; + } + } + if (cmp->prefix) + { + g_free (cmp->prefix); + cmp->prefix = NULL; + } + if (cmp->cache) + cmp->prefix = g_strdup (prefix); + completion_check_cache (cmp, new_prefix); + + return *prefix ? cmp->cache : cmp->items; +} + +/** + * completion_free: + * @cmp: the #Completion. + * + * Frees all memory used by the #Completion. The items are not freed, so if + * the memory was dynamically allocated, it should be freed after calling this + * function. + * + * Deprecated: 2.26: Rarely used API + **/ +void +completion_free (Completion* cmp) +{ + g_return_if_fail (cmp != NULL); + + completion_clear_items (cmp); + g_free (cmp); +} + +/** + * completion_set_compare: + * @cmp: a #Completion. + * @strncmp_func: the string comparison function. + * + * Sets the function to use for string comparisons. The default string + * comparison function is strncmp(). + * + * Deprecated: 2.26: Rarely used API + **/ +void +completion_set_compare(Completion *cmp, + CompletionStrncmpFunc strncmp_func) +{ + cmp->strncmp_func = strncmp_func; +} + +#ifdef TEST_COMPLETION +#include +int +main (int argc, + char* argv[]) +{ + FILE *file; + gchar buf[1024]; + GList *list; + GList *result; + GList *tmp; + Completion *cmp; + gint i; + gchar *longp = NULL; + + if (argc < 3) + { + g_warning ("Usage: %s filename prefix1 [prefix2 ...]\n", argv[0]); + return 1; + } + + file = fopen (argv[1], "r"); + if (!file) + { + g_warning ("Cannot open %s\n", argv[1]); + return 1; + } + + cmp = completion_new (NULL); + list = g_list_alloc (); + while (fgets (buf, 1024, file)) + { + list->data = g_strdup (buf); + completion_add_items (cmp, list); + } + fclose (file); + + for (i = 2; i < argc; ++i) + { + printf ("COMPLETING: %s\n", argv[i]); + result = completion_complete (cmp, argv[i], &longp); + g_list_foreach (result, (GFunc) printf, NULL); + printf ("LONG MATCH: %s\n", longp); + g_free (longp); + longp = NULL; + } + + g_list_foreach (cmp->items, (GFunc) g_free, NULL); + completion_free (cmp); + g_list_free (list); + + return 0; +} + +#endif diff --git a/mixlib/completion.h b/mixlib/completion.h new file mode 100644 index 0000000..271543b --- /dev/null +++ b/mixlib/completion.h @@ -0,0 +1,73 @@ +/* Adapted from GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +/* + * Modified by Jose Antonio Ortega Ruiz 2014, for inclusion in MDK due + * to deprecation in new versions of Glib. Only changes are renaming + * GCompletion to Completion and g_completion to completion. + */ + +#ifndef __COMPLETION_H__ +#define __COMPLETION_H__ + +#include + +typedef struct _Completion Completion; + +typedef gchar* (*CompletionFunc) (gpointer); + +/* Completion + */ + +typedef gint (*CompletionStrncmpFunc) (const gchar *s1, + const gchar *s2, + gsize n); + +struct _Completion +{ + GList* items; + CompletionFunc func; + + gchar* prefix; + GList* cache; + CompletionStrncmpFunc strncmp_func; +}; + +Completion* completion_new (CompletionFunc func); +void completion_add_items (Completion* cmp, GList* items); +void completion_remove_items (Completion* cmp, GList* items); +void completion_clear_items (Completion* cmp); +GList* completion_complete (Completion* cmp, + const gchar* prefix, + gchar** new_prefix); +GList* completion_complete_utf8 (Completion *cmp, + const gchar* prefix, + gchar** new_prefix); +void completion_set_compare (Completion *cmp, + CompletionStrncmpFunc strncmp_func); +void completion_free (Completion* cmp); + +#endif /* __COMPLETION_H__ */ diff --git a/mixlib/mix_vm_command.c b/mixlib/mix_vm_command.c index e144d30..e91d67a 100644 --- a/mixlib/mix_vm_command.c +++ b/mixlib/mix_vm_command.c @@ -1,7 +1,7 @@ /* -*-c-*- -------------- mix_vm_command.c : * Implementation of the functions declared in mix_vm_command.h * ------------------------------------------------------------------ - * Copyright (C) 2001, 2002, 2004, 2006, 2007 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2004, 2006, 2007, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,13 +15,15 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. * */ #include "xmix_vm_command.h" #include "xmix_vm_handlers.h" +#include "completion.h" #ifdef HAVE_LIBHISTORY # include @@ -91,16 +93,16 @@ mix_vm_command_usage (mix_vm_command_t cmd) } /* create a new command dispatcher */ -static GCompletion * +static Completion * make_completions_ (void) { GList *cmds = NULL; gint k; - GCompletion *completions = g_completion_new (NULL); + Completion *completions = completion_new (NULL); for (k = 0; k < MIX_CMD_INVALID; ++k) cmds = g_list_append (cmds, (gpointer) mix_vm_command_to_string (k)); - g_completion_add_items (completions, cmds); + completion_add_items (completions, cmds); return completions; } @@ -239,7 +241,7 @@ mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis) g_hash_table_foreach_remove (dis->mem_preds, del_pred_, NULL); g_hash_table_destroy (dis->mem_preds); g_hash_table_destroy (dis->commands); - g_completion_free (dis->completions); + completion_free (dis->completions); for (k = 0; k < MIX_CMD_INVALID; ++k) { del_hook_list_ (dis->pre_hooks[k]); @@ -260,7 +262,7 @@ mix_vm_cmd_dispatcher_register_new (mix_vm_cmd_dispatcher_t *dis, g_return_if_fail (cmd != NULL); g_hash_table_insert (dis->commands, (gpointer)cmd->name, (gpointer)cmd); list = g_list_append (list, (gpointer)cmd->name); - g_completion_add_items (dis->completions, list); + completion_add_items (dis->completions, list); } const GList * @@ -274,7 +276,7 @@ mix_vm_cmd_dispatcher_complete (const mix_vm_cmd_dispatcher_t *dis, g_return_val_if_fail (cmd != NULL, NULL); cp = g_strdup (cmd); - result = g_completion_complete (dis->completions, cp, prefix); + result = completion_complete (dis->completions, cp, prefix); g_free (cp); return result; } @@ -633,11 +635,10 @@ mix_vm_cmd_dispatcher_get_src_file_line (const mix_vm_cmd_dispatcher_t *dis, { enum {BUFF_SIZE = 256}; static gchar BUFFER[BUFF_SIZE]; - int len = - g_snprintf (BUFFER, BUFF_SIZE, "%s", mix_src_file_get_line (file, line)); + int len = g_snprintf (BUFFER, BUFF_SIZE, + "%s", + mix_src_file_get_line (file, line)); if (len > 0 && BUFFER[len - 1] == '\n') BUFFER[len - 1] = '\0'; return BUFFER; } } - - diff --git a/mixlib/mix_vm_command.h b/mixlib/mix_vm_command.h index 65b78e9..bd5fb19 100644 --- a/mixlib/mix_vm_command.h +++ b/mixlib/mix_vm_command.h @@ -1,7 +1,7 @@ /* -*-c-*- ---------------- mix_vm_command.h : * declarations for mix_vm_command_t, describing commands issued to a vm * ------------------------------------------------------------------ - * Copyright (C) 2001, 2006, 2007 Free Software Foundation, Inc. + * Copyright (C) 2001, 2006, 2007, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -251,4 +251,3 @@ mix_vm_cmd_dispatcher_get_vm (const mix_vm_cmd_dispatcher_t *dis); #endif /* MIX_VM_COMMAND_H */ - diff --git a/mixlib/xmix_vm_command.h b/mixlib/xmix_vm_command.h index 8a6afae..95369aa 100644 --- a/mixlib/xmix_vm_command.h +++ b/mixlib/xmix_vm_command.h @@ -1,7 +1,7 @@ /* -*-c-*- ---------------- xmix_vm_command.h : * Private type declarations form mix_vm_command * ------------------------------------------------------------------ - * Copyright (C) 2001, 2004, 2007 Free Software Foundation, Inc. + * Copyright (C) 2001, 2004, 2007, 2014 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,6 +36,7 @@ #include "mix_eval.h" #include "mix_predicate.h" #include "mix_vm_command.h" +#include "completion.h" /* configuration keys */ @@ -77,7 +78,7 @@ struct mix_vm_cmd_dispatcher_t mix_time_t laptime; /* last run time */ mix_time_t progtime; /* current program running time */ GHashTable *commands; /* local commands */ - GCompletion *completions; /* command completion list */ + Completion *completions; /* command completion list */ GSList *pre_hooks[HOOKNO_]; /* Pre-command hooks */ GSList *post_hooks[HOOKNO_]; /* Post-command hooks */ GSList *global_pre; /* global pre-command hook */ @@ -97,4 +98,3 @@ log_error_ (mix_vm_cmd_dispatcher_t *dis, const gchar *fmt, ...); #define wants_logs_(dis) (dis)->log_msg #endif /* XMIX_VM_COMMAND_H */ - -- cgit v1.2.3