No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / editline / complete.c
blob7eaeeff863d2c86509d217f3e50691f84d78a8e7
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 "edit_locl.h"
26 __RCSID("$Heimdal: complete.c 15421 2005-06-16 18:41:28Z lha $"
27 "$NetBSD$");
30 ** strcmp-like sorting predicate for qsort.
32 static int
33 compare(const void *p1, const void *p2)
35 char * const *v1;
36 char * const *v2;
38 v1 = (char * const *)p1;
39 v2 = (char * const *)p2;
40 return strcmp(*v1, *v2);
44 ** Fill in *avp with an array of names that match file, up to its length.
45 ** Ignore . and .. .
47 static int
48 FindMatches(char *dir, char *file, char ***avp)
50 char **av;
51 char **new;
52 char *p;
53 DIR *dp;
54 DIRENTRY *ep;
55 size_t ac;
56 size_t len;
58 if ((dp = opendir(dir)) == NULL)
59 return 0;
61 av = NULL;
62 ac = 0;
63 len = strlen(file);
64 while ((ep = readdir(dp)) != NULL) {
65 p = ep->d_name;
66 if (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')))
67 continue;
68 if (len && strncmp(p, file, len) != 0)
69 continue;
71 if ((ac % MEM_INC) == 0) {
72 if ((new = malloc(sizeof(char*) * (ac + MEM_INC))) == NULL)
73 break;
74 if (ac) {
75 memcpy(new, av, ac * sizeof (char **));
76 free(av);
78 *avp = av = new;
81 if ((av[ac] = strdup(p)) == NULL) {
82 if (ac == 0)
83 free(av);
84 break;
86 ac++;
89 /* Clean up and return. */
90 (void)closedir(dp);
91 if (ac)
92 qsort(av, ac, sizeof (char **), compare);
93 return ac;
97 ** Split a pathname into allocated directory and trailing filename parts.
99 static int SplitPath(char *path, char **dirpart, char **filepart)
101 static char DOT[] = ".";
102 char *dpart;
103 char *fpart;
105 if ((fpart = strrchr(path, '/')) == NULL) {
106 if ((dpart = strdup(DOT)) == NULL)
107 return -1;
108 if ((fpart = strdup(path)) == NULL) {
109 free(dpart);
110 return -1;
113 else {
114 if ((dpart = strdup(path)) == NULL)
115 return -1;
116 dpart[fpart - path] = '\0';
117 if ((fpart = strdup(++fpart)) == NULL) {
118 free(dpart);
119 return -1;
122 *dirpart = dpart;
123 *filepart = fpart;
124 return 0;
128 ** Attempt to complete the pathname, returning an allocated copy.
129 ** Fill in *unique if we completed it, or set it to 0 if ambiguous.
132 static char *
133 rl_complete_filename(char *pathname, int *unique)
135 char **av;
136 char *new;
137 char *p;
138 size_t ac;
139 size_t end;
140 size_t i;
141 size_t j;
142 size_t len;
143 char *s;
145 ac = rl_list_possib(pathname, &av);
146 if(ac == 0)
147 return NULL;
149 s = strrchr(pathname, '/');
150 if(s == NULL)
151 len = strlen(pathname);
152 else
153 len = strlen(s + 1);
155 p = NULL;
156 if (ac == 1) {
157 /* Exactly one match -- finish it off. */
158 *unique = 1;
159 j = strlen(av[0]) - len + 2;
160 if ((p = malloc(j + 1)) != NULL) {
161 memcpy(p, av[0] + len, j);
162 asprintf(&new, "%s%s", pathname, p);
163 if(new != NULL) {
164 rl_add_slash(new, p, j + 1);
165 free(new);
169 else {
170 *unique = 0;
171 if (len) {
172 /* Find largest matching substring. */
173 for (i = len, end = strlen(av[0]); i < end; i++)
174 for (j = 1; j < ac; j++)
175 if (av[0][i] != av[j][i])
176 goto breakout;
177 breakout:
178 if (i > len) {
179 j = i - len + 1;
180 if ((p = malloc(j)) != NULL) {
181 memcpy(p, av[0] + len, j);
182 p[j - 1] = '\0';
188 /* Clean up and return. */
189 for (i = 0; i < ac; i++)
190 free(av[i]);
191 free(av);
192 return p;
195 static rl_complete_func_t complete_func = rl_complete_filename;
197 char *
198 rl_complete(char *pathname, int *unique)
200 return (*complete_func)(pathname, unique);
203 rl_complete_func_t
204 rl_set_complete_func(rl_complete_func_t func)
206 rl_complete_func_t old = complete_func;
207 complete_func = func;
208 return old;
213 ** Return all possible completions.
215 static int
216 rl_list_possib_filename(char *pathname, char ***avp)
218 char *dir;
219 char *file;
220 int ac;
222 if (SplitPath(pathname, &dir, &file) < 0)
223 return 0;
224 ac = FindMatches(dir, file, avp);
225 free(dir);
226 free(file);
227 return ac;
230 static rl_list_possib_func_t list_possib_func = rl_list_possib_filename;
233 rl_list_possib(char *pathname, char ***avp)
235 return (*list_possib_func)(pathname, avp);
238 rl_list_possib_func_t
239 rl_set_list_possib_func(rl_list_possib_func_t func)
241 rl_list_possib_func_t old = list_possib_func;
242 list_possib_func = func;
243 return old;