Edinburgh Speech Tools 2.4-release
 
Loading...
Searching...
No Matches
el_complete.c
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*/
51char * 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*/
64STATIC 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*/
78STATIC 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*/
134STATIC 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*/
171char *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*/
240int 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}