VM: full munmap
[minix.git] / lib / libedit / complete.c
blobcfdff493fad282d1c2b29d7bb428be82ca3e910d
1 /*
2 ** History and file completion functions for editline library.
3 */
4 #include "editline.h"
7 #if defined(NEED_STRDUP)
8 /*
9 ** Return an allocated copy of a string.
11 char *
12 strdup(p)
13 char *p;
15 char *new;
17 if ((new = NEW(char, strlen(p) + 1)) != NULL)
18 (void)strcpy(new, p);
19 return new;
21 #endif /* defined(NEED_STRDUP) */
24 ** strcmp-like sorting predicate for qsort.
26 STATIC int
27 compare(p1, p2)
28 CONST void *p1;
29 CONST void *p2;
31 CONST char **v1;
32 CONST char **v2;
34 v1 = (CONST char **)p1;
35 v2 = (CONST char **)p2;
36 return strcmp(*v1, *v2);
40 ** Fill in *avp with an array of names that match file, up to its length.
41 ** Ignore . and .. .
43 STATIC int
44 FindMatches(dir, file, avp)
45 char *dir;
46 char *file;
47 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;
56 SIZE_T choices;
57 SIZE_T total;
58 #define MAX_TOTAL (256 << sizeof(char *))
60 if ((dp = opendir(dir)) == NULL)
61 return 0;
63 av = NULL;
64 ac = 0;
65 len = strlen(file);
66 choices = 0;
67 total = 0;
68 while ((ep = readdir(dp)) != NULL) {
69 p = ep->d_name;
70 if (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')))
71 continue;
72 if (len && strncmp(p, file, len) != 0)
73 continue;
75 choices++;
76 if ((total += strlen(p)) > MAX_TOTAL) {
77 /* This is a bit too much. */
78 while (ac > 0) DISPOSE(av[--ac]);
79 continue;
82 if ((ac % MEM_INC) == 0) {
83 if ((new = NEW(char*, ac + MEM_INC)) == NULL) {
84 total = 0;
85 break;
87 if (ac) {
88 COPYFROMTO(new, av, ac * sizeof (char **));
89 DISPOSE(av);
91 *avp = av = new;
94 if ((av[ac] = strdup(p)) == NULL) {
95 if (ac == 0)
96 DISPOSE(av);
97 total = 0;
98 break;
100 ac++;
103 /* Clean up and return. */
104 (void)closedir(dp);
105 if (total > MAX_TOTAL) {
106 char many[sizeof(total) * 3];
107 p = many + sizeof(many);
108 *--p = '\0';
109 while (choices > 0) {
110 *--p = '0' + choices % 10;
111 choices /= 10;
113 while (p > many + sizeof(many) - 8) *--p = ' ';
114 if ((p = strdup(p)) != NULL) av[ac++] = p;
115 if ((p = strdup("choices")) != NULL) av[ac++] = p;
116 } else {
117 if (ac)
118 qsort(av, ac, sizeof (char **), compare);
120 return ac;
124 ** Split a pathname into allocated directory and trailing filename parts.
126 STATIC int
127 SplitPath(path, dirpart, filepart)
128 char *path;
129 char **dirpart;
130 char **filepart;
132 static char DOT[] = ".";
133 char *dpart;
134 char *fpart;
136 if ((fpart = strrchr(path, '/')) == NULL) {
137 if ((dpart = strdup(DOT)) == NULL)
138 return -1;
139 if ((fpart = strdup(path)) == NULL) {
140 DISPOSE(dpart);
141 return -1;
144 else {
145 if ((dpart = strdup(path)) == NULL)
146 return -1;
147 dpart[fpart - path + 1] = '\0';
148 if ((fpart = strdup(++fpart)) == NULL) {
149 DISPOSE(dpart);
150 return -1;
153 *dirpart = dpart;
154 *filepart = fpart;
155 return 0;
159 ** Attempt to complete the pathname, returning an allocated copy.
160 ** Fill in *unique if we completed it, or set it to 0 if ambiguous.
162 char *
163 rl_complete(pathname, unique)
164 char *pathname;
165 int *unique;
167 char **av;
168 char *dir;
169 char *file;
170 char *new;
171 char *p;
172 SIZE_T ac;
173 SIZE_T end;
174 SIZE_T i;
175 SIZE_T j;
176 SIZE_T len;
178 if (SplitPath(pathname, &dir, &file) < 0)
179 return NULL;
180 if ((ac = FindMatches(dir, file, &av)) == 0) {
181 DISPOSE(dir);
182 DISPOSE(file);
183 return NULL;
186 p = NULL;
187 len = strlen(file);
188 if (ac == 1) {
189 /* Exactly one match -- finish it off. */
190 *unique = 1;
191 j = strlen(av[0]) - len + 1;
192 if ((p = NEW(char, j + 1)) != NULL) {
193 COPYFROMTO(p, av[0] + len, j);
194 if ((new = NEW(char, strlen(dir) + strlen(av[0]) + 2)) != NULL) {
195 (void)strcpy(new, dir);
196 (void)strcat(new, "/");
197 (void)strcat(new, av[0]);
198 rl_add_slash(new, p);
199 DISPOSE(new);
203 else {
204 *unique = 0;
205 if (len) {
206 /* Find largest matching substring. */
207 for (i = len, end = strlen(av[0]); i < end; i++)
208 for (j = 1; j < ac; j++)
209 if (av[0][i] != av[j][i])
210 goto breakout;
211 breakout:
212 if (i > len) {
213 j = i - len + 1;
214 if ((p = NEW(char, j)) != NULL) {
215 COPYFROMTO(p, av[0] + len, j);
216 p[j - 1] = '\0';
222 /* Clean up and return. */
223 DISPOSE(dir);
224 DISPOSE(file);
225 for (i = 0; i < ac; i++)
226 DISPOSE(av[i]);
227 DISPOSE(av);
228 return p;
232 ** Return all possible completions.
235 rl_list_possib(pathname, avp)
236 char *pathname;
237 char ***avp;
239 char *dir;
240 char *file;
241 int ac;
243 if (SplitPath(pathname, &dir, &file) < 0)
244 return 0;
245 ac = FindMatches(dir, file, avp);
246 DISPOSE(dir);
247 DISPOSE(file);
248 return ac;
252 * $PchId: complete.c,v 1.3 1996/02/22 21:18:51 philip Exp $