Fixes for /usr/xbin binaries bootstrap dir.
[minix3.git] / lib / editline / complete.c
blobe34c491b66904d592e26bda3a57045aaa8af2b2b
1 /* $Revision$
2 **
3 ** History and file completion functions for editline library.
4 */
5 #include "editline.h"
8 #if defined(NEED_STRDUP)
9 /*
10 ** Return an allocated copy of a string.
12 char *
13 strdup(p)
14 char *p;
16 char *new;
18 if ((new = NEW(char, strlen(p) + 1)) != NULL)
19 (void)strcpy(new, p);
20 return new;
22 #endif /* defined(NEED_STRDUP) */
25 ** strcmp-like sorting predicate for qsort.
27 STATIC int
28 compare(p1, p2)
29 CONST void *p1;
30 CONST void *p2;
32 CONST char **v1;
33 CONST char **v2;
35 v1 = (CONST char **)p1;
36 v2 = (CONST char **)p2;
37 return strcmp(*v1, *v2);
41 ** Fill in *avp with an array of names that match file, up to its length.
42 ** Ignore . and .. .
44 STATIC int
45 FindMatches(dir, file, avp)
46 char *dir;
47 char *file;
48 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;
57 SIZE_T choices;
58 SIZE_T total;
59 #define MAX_TOTAL (256 << sizeof(char *))
61 if ((dp = opendir(dir)) == NULL)
62 return 0;
64 av = NULL;
65 ac = 0;
66 len = strlen(file);
67 choices = 0;
68 total = 0;
69 while ((ep = readdir(dp)) != NULL) {
70 p = ep->d_name;
71 if (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')))
72 continue;
73 if (len && strncmp(p, file, len) != 0)
74 continue;
76 choices++;
77 if ((total += strlen(p)) > MAX_TOTAL) {
78 /* This is a bit too much. */
79 while (ac > 0) DISPOSE(av[--ac]);
80 continue;
83 if ((ac % MEM_INC) == 0) {
84 if ((new = NEW(char*, ac + MEM_INC)) == NULL) {
85 total = 0;
86 break;
88 if (ac) {
89 COPYFROMTO(new, av, ac * sizeof (char **));
90 DISPOSE(av);
92 *avp = av = new;
95 if ((av[ac] = strdup(p)) == NULL) {
96 if (ac == 0)
97 DISPOSE(av);
98 total = 0;
99 break;
101 ac++;
104 /* Clean up and return. */
105 (void)closedir(dp);
106 if (total > MAX_TOTAL) {
107 char many[sizeof(total) * 3];
108 p = many + sizeof(many);
109 *--p = '\0';
110 while (choices > 0) {
111 *--p = '0' + choices % 10;
112 choices /= 10;
114 while (p > many + sizeof(many) - 8) *--p = ' ';
115 if ((p = strdup(p)) != NULL) av[ac++] = p;
116 if ((p = strdup("choices")) != NULL) av[ac++] = p;
117 } else {
118 if (ac)
119 qsort(av, ac, sizeof (char **), compare);
121 return ac;
125 ** Split a pathname into allocated directory and trailing filename parts.
127 STATIC int
128 SplitPath(path, dirpart, filepart)
129 char *path;
130 char **dirpart;
131 char **filepart;
133 static char DOT[] = ".";
134 char *dpart;
135 char *fpart;
137 if ((fpart = strrchr(path, '/')) == NULL) {
138 if ((dpart = strdup(DOT)) == NULL)
139 return -1;
140 if ((fpart = strdup(path)) == NULL) {
141 DISPOSE(dpart);
142 return -1;
145 else {
146 if ((dpart = strdup(path)) == NULL)
147 return -1;
148 dpart[fpart - path + 1] = '\0';
149 if ((fpart = strdup(++fpart)) == NULL) {
150 DISPOSE(dpart);
151 return -1;
154 *dirpart = dpart;
155 *filepart = fpart;
156 return 0;
160 ** Attempt to complete the pathname, returning an allocated copy.
161 ** Fill in *unique if we completed it, or set it to 0 if ambiguous.
163 char *
164 rl_complete(pathname, unique)
165 char *pathname;
166 int *unique;
168 char **av;
169 char *dir;
170 char *file;
171 char *new;
172 char *p;
173 SIZE_T ac;
174 SIZE_T end;
175 SIZE_T i;
176 SIZE_T j;
177 SIZE_T len;
179 if (SplitPath(pathname, &dir, &file) < 0)
180 return NULL;
181 if ((ac = FindMatches(dir, file, &av)) == 0) {
182 DISPOSE(dir);
183 DISPOSE(file);
184 return NULL;
187 p = NULL;
188 len = strlen(file);
189 if (ac == 1) {
190 /* Exactly one match -- finish it off. */
191 *unique = 1;
192 j = strlen(av[0]) - len + 2;
193 if ((p = NEW(char, j + 1)) != NULL) {
194 COPYFROMTO(p, av[0] + len, j);
195 if ((new = NEW(char, strlen(dir) + strlen(av[0]) + 2)) != NULL) {
196 (void)strcpy(new, dir);
197 (void)strcat(new, "/");
198 (void)strcat(new, av[0]);
199 rl_add_slash(new, p);
200 DISPOSE(new);
204 else {
205 *unique = 0;
206 if (len) {
207 /* Find largest matching substring. */
208 for (i = len, end = strlen(av[0]); i < end; i++)
209 for (j = 1; j < ac; j++)
210 if (av[0][i] != av[j][i])
211 goto breakout;
212 breakout:
213 if (i > len) {
214 j = i - len + 1;
215 if ((p = NEW(char, j)) != NULL) {
216 COPYFROMTO(p, av[0] + len, j);
217 p[j - 1] = '\0';
223 /* Clean up and return. */
224 DISPOSE(dir);
225 DISPOSE(file);
226 for (i = 0; i < ac; i++)
227 DISPOSE(av[i]);
228 DISPOSE(av);
229 return p;
233 ** Return all possible completions.
236 rl_list_possib(pathname, avp)
237 char *pathname;
238 char ***avp;
240 char *dir;
241 char *file;
242 int ac;
244 if (SplitPath(pathname, &dir, &file) < 0)
245 return 0;
246 ac = FindMatches(dir, file, avp);
247 DISPOSE(dir);
248 DISPOSE(file);
249 return ac;
253 * $PchId: complete.c,v 1.3 1996/02/22 21:18:51 philip Exp $