*** empty log message ***
[arla.git] / lib / editline / complete.c
blob9dfa582cc26130443251533aee4757bb1f578282
1 /* Copyright 1992 Simmule Turner and Rich Salz. All rights reserved.
3 * This software is not subject to any license of the American Telephone
4 * and Telegraph Company or of the Regents of the University of California.
6 * Permission is granted to anyone to use this software for any purpose on
7 * any computer system, and to alter it and redistribute it freely, subject
8 * to the following restrictions:
9 * 1. The authors are not responsible for the consequences of use of this
10 * software, no matter how awful, even if they arise from flaws in it.
11 * 2. The origin of this software must not be misrepresented, either by
12 * explicit claim or by omission. Since few users ever read sources,
13 * credits must appear in the documentation.
14 * 3. Altered versions must be plainly marked as such, and must not be
15 * misrepresented as being the original software. Since few users
16 * ever read sources, credits must appear in the documentation.
17 * 4. This notice may not be removed or altered.
21 ** History and file completion functions for editline library.
23 #include <config.h>
24 #include "editline.h"
26 RCSID("$Id$");
29 ** strcmp-like sorting predicate for qsort.
31 static int
32 compare(const void *p1, const void *p2)
34 const char **v1;
35 const char **v2;
37 v1 = (const char **)p1;
38 v2 = (const char **)p2;
39 return strcmp(*v1, *v2);
43 ** Fill in *avp with an array of names that match file, up to its length.
44 ** Ignore . and .. .
46 static int
47 FindMatches(char *dir, char *file, char ***avp)
49 char **av;
50 char **new;
51 char *p;
52 DIR *dp;
53 DIRENTRY *ep;
54 size_t ac;
55 size_t len;
57 if ((dp = opendir(dir)) == NULL)
58 return 0;
60 av = NULL;
61 ac = 0;
62 len = strlen(file);
63 while ((ep = readdir(dp)) != NULL) {
64 p = ep->d_name;
65 if (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')))
66 continue;
67 if (len && strncmp(p, file, len) != 0)
68 continue;
70 if ((ac % MEM_INC) == 0) {
71 if ((new = malloc(sizeof(char*) * (ac + MEM_INC))) == NULL)
72 break;
73 if (ac) {
74 memcpy(new, av, ac * sizeof (char **));
75 free(av);
77 *avp = av = new;
80 if ((av[ac] = strdup(p)) == NULL) {
81 if (ac == 0)
82 free(av);
83 break;
85 ac++;
88 /* Clean up and return. */
89 (void)closedir(dp);
90 if (ac)
91 qsort(av, ac, sizeof (char **), compare);
92 return ac;
96 ** Split a pathname into allocated directory and trailing filename parts.
98 static int SplitPath(char *path, char **dirpart, char **filepart)
100 static char DOT[] = ".";
101 char *dpart;
102 char *fpart;
104 if ((fpart = strrchr(path, '/')) == NULL) {
105 if ((dpart = strdup(DOT)) == NULL)
106 return -1;
107 if ((fpart = strdup(path)) == NULL) {
108 free(dpart);
109 return -1;
112 else {
113 if ((dpart = strdup(path)) == NULL)
114 return -1;
115 dpart[fpart - path] = '\0';
116 if ((fpart = strdup(++fpart)) == NULL) {
117 free(dpart);
118 return -1;
121 *dirpart = dpart;
122 *filepart = fpart;
123 return 0;
127 ** Attempt to complete the pathname, returning an allocated copy.
128 ** Fill in *unique if we completed it, or set it to 0 if ambiguous.
131 static char *
132 rl_complete_filename(char *pathname, int *unique)
134 char **av;
135 char *new;
136 char *p;
137 size_t ac;
138 size_t end;
139 size_t i;
140 size_t j;
141 size_t len;
142 char *s;
144 ac = rl_list_possib(pathname, &av);
145 if(ac == 0)
146 return NULL;
148 s = strrchr(pathname, '/');
149 if(s == NULL)
150 len = strlen(pathname);
151 else
152 len = strlen(s + 1);
154 p = NULL;
155 if (ac == 1) {
156 /* Exactly one match -- finish it off. */
157 *unique = 1;
158 j = strlen(av[0]) - len + 2;
159 if ((p = malloc(j + 1)) != NULL) {
160 memcpy(p, av[0] + len, j);
161 asprintf(&new, "%s%s", pathname, p);
162 if(new != NULL) {
163 rl_add_slash(new, p);
164 free(new);
168 else {
169 *unique = 0;
170 if (len) {
171 /* Find largest matching substring. */
172 for (i = len, end = strlen(av[0]); i < end; i++)
173 for (j = 1; j < ac; j++)
174 if (av[0][i] != av[j][i])
175 goto breakout;
176 breakout:
177 if (i > len) {
178 j = i - len + 1;
179 if ((p = malloc(j)) != NULL) {
180 memcpy(p, av[0] + len, j);
181 p[j - 1] = '\0';
187 /* Clean up and return. */
188 for (i = 0; i < ac; i++)
189 free(av[i]);
190 free(av);
191 return p;
194 static rl_complete_func_t complete_func = rl_complete_filename;
196 char *
197 rl_complete(char *pathname, int *unique)
199 return (*complete_func)(pathname, unique);
202 rl_complete_func_t
203 rl_set_complete_func(rl_complete_func_t func)
205 rl_complete_func_t old = complete_func;
206 complete_func = func;
207 return old;
212 ** Return all possible completions.
214 static int
215 rl_list_possib_filename(char *pathname, char ***avp)
217 char *dir;
218 char *file;
219 int ac;
221 if (SplitPath(pathname, &dir, &file) < 0)
222 return 0;
223 ac = FindMatches(dir, file, avp);
224 free(dir);
225 free(file);
226 return ac;
229 static rl_list_possib_func_t list_possib_func = rl_list_possib_filename;
232 rl_list_possib(char *pathname, char ***avp)
234 return (*list_possib_func)(pathname, avp);
237 rl_list_possib_func_t
238 rl_set_list_possib_func(rl_list_possib_func_t func)
240 rl_list_possib_func_t old = list_possib_func;
241 list_possib_func = func;
242 return old;