1 /****************************************************************************/
2 /*                                                                          */
3 /* Copyright 1992 Simmule Turner and Rich Salz.  All rights reserved.       */
4 /*                                                                          */
5 /* This software is not subject to any license of the American Telephone    */
6 /* and Telegraph Company or of the Regents of the University of California. */
7 /*                                                                          */
8 /* Permission is granted to anyone to use this software for any purpose on  */
9 /* any computer system, and to alter it and redistribute it freely, subject */
10 /* to the following restrictions:                                           */
11 /* 1. The authors are not responsible for the consequences of use of this   */
12 /*    software, no matter how awful, even if they arise from flaws in it.   */
13 /* 2. The origin of this software must not be misrepresented, either by     */
14 /*    explicit claim or by omission.  Since few users ever read sources,    */
15 /*    credits must appear in the documentation.                             */
16 /* 3. Altered versions must be plainly marked as such, and must not be      */
17 /*    misrepresented as being the original software.  Since few users       */
18 /*    ever read sources, credits must appear in the documentation.          */
19 /* 4. This notice may not be removed or altered.                            */
20 /*                                                                          */
21 /****************************************************************************/
22 /*                                                                          */
23 /*  This is a line-editing library, it can be linked into almost any        */
24 /*  program to provide command-line editing and recall.                     */
25 /*                                                                          */
26 /*  Posted to comp.sources.misc Sun, 2 Aug 1992 03:05:27 GMT                */
27 /*      by rsalz@osf.org (Rich $alz)                                        */
28 /*                                                                          */
29 /****************************************************************************/
30 /*                                                                          */
31 /*  The version contained here has some modifications by awb@cstr.ed.ac.uk  */
32 /*  (Alan W Black) in order to integrate it with the Edinburgh Speech Tools */
33 /*  library and Scheme-in-one-defun in particular.  All modifications to    */
34 /*  to this work are continued with the same copyright above.  That is      */
35 /*  This version editline does not have the the "no commercial use"         */
36 /*  restriction that some of the rest of the EST library may have           */
37 /*  awb Dec 30 1998                                                         */
38 /*                                                                          */
39 /****************************************************************************/
40 /*  $Revision: 1.3 $
41 **
42 **  History and file completion functions for editline library.
43 */
44 #include "editline.h"
45 
46 
47 #if	defined(NEED_STRDUP)
48 /*
49 **  Return an allocated copy of a string.
50 */
strdup(char * p)51 char * strdup(char *p)
52 {
53     char	*new;
54 
55     if ((new = NEW(char, strlen(p) + 1)) != NULL)
56 	(void)strcpy(new, p);
57     return new;
58 }
59 #endif	/* defined(NEED_STRDUP) */
60 
61 /*
62 **  strcmp-like sorting predicate for qsort.
63 */
compare(CONST void * p1,CONST void * p2)64 STATIC int compare(CONST void *p1,CONST void *p2)
65 {
66     CONST char	**v1;
67     CONST char	**v2;
68 
69     v1 = (CONST char **)p1;
70     v2 = (CONST char **)p2;
71     return strcmp(*v1, *v2);
72 }
73 
74 /*
75 **  Fill in *avp with an array of names that match file, up to its length.
76 **  Ignore . and .. .
77 */
FindMatches(char * dir,char * file,char *** avp)78 STATIC int FindMatches(char *dir,char *file,char ***avp)
79 {
80 #if !defined(SYSTEM_IS_WIN32)
81     char	**av;
82     char	**neww;
83     char	*p;
84     DIR		*dp;
85     DIRENTRY	*ep;
86     ESIZE_T	ac;
87     ESIZE_T	len;
88 
89     if ((dp = opendir(dir)) == NULL)
90 	return 0;
91 
92     av = NULL;
93     ac = 0;
94     len = strlen(file);
95     while ((ep = readdir(dp)) != NULL) {
96 	p = ep->d_name;
97 	if (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')))
98 	    continue;
99 	if (len && strncmp(p, file, len) != 0)
100 	    continue;
101 
102 	if ((ac % MEM_INC) == 0) {
103 	    if ((neww = NEW(char*, ac + MEM_INC)) == NULL)
104 		break;
105 	    if (ac) {
106 		COPYFROMTO(neww, av, ac * sizeof (char **));
107 		DISPOSE(av);
108 	    }
109 	    *avp = av = neww;
110 	}
111 
112 	if ((av[ac] = STRDUP(p)) == NULL) {
113 	    if (ac == 0)
114 		DISPOSE(av);
115 	    break;
116 	}
117 	ac++;
118     }
119 
120     /* Clean up and return. */
121     (void)closedir(dp);
122     if (ac)
123 	qsort(av, ac, sizeof (char **), compare);
124     return ac;
125 #else
126     *avp=NULL;
127     return 0;
128 #endif
129 }
130 
131 /*
132 **  Split a pathname into allocated directory and trailing filename parts.
133 */
SplitPath(char * path,char ** dirpart,char ** filepart)134 STATIC int SplitPath(char *path,char **dirpart,char **filepart)
135 {
136     static char	DOT[] = ".";
137     char	*dpart;
138     char	*fpart;
139 
140     if ((fpart = strrchr(path, '/')) == NULL) {
141 	if ((dpart = STRDUP(DOT)) == NULL)
142 	    return -1;
143 	if ((fpart = STRDUP(path)) == NULL) {
144 	    DISPOSE(dpart);
145 	    return -1;
146 	}
147     }
148     else {
149 	if ((dpart = STRDUP(path)) == NULL)
150 	    return -1;
151 	dpart[fpart - path] = '\0';
152 	if ((fpart = STRDUP(++fpart)) == NULL) {
153 	    DISPOSE(dpart);
154 	    return -1;
155 	}
156 	if (dpart[0] == '\0')  /* special case for root */
157 	{
158 	    dpart[0] = '/';
159 	    dpart[1] = '\0';
160 	}
161     }
162     *dirpart = dpart;
163     *filepart = fpart;
164     return 0;
165 }
166 
167 /*
168 **  Attempt to complete the pathname, returning an allocated copy.
169 **  Fill in *unique if we completed it, or set it to 0 if ambiguous.
170 */
rl_complete(char * pathname,int * unique)171 char *rl_complete(char *pathname,int *unique)
172 {
173     char	**av;
174     char	*dir;
175     char	*file;
176     char	*neww;
177     char	*p;
178     ESIZE_T	ac;
179     ESIZE_T	end;
180     ESIZE_T	i;
181     ESIZE_T	j;
182     ESIZE_T	len;
183 
184     if (SplitPath(pathname, &dir, &file) < 0)
185 	return NULL;
186     if ((ac = FindMatches(dir, file, &av)) == 0) {
187 	DISPOSE(dir);
188 	DISPOSE(file);
189 	return NULL;
190     }
191 
192     p = NULL;
193     len = strlen(file);
194     if (ac == 1) {
195 	/* Exactly one match -- finish it off. */
196 	*unique = 1;
197 	j = strlen(av[0]) - len + 2;
198 	if ((p = NEW(char, j + 1)) != NULL) {
199 	    COPYFROMTO(p, av[0] + len, j);
200 	    if ((neww = NEW(char, strlen(dir) + strlen(av[0]) + 2)) != NULL) {
201 		(void)strcpy(neww, dir);
202 		(void)strcat(neww, "/");
203 		(void)strcat(neww, av[0]);
204 		rl_add_slash(neww, p);
205 		DISPOSE(neww);
206 	    }
207 	}
208     }
209     else {
210 	*unique = 0;
211 	if (len) {
212 	    /* Find largest matching substring. */
213 	    for (i = len, end = strlen(av[0]); i < end; i++)
214 		for (j = 1; j < ac; j++)
215 		    if (av[0][i] != av[j][i])
216 			goto breakout;
217   breakout:
218 	    if (i > len) {
219 		j = i - len + 1;
220 		if ((p = NEW(char, j)) != NULL) {
221 		    COPYFROMTO(p, av[0] + len, j);
222 		    p[j - 1] = '\0';
223 		}
224 	    }
225 	}
226     }
227 
228     /* Clean up and return. */
229     DISPOSE(dir);
230     DISPOSE(file);
231     for (i = 0; i < ac; i++)
232 	DISPOSE(av[i]);
233     DISPOSE(av);
234     return p;
235 }
236 
237 /*
238 **  Return all possible completions.
239 */
rl_list_possib(char * pathname,char *** avp)240 int rl_list_possib(char *pathname,char ***avp)
241 {
242     char	*dir;
243     char	*file, *path, *tt;
244     int		ac,i;
245 
246     if (SplitPath(pathname, &dir, &file) < 0)
247 	return 0;
248     ac = FindMatches(dir, file, avp);
249     /* Identify directories with trailing / */
250     for (i = 0; i < ac; i++)
251     {
252 	path = walloc(char,strlen(dir)+strlen((*avp)[i])+3);
253 	sprintf(path,"%s/%s",dir,(*avp)[i]);
254 	if (el_is_directory(path))
255 	{
256 	    tt = walloc(char,strlen((*avp)[i])+2);
257 	    sprintf(tt,"%s/",(*avp)[i]);
258 	    wfree((*avp)[i]);
259 	    (*avp)[i] = tt;
260 	}
261 	wfree(path);
262     }
263     DISPOSE(dir);
264     DISPOSE(file);
265     return ac;
266 }
267