source: trunk/minix/lib/editline/complete.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 4.7 KB
Line 
1/* $Revision: 1.1.1.1 $
2**
3** History and file completion functions for editline library.
4*/
5#include "editline.h"
6
7
8#if defined(NEED_STRDUP)
9/*
10** Return an allocated copy of a string.
11*/
12char *
13strdup(p)
14 char *p;
15{
16 char *new;
17
18 if ((new = NEW(char, strlen(p) + 1)) != NULL)
19 (void)strcpy(new, p);
20 return new;
21}
22#endif /* defined(NEED_STRDUP) */
23
24/*
25** strcmp-like sorting predicate for qsort.
26*/
27STATIC int
28compare(p1, p2)
29 CONST void *p1;
30 CONST void *p2;
31{
32 CONST char **v1;
33 CONST char **v2;
34
35 v1 = (CONST char **)p1;
36 v2 = (CONST char **)p2;
37 return strcmp(*v1, *v2);
38}
39
40/*
41** Fill in *avp with an array of names that match file, up to its length.
42** Ignore . and .. .
43*/
44STATIC int
45FindMatches(dir, file, avp)
46 char *dir;
47 char *file;
48 char ***avp;
49{
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 *))
60
61 if ((dp = opendir(dir)) == NULL)
62 return 0;
63
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;
75
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;
81 }
82
83 if ((ac % MEM_INC) == 0) {
84 if ((new = NEW(char*, ac + MEM_INC)) == NULL) {
85 total = 0;
86 break;
87 }
88 if (ac) {
89 COPYFROMTO(new, av, ac * sizeof (char **));
90 DISPOSE(av);
91 }
92 *avp = av = new;
93 }
94
95 if ((av[ac] = strdup(p)) == NULL) {
96 if (ac == 0)
97 DISPOSE(av);
98 total = 0;
99 break;
100 }
101 ac++;
102 }
103
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;
113 }
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);
120 }
121 return ac;
122}
123
124/*
125** Split a pathname into allocated directory and trailing filename parts.
126*/
127STATIC int
128SplitPath(path, dirpart, filepart)
129 char *path;
130 char **dirpart;
131 char **filepart;
132{
133 static char DOT[] = ".";
134 char *dpart;
135 char *fpart;
136
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;
143 }
144 }
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;
152 }
153 }
154 *dirpart = dpart;
155 *filepart = fpart;
156 return 0;
157}
158
159/*
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.
162*/
163char *
164rl_complete(pathname, unique)
165 char *pathname;
166 int *unique;
167{
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;
178
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;
185 }
186
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);
201 }
202 }
203 }
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';
218 }
219 }
220 }
221 }
222
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;
230}
231
232/*
233** Return all possible completions.
234*/
235int
236rl_list_possib(pathname, avp)
237 char *pathname;
238 char ***avp;
239{
240 char *dir;
241 char *file;
242 int ac;
243
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;
250}
251
252/*
253 * $PchId: complete.c,v 1.3 1996/02/22 21:18:51 philip Exp $
254 */
Note: See TracBrowser for help on using the repository browser.