00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "glib.h"
00032 #include <string.h>
00033
00034 static void completion_check_cache (GCompletion* cmp,
00035 gchar** new_prefix);
00036
00037 GCompletion*
00038 g_completion_new (GCompletionFunc func)
00039 {
00040 GCompletion* gcomp;
00041
00042 gcomp = g_new (GCompletion, 1);
00043 gcomp->items = NULL;
00044 gcomp->cache = NULL;
00045 gcomp->prefix = NULL;
00046 gcomp->func = func;
00047
00048 return gcomp;
00049 }
00050
00051 void
00052 g_completion_add_items (GCompletion* cmp,
00053 GList* items)
00054 {
00055 GList* it;
00056
00057 g_return_if_fail (cmp != NULL);
00058 g_return_if_fail (items != NULL);
00059
00060
00061 if (cmp->cache)
00062 {
00063 g_list_free (cmp->cache);
00064 cmp->cache = NULL;
00065 }
00066
00067 if (cmp->prefix)
00068 {
00069 g_free (cmp->prefix);
00070 cmp->prefix = NULL;
00071 }
00072
00073 it = items;
00074 while (it)
00075 {
00076 cmp->items = g_list_prepend (cmp->items, it->data);
00077 it = it->next;
00078 }
00079 }
00080
00081 void
00082 g_completion_remove_items (GCompletion* cmp,
00083 GList* items)
00084 {
00085 GList* it;
00086
00087 g_return_if_fail (cmp != NULL);
00088 g_return_if_fail (items != NULL);
00089
00090 it = items;
00091 while (cmp->items && it)
00092 {
00093 cmp->items = g_list_remove (cmp->items, it->data);
00094 it = it->next;
00095 }
00096
00097 it = items;
00098 while (cmp->cache && it)
00099 {
00100 cmp->cache = g_list_remove(cmp->cache, it->data);
00101 it = it->next;
00102 }
00103 }
00104
00105 void
00106 g_completion_clear_items (GCompletion* cmp)
00107 {
00108 g_return_if_fail (cmp != NULL);
00109
00110 g_list_free (cmp->items);
00111 cmp->items = NULL;
00112 g_list_free (cmp->cache);
00113 cmp->cache = NULL;
00114 g_free (cmp->prefix);
00115 cmp->prefix = NULL;
00116 }
00117
00118 static void
00119 completion_check_cache (GCompletion* cmp,
00120 gchar** new_prefix)
00121 {
00122 register GList* list;
00123 register gint len;
00124 register gint i;
00125 register gint plen;
00126 gchar* postfix;
00127 gchar* s;
00128
00129 if (!new_prefix)
00130 return;
00131 if (!cmp->cache)
00132 {
00133 *new_prefix = NULL;
00134 return;
00135 }
00136
00137 len = strlen(cmp->prefix);
00138 list = cmp->cache;
00139 s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
00140 postfix = s + len;
00141 plen = strlen (postfix);
00142 list = list->next;
00143
00144 while (list && plen)
00145 {
00146 s = cmp->func ? cmp->func (list->data) : (gchar*) list->data;
00147 s += len;
00148 for (i = 0; i < plen; ++i)
00149 {
00150 if (postfix[i] != s[i])
00151 break;
00152 }
00153 plen = i;
00154 list = list->next;
00155 }
00156
00157 *new_prefix = g_new0 (gchar, len + plen + 1);
00158 strncpy (*new_prefix, cmp->prefix, len);
00159 strncpy (*new_prefix + len, postfix, plen);
00160 }
00161
00162 GList*
00163 g_completion_complete (GCompletion* cmp,
00164 gchar* prefix,
00165 gchar** new_prefix)
00166 {
00167 gint plen, len;
00168 gint done = 0;
00169 GList* list;
00170
00171 g_return_val_if_fail (cmp != NULL, NULL);
00172 g_return_val_if_fail (prefix != NULL, NULL);
00173
00174 len = strlen (prefix);
00175 if (cmp->prefix && cmp->cache)
00176 {
00177 plen = strlen (cmp->prefix);
00178 if (plen <= len && !strncmp (prefix, cmp->prefix, plen))
00179 {
00180
00181 list = cmp->cache;
00182 while (list)
00183 {
00184 if (strncmp (prefix,
00185 cmp->func ? cmp->func (list->data) : (gchar*) list->data,
00186 len))
00187 {
00188 list = g_list_remove_link (cmp->cache, list);
00189 if (list != cmp->cache)
00190 cmp->cache = list;
00191 }
00192 else
00193 list = list->next;
00194 }
00195 done = 1;
00196 }
00197 }
00198
00199 if (!done)
00200 {
00201
00202 g_list_free (cmp->cache);
00203 cmp->cache = NULL;
00204 list = cmp->items;
00205 while (*prefix && list)
00206 {
00207 if (!strncmp (prefix,
00208 cmp->func ? cmp->func (list->data) : (gchar*) list->data,
00209 len))
00210 cmp->cache = g_list_prepend (cmp->cache, list->data);
00211 list = list->next;
00212 }
00213 }
00214 if (cmp->prefix)
00215 {
00216 g_free (cmp->prefix);
00217 cmp->prefix = NULL;
00218 }
00219 if (cmp->cache)
00220 cmp->prefix = g_strdup (prefix);
00221 completion_check_cache (cmp, new_prefix);
00222
00223 return *prefix ? cmp->cache : cmp->items;
00224 }
00225
00226 void
00227 g_completion_free (GCompletion* cmp)
00228 {
00229 g_return_if_fail (cmp != NULL);
00230
00231 g_completion_clear_items (cmp);
00232 g_free (cmp);
00233 }
00234
00235 #ifdef TEST_COMPLETION
00236 #include <stdio.h>
00237 int
00238 main (int argc,
00239 char* argv[])
00240 {
00241 FILE *file;
00242 gchar buf[1024];
00243 GList *list;
00244 GList *result;
00245 GList *tmp;
00246 GCompletion *cmp;
00247 gint i;
00248 gchar *longp = NULL;
00249
00250 if (argc < 3)
00251 {
00252 g_warning ("Usage: %s filename prefix1 [prefix2 ...]\n", argv[0]);
00253 return 1;
00254 }
00255
00256 file = fopen (argv[1], "r");
00257 if (!file)
00258 {
00259 g_warning ("Cannot open %s\n", argv[1]);
00260 return 1;
00261 }
00262
00263 cmp = g_completion_new (NULL);
00264 list = g_list_alloc ();
00265 while (fgets (buf, 1024, file))
00266 {
00267 list->data = g_strdup (buf);
00268 g_completion_add_items (cmp, list);
00269 }
00270 fclose (file);
00271
00272 for (i = 2; i < argc; ++i)
00273 {
00274 printf ("COMPLETING: %s\n", argv[i]);
00275 result = g_completion_complete (cmp, argv[i], &longp);
00276 g_list_foreach (result, (GFunc) printf, NULL);
00277 printf ("LONG MATCH: %s\n", longp);
00278 g_free (longp);
00279 longp = NULL;
00280 }
00281
00282 g_list_foreach (cmp->items, (GFunc) g_free, NULL);
00283 g_completion_free (cmp);
00284 g_list_free (list);
00285
00286 return 0;
00287 }
00288 #endif