filecomplete.c (209224) | filecomplete.c (276881) |
---|---|
1/* $NetBSD: filecomplete.c,v 1.34 2014/10/18 15:07:02 riz Exp $ */ 2 |
|
1/*- 2 * Copyright (c) 1997 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Jaromir Dolecek. 7 * 8 * Redistribution and use in source and binary forms, with or without --- 11 unchanged lines hidden (view full) --- 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. | 3/*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jaromir Dolecek. 9 * 10 * Redistribution and use in source and binary forms, with or without --- 11 unchanged lines hidden (view full) --- 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. |
28 * 29 * $NetBSD: filecomplete.c,v 1.19 2010/06/01 18:20:26 christos Exp $ | |
30 */ 31 | 30 */ 31 |
32#include "config.h" 33#if !defined(lint) && !defined(SCCSID) 34__RCSID("$NetBSD: filecomplete.c,v 1.34 2014/10/18 15:07:02 riz Exp $"); 35#endif /* not lint && not SCCSID */ |
|
32#include <sys/cdefs.h> | 36#include <sys/cdefs.h> |
33__FBSDID("$FreeBSD: head/lib/libedit/filecomplete.c 209224 2010-06-15 22:23:21Z jilles $"); | 37__FBSDID("$FreeBSD: head/lib/libedit/filecomplete.c 276881 2015-01-09 07:40:56Z bapt $"); |
34 35#include <sys/types.h> 36#include <sys/stat.h> 37#include <stdio.h> 38#include <dirent.h> 39#include <string.h> 40#include <pwd.h> 41#include <ctype.h> 42#include <stdlib.h> 43#include <unistd.h> 44#include <limits.h> 45#include <errno.h> 46#include <fcntl.h> | 38 39#include <sys/types.h> 40#include <sys/stat.h> 41#include <stdio.h> 42#include <dirent.h> 43#include <string.h> 44#include <pwd.h> 45#include <ctype.h> 46#include <stdlib.h> 47#include <unistd.h> 48#include <limits.h> 49#include <errno.h> 50#include <fcntl.h> |
47#include <vis.h> | 51 |
48#include "el.h" 49#include "fcns.h" /* for EL_NUM_FCNS */ 50#include "histedit.h" 51#include "filecomplete.h" 52 | 52#include "el.h" 53#include "fcns.h" /* for EL_NUM_FCNS */ 54#include "histedit.h" 55#include "filecomplete.h" 56 |
53static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', 54 '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; | 57static const Char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', 58 '$', '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; |
55/* Tilde is deliberately omitted here, we treat it specially. */ | 59/* Tilde is deliberately omitted here, we treat it specially. */ |
56static char extra_quote_chars[] = { ')', '}', '*', '?', '[', '$', '\0' }; | 60static const Char extra_quote_chars[] = { ')', '}', '*', '?', '[', '$', '\0' }; |
57 58 59/********************************/ 60/* completion functions */ 61 62/* 63 * does tilde expansion of strings of type ``~user/foo'' 64 * if ``user'' isn't valid user name or ``txt'' doesn't start 65 * w/ '~', returns pointer to strdup()ed copy of ``txt'' 66 * | 61 62 63/********************************/ 64/* completion functions */ 65 66/* 67 * does tilde expansion of strings of type ``~user/foo'' 68 * if ``user'' isn't valid user name or ``txt'' doesn't start 69 * w/ '~', returns pointer to strdup()ed copy of ``txt'' 70 * |
67 * it's callers's responsibility to free() returned string | 71 * it's the caller's responsibility to free() the returned string |
68 */ 69char * 70fn_tilde_expand(const char *txt) 71{ | 72 */ 73char * 74fn_tilde_expand(const char *txt) 75{ |
72 struct passwd pwres, *pass; | 76#if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) 77 struct passwd pwres; 78 char pwbuf[1024]; 79#endif 80 struct passwd *pass; |
73 char *temp; 74 size_t len = 0; | 81 char *temp; 82 size_t len = 0; |
75 char pwbuf[1024]; | |
76 77 if (txt[0] != '~') | 83 84 if (txt[0] != '~') |
78 return (strdup(txt)); | 85 return strdup(txt); |
79 80 temp = strchr(txt + 1, '/'); 81 if (temp == NULL) { 82 temp = strdup(txt + 1); 83 if (temp == NULL) 84 return NULL; 85 } else { | 86 87 temp = strchr(txt + 1, '/'); 88 if (temp == NULL) { 89 temp = strdup(txt + 1); 90 if (temp == NULL) 91 return NULL; 92 } else { |
86 len = temp - txt + 1; /* text until string after slash */ 87 temp = malloc(len); | 93 /* text until string after slash */ 94 len = (size_t)(temp - txt + 1); 95 temp = el_malloc(len * sizeof(*temp)); |
88 if (temp == NULL) 89 return NULL; 90 (void)strncpy(temp, txt + 1, len - 2); 91 temp[len - 2] = '\0'; 92 } 93 if (temp[0] == 0) { | 96 if (temp == NULL) 97 return NULL; 98 (void)strncpy(temp, txt + 1, len - 2); 99 temp[len - 2] = '\0'; 100 } 101 if (temp[0] == 0) { |
94 if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) 95 pass = NULL; | 102#ifdef HAVE_GETPW_R_POSIX 103 if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), 104 &pass) != 0) 105 pass = NULL; 106#elif HAVE_GETPW_R_DRAFT 107 pass = getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf)); 108#else 109 pass = getpwuid(getuid()); 110#endif |
96 } else { | 111 } else { |
112#ifdef HAVE_GETPW_R_POSIX |
|
97 if (getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) 98 pass = NULL; | 113 if (getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) 114 pass = NULL; |
115#elif HAVE_GETPW_R_DRAFT 116 pass = getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf)); 117#else 118 pass = getpwnam(temp); 119#endif |
|
99 } | 120 } |
100 free(temp); /* value no more needed */ | 121 el_free(temp); /* value no more needed */ |
101 if (pass == NULL) | 122 if (pass == NULL) |
102 return (strdup(txt)); | 123 return strdup(txt); |
103 | 124 |
104 /* update pointer txt to point at string immediately following */ | 125 /* update pointer txt to point at string immedially following */ |
105 /* first slash */ 106 txt += len; 107 | 126 /* first slash */ 127 txt += len; 128 |
108 temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); | 129 len = strlen(pass->pw_dir) + 1 + strlen(txt) + 1; 130 temp = el_malloc(len * sizeof(*temp)); |
109 if (temp == NULL) 110 return NULL; | 131 if (temp == NULL) 132 return NULL; |
111 (void)sprintf(temp, "%s/%s", pass->pw_dir, txt); | 133 (void)snprintf(temp, len, "%s/%s", pass->pw_dir, txt); |
112 | 134 |
113 return (temp); | 135 return temp; |
114} 115 116 117/* 118 * return first found file name starting by the ``text'' or NULL if no 119 * such file can be found 120 * value of ``state'' is ignored 121 * | 136} 137 138 139/* 140 * return first found file name starting by the ``text'' or NULL if no 141 * such file can be found 142 * value of ``state'' is ignored 143 * |
122 * it's caller's responsibility to free returned string | 144 * it's the caller's responsibility to free the returned string |
123 */ 124char * 125fn_filename_completion_function(const char *text, int state) 126{ 127 static DIR *dir = NULL; 128 static char *filename = NULL, *dirname = NULL, *dirpath = NULL; 129 static size_t filename_len = 0; 130 struct dirent *entry; 131 char *temp; 132 size_t len; 133 134 if (state == 0 || dir == NULL) { 135 temp = strrchr(text, '/'); 136 if (temp) { 137 char *nptr; 138 temp++; | 145 */ 146char * 147fn_filename_completion_function(const char *text, int state) 148{ 149 static DIR *dir = NULL; 150 static char *filename = NULL, *dirname = NULL, *dirpath = NULL; 151 static size_t filename_len = 0; 152 struct dirent *entry; 153 char *temp; 154 size_t len; 155 156 if (state == 0 || dir == NULL) { 157 temp = strrchr(text, '/'); 158 if (temp) { 159 char *nptr; 160 temp++; |
139 nptr = realloc(filename, strlen(temp) + 1); | 161 nptr = el_realloc(filename, (strlen(temp) + 1) * 162 sizeof(*nptr)); |
140 if (nptr == NULL) { | 163 if (nptr == NULL) { |
141 free(filename); | 164 el_free(filename); |
142 filename = NULL; 143 return NULL; 144 } 145 filename = nptr; 146 (void)strcpy(filename, temp); | 165 filename = NULL; 166 return NULL; 167 } 168 filename = nptr; 169 (void)strcpy(filename, temp); |
147 len = temp - text; /* including last slash */ | 170 len = (size_t)(temp - text); /* including last slash */ |
148 | 171 |
149 nptr = realloc(dirname, len + 1); | 172 nptr = el_realloc(dirname, (len + 1) * 173 sizeof(*nptr)); |
150 if (nptr == NULL) { | 174 if (nptr == NULL) { |
151 free(dirname); | 175 el_free(dirname); |
152 dirname = NULL; 153 return NULL; 154 } 155 dirname = nptr; 156 (void)strncpy(dirname, text, len); 157 dirname[len] = '\0'; 158 } else { | 176 dirname = NULL; 177 return NULL; 178 } 179 dirname = nptr; 180 (void)strncpy(dirname, text, len); 181 dirname[len] = '\0'; 182 } else { |
159 free(filename); | 183 el_free(filename); |
160 if (*text == 0) 161 filename = NULL; 162 else { 163 filename = strdup(text); 164 if (filename == NULL) 165 return NULL; 166 } | 184 if (*text == 0) 185 filename = NULL; 186 else { 187 filename = strdup(text); 188 if (filename == NULL) 189 return NULL; 190 } |
167 free(dirname); | 191 el_free(dirname); |
168 dirname = NULL; 169 } 170 171 if (dir != NULL) { 172 (void)closedir(dir); 173 dir = NULL; 174 } 175 176 /* support for ``~user'' syntax */ 177 | 192 dirname = NULL; 193 } 194 195 if (dir != NULL) { 196 (void)closedir(dir); 197 dir = NULL; 198 } 199 200 /* support for ``~user'' syntax */ 201 |
178 free(dirpath); | 202 el_free(dirpath); |
179 dirpath = NULL; 180 if (dirname == NULL) { 181 if ((dirname = strdup("")) == NULL) 182 return NULL; 183 dirpath = strdup("./"); 184 } else if (*dirname == '~') 185 dirpath = fn_tilde_expand(dirname); 186 else 187 dirpath = strdup(dirname); 188 189 if (dirpath == NULL) 190 return NULL; 191 192 dir = opendir(dirpath); 193 if (!dir) | 203 dirpath = NULL; 204 if (dirname == NULL) { 205 if ((dirname = strdup("")) == NULL) 206 return NULL; 207 dirpath = strdup("./"); 208 } else if (*dirname == '~') 209 dirpath = fn_tilde_expand(dirname); 210 else 211 dirpath = strdup(dirname); 212 213 if (dirpath == NULL) 214 return NULL; 215 216 dir = opendir(dirpath); 217 if (!dir) |
194 return (NULL); /* cannot open the directory */ | 218 return NULL; /* cannot open the directory */ |
195 196 /* will be used in cycle */ 197 filename_len = filename ? strlen(filename) : 0; 198 } 199 200 /* find the match */ 201 while ((entry = readdir(dir)) != NULL) { 202 /* skip . and .. */ 203 if (entry->d_name[0] == '.' && (!entry->d_name[1] 204 || (entry->d_name[1] == '.' && !entry->d_name[2]))) 205 continue; 206 if (filename_len == 0) 207 break; 208 /* otherwise, get first entry where first */ 209 /* filename_len characters are equal */ 210 if (entry->d_name[0] == filename[0] | 219 220 /* will be used in cycle */ 221 filename_len = filename ? strlen(filename) : 0; 222 } 223 224 /* find the match */ 225 while ((entry = readdir(dir)) != NULL) { 226 /* skip . and .. */ 227 if (entry->d_name[0] == '.' && (!entry->d_name[1] 228 || (entry->d_name[1] == '.' && !entry->d_name[2]))) 229 continue; 230 if (filename_len == 0) 231 break; 232 /* otherwise, get first entry where first */ 233 /* filename_len characters are equal */ 234 if (entry->d_name[0] == filename[0] |
235#if HAVE_STRUCT_DIRENT_D_NAMLEN |
|
211 && entry->d_namlen >= filename_len | 236 && entry->d_namlen >= filename_len |
237#else 238 && strlen(entry->d_name) >= filename_len 239#endif |
|
212 && strncmp(entry->d_name, filename, 213 filename_len) == 0) 214 break; 215 } 216 217 if (entry) { /* match found */ | 240 && strncmp(entry->d_name, filename, 241 filename_len) == 0) 242 break; 243 } 244 245 if (entry) { /* match found */ |
246 247#if HAVE_STRUCT_DIRENT_D_NAMLEN |
|
218 len = entry->d_namlen; | 248 len = entry->d_namlen; |
249#else 250 len = strlen(entry->d_name); 251#endif |
|
219 | 252 |
220 temp = malloc(strlen(dirname) + len + 1); | 253 len = strlen(dirname) + len + 1; 254 temp = el_malloc(len * sizeof(*temp)); |
221 if (temp == NULL) 222 return NULL; | 255 if (temp == NULL) 256 return NULL; |
223 (void)sprintf(temp, "%s%s", dirname, entry->d_name); | 257 (void)snprintf(temp, len, "%s%s", dirname, entry->d_name); |
224 } else { 225 (void)closedir(dir); 226 dir = NULL; 227 temp = NULL; 228 } 229 | 258 } else { 259 (void)closedir(dir); 260 dir = NULL; 261 temp = NULL; 262 } 263 |
230 return (temp); | 264 return temp; |
231} 232 233 234static const char * 235append_char_function(const char *name) 236{ 237 struct stat stbuf; 238 char *expname = *name == '~' ? fn_tilde_expand(name) : NULL; 239 const char *rs = " "; 240 241 if (stat(expname ? expname : name, &stbuf) == -1) 242 goto out; 243 if (S_ISDIR(stbuf.st_mode)) 244 rs = "/"; 245out: 246 if (expname) | 265} 266 267 268static const char * 269append_char_function(const char *name) 270{ 271 struct stat stbuf; 272 char *expname = *name == '~' ? fn_tilde_expand(name) : NULL; 273 const char *rs = " "; 274 275 if (stat(expname ? expname : name, &stbuf) == -1) 276 goto out; 277 if (S_ISDIR(stbuf.st_mode)) 278 rs = "/"; 279out: 280 if (expname) |
247 free(expname); | 281 el_free(expname); |
248 return rs; 249} | 282 return rs; 283} |
250 251 | |
252/* 253 * returns list of completions for text given 254 * non-static for readline. 255 */ 256char ** completion_matches(const char *, char *(*)(const char *, int)); 257char ** 258completion_matches(const char *text, char *(*genfunc)(const char *, int)) 259{ --- 4 unchanged lines hidden (view full) --- 264 matches = 0; 265 match_list_len = 1; 266 while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { 267 /* allow for list terminator here */ 268 if (matches + 3 >= match_list_len) { 269 char **nmatch_list; 270 while (matches + 3 >= match_list_len) 271 match_list_len <<= 1; | 284/* 285 * returns list of completions for text given 286 * non-static for readline. 287 */ 288char ** completion_matches(const char *, char *(*)(const char *, int)); 289char ** 290completion_matches(const char *text, char *(*genfunc)(const char *, int)) 291{ --- 4 unchanged lines hidden (view full) --- 296 matches = 0; 297 match_list_len = 1; 298 while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { 299 /* allow for list terminator here */ 300 if (matches + 3 >= match_list_len) { 301 char **nmatch_list; 302 while (matches + 3 >= match_list_len) 303 match_list_len <<= 1; |
272 nmatch_list = realloc(match_list, 273 match_list_len * sizeof(char *)); | 304 nmatch_list = el_realloc(match_list, 305 match_list_len * sizeof(*nmatch_list)); |
274 if (nmatch_list == NULL) { | 306 if (nmatch_list == NULL) { |
275 free(match_list); | 307 el_free(match_list); |
276 return NULL; 277 } 278 match_list = nmatch_list; 279 280 } 281 match_list[++matches] = retstr; 282 } 283 --- 6 unchanged lines hidden (view full) --- 290 max_equal = strlen(prevstr); 291 for (; which <= matches; which++) { 292 for (i = 0; i < max_equal && 293 prevstr[i] == match_list[which][i]; i++) 294 continue; 295 max_equal = i; 296 } 297 | 308 return NULL; 309 } 310 match_list = nmatch_list; 311 312 } 313 match_list[++matches] = retstr; 314 } 315 --- 6 unchanged lines hidden (view full) --- 322 max_equal = strlen(prevstr); 323 for (; which <= matches; which++) { 324 for (i = 0; i < max_equal && 325 prevstr[i] == match_list[which][i]; i++) 326 continue; 327 max_equal = i; 328 } 329 |
298 retstr = malloc(max_equal + 1); | 330 retstr = el_malloc((max_equal + 1) * sizeof(*retstr)); |
299 if (retstr == NULL) { | 331 if (retstr == NULL) { |
300 free(match_list); | 332 el_free(match_list); |
301 return NULL; 302 } 303 (void)strncpy(retstr, match_list[1], max_equal); 304 retstr[max_equal] = '\0'; 305 match_list[0] = retstr; 306 307 /* add NULL as last pointer to the array */ | 333 return NULL; 334 } 335 (void)strncpy(retstr, match_list[1], max_equal); 336 retstr[max_equal] = '\0'; 337 match_list[0] = retstr; 338 339 /* add NULL as last pointer to the array */ |
308 match_list[matches + 1] = (char *) NULL; | 340 match_list[matches + 1] = NULL; |
309 | 341 |
310 return (match_list); | 342 return match_list; |
311} 312 | 343} 344 |
313 | |
314/* 315 * Sort function for qsort(). Just wrapper around strcasecmp(). 316 */ 317static int 318_fn_qsort_string_compare(const void *i1, const void *i2) 319{ 320 const char *s1 = ((const char * const *)i1)[0]; 321 const char *s2 = ((const char * const *)i2)[0]; 322 323 return strcasecmp(s1, s2); 324} 325 | 345/* 346 * Sort function for qsort(). Just wrapper around strcasecmp(). 347 */ 348static int 349_fn_qsort_string_compare(const void *i1, const void *i2) 350{ 351 const char *s1 = ((const char * const *)i1)[0]; 352 const char *s2 = ((const char * const *)i2)[0]; 353 354 return strcasecmp(s1, s2); 355} 356 |
326 | |
327/* 328 * Display list of strings in columnar format on readline's output stream. | 357/* 358 * Display list of strings in columnar format on readline's output stream. |
329 * 'matches' is list of strings, 'len' is number of strings in 'matches', 330 * 'max' is maximum length of string in 'matches'. | 359 * 'matches' is list of strings, 'num' is number of strings in 'matches', 360 * 'width' is maximum length of string in 'matches'. 361 * 362 * matches[0] is not one of the match strings, but it is counted in 363 * num, so the strings are matches[1] *through* matches[num-1]. |
331 */ 332void | 364 */ 365void |
333fn_display_match_list(EditLine *el, char **matches, size_t len, size_t max) | 366fn_display_match_list (EditLine *el, char **matches, size_t num, size_t width) |
334{ | 367{ |
335 size_t i, idx, limit, count; 336 int screenwidth = el->el_term.t_size.h; | 368 size_t line, lines, col, cols, thisguy; 369 int screenwidth = el->el_terminal.t_size.h; |
337 | 370 |
371 /* Ignore matches[0]. Avoid 1-based array logic below. */ 372 matches++; 373 num--; 374 |
|
338 /* | 375 /* |
339 * Find out how many entries can be put on one line, count 340 * with two spaces between strings. | 376 * Find out how many entries can be put on one line; count 377 * with one space between strings the same way it's printed. |
341 */ | 378 */ |
342 limit = screenwidth / (max + 2); 343 if (limit == 0) 344 limit = 1; | 379 cols = (size_t)screenwidth / (width + 1); 380 if (cols == 0) 381 cols = 1; |
345 | 382 |
346 /* how many lines of output */ 347 count = len / limit; 348 if (count * limit < len) 349 count++; | 383 /* how many lines of output, rounded up */ 384 lines = (num + cols - 1) / cols; |
350 | 385 |
351 /* Sort the items if they are not already sorted. */ 352 qsort(&matches[1], len, sizeof(char *), _fn_qsort_string_compare); | 386 /* Sort the items. */ 387 qsort(matches, num, sizeof(char *), _fn_qsort_string_compare); |
353 | 388 |
354 idx = 1; 355 for(; count > 0; count--) { 356 int more = limit > 0 && matches[0]; 357 for(i = 0; more; idx++) { 358 more = ++i < limit && matches[idx + 1]; 359 (void)fprintf(el->el_outfile, "%-*s%s", (int)max, 360 matches[idx], more ? " " : ""); | 389 /* 390 * On the ith line print elements i, i+lines, i+lines*2, etc. 391 */ 392 for (line = 0; line < lines; line++) { 393 for (col = 0; col < cols; col++) { 394 thisguy = line + col * lines; 395 if (thisguy >= num) 396 break; 397 (void)fprintf(el->el_outfile, "%s%-*s", 398 col == 0 ? "" : " ", (int)width, matches[thisguy]); |
361 } 362 (void)fprintf(el->el_outfile, "\n"); 363 } 364} 365 | 399 } 400 (void)fprintf(el->el_outfile, "\n"); 401 } 402} 403 |
366 | |
367/* 368 * Complete the word at or before point, 369 * 'what_to_do' says what to do with the completion. 370 * \t means do standard completion. 371 * `?' means list the possible completions. 372 * `*' means insert all of the possible completions. 373 * `!' means to do standard completion, and list all possible completions if 374 * there is more than one. 375 * 376 * Note: '*' support is not implemented 377 * '!' could never be invoked 378 */ 379int 380fn_complete(EditLine *el, 381 char *(*complet_func)(const char *, int), 382 char **(*attempted_completion_function)(const char *, int, int), | 404/* 405 * Complete the word at or before point, 406 * 'what_to_do' says what to do with the completion. 407 * \t means do standard completion. 408 * `?' means list the possible completions. 409 * `*' means insert all of the possible completions. 410 * `!' means to do standard completion, and list all possible completions if 411 * there is more than one. 412 * 413 * Note: '*' support is not implemented 414 * '!' could never be invoked 415 */ 416int 417fn_complete(EditLine *el, 418 char *(*complet_func)(const char *, int), 419 char **(*attempted_completion_function)(const char *, int, int), |
383 const char *word_break, const char *special_prefixes, | 420 const Char *word_break, const Char *special_prefixes, |
384 const char *(*app_func)(const char *), size_t query_items, 385 int *completion_type, int *over, int *point, int *end, | 421 const char *(*app_func)(const char *), size_t query_items, 422 int *completion_type, int *over, int *point, int *end, |
386 const char *(*find_word_start_func)(const char *, const char *), 387 char *(*dequoting_func)(const char *), | 423 const Char *(*find_word_start_func)(const Char *, const Char *), 424 Char *(*dequoting_func)(const Char *), |
388 char *(*quoting_func)(const char *)) 389{ | 425 char *(*quoting_func)(const char *)) 426{ |
390 const LineInfo *li; 391 char *temp; 392 char *dequoted_temp; 393 char **matches; 394 const char *ctemp; | 427 const TYPE(LineInfo) *li; 428 Char *temp; 429 Char *dequoted_temp; 430 char **matches; 431 const Char *ctemp; |
395 size_t len; 396 int what_to_do = '\t'; 397 int retval = CC_NORM; 398 399 if (el->el_state.lastcmd == el->el_state.thiscmd) 400 what_to_do = '?'; 401 402 /* readline's rl_complete() has to be told what we did... */ 403 if (completion_type != NULL) 404 *completion_type = what_to_do; 405 406 if (!complet_func) 407 complet_func = fn_filename_completion_function; 408 if (!app_func) 409 app_func = append_char_function; 410 411 /* We now look backwards for the start of a filename/variable word */ | 432 size_t len; 433 int what_to_do = '\t'; 434 int retval = CC_NORM; 435 436 if (el->el_state.lastcmd == el->el_state.thiscmd) 437 what_to_do = '?'; 438 439 /* readline's rl_complete() has to be told what we did... */ 440 if (completion_type != NULL) 441 *completion_type = what_to_do; 442 443 if (!complet_func) 444 complet_func = fn_filename_completion_function; 445 if (!app_func) 446 app_func = append_char_function; 447 448 /* We now look backwards for the start of a filename/variable word */ |
412 li = el_line(el); | 449 li = FUN(el,line)(el); |
413 if (find_word_start_func) 414 ctemp = find_word_start_func(li->buffer, li->cursor); 415 else { 416 ctemp = li->cursor; 417 while (ctemp > li->buffer | 450 if (find_word_start_func) 451 ctemp = find_word_start_func(li->buffer, li->cursor); 452 else { 453 ctemp = li->cursor; 454 while (ctemp > li->buffer |
418 && !strchr(word_break, ctemp[-1]) 419 && (!special_prefixes || !strchr(special_prefixes, ctemp[-1]) ) ) | 455 && !Strchr(word_break, ctemp[-1]) 456 && (!special_prefixes || !Strchr(special_prefixes, ctemp[-1]) ) ) |
420 ctemp--; 421 } 422 | 457 ctemp--; 458 } 459 |
423 len = li->cursor - ctemp; 424#if defined(__SSP__) || defined(__SSP_ALL__) 425 temp = malloc(sizeof(*temp) * (len + 1)); 426 if (temp == NULL) 427 return retval; 428#else 429 temp = alloca(sizeof(*temp) * (len + 1)); 430#endif 431 (void)strncpy(temp, ctemp, len); | 460 len = (size_t)(li->cursor - ctemp); 461 temp = el_malloc((len + 1) * sizeof(*temp)); 462 (void)Strncpy(temp, ctemp, len); |
432 temp[len] = '\0'; 433 434 if (dequoting_func) { 435 dequoted_temp = dequoting_func(temp); 436 if (dequoted_temp == NULL) 437 return retval; 438 } else 439 dequoted_temp = NULL; 440 441 /* these can be used by function called in completion_matches() */ 442 /* or (*attempted_completion_function)() */ 443 if (point != 0) 444 *point = (int)(li->cursor - li->buffer); 445 if (end != NULL) 446 *end = (int)(li->lastchar - li->buffer); 447 448 if (attempted_completion_function) { 449 int cur_off = (int)(li->cursor - li->buffer); | 463 temp[len] = '\0'; 464 465 if (dequoting_func) { 466 dequoted_temp = dequoting_func(temp); 467 if (dequoted_temp == NULL) 468 return retval; 469 } else 470 dequoted_temp = NULL; 471 472 /* these can be used by function called in completion_matches() */ 473 /* or (*attempted_completion_function)() */ 474 if (point != 0) 475 *point = (int)(li->cursor - li->buffer); 476 if (end != NULL) 477 *end = (int)(li->lastchar - li->buffer); 478 479 if (attempted_completion_function) { 480 int cur_off = (int)(li->cursor - li->buffer); |
450 matches = (*attempted_completion_function) (dequoted_temp ? dequoted_temp : temp, 451 (int)(cur_off - len), cur_off); | 481 matches = (*attempted_completion_function)( 482 ct_encode_string(dequoted_temp ? dequoted_temp : temp, 483 &el->el_scratch), 484 cur_off - (int)len, cur_off); |
452 } else 453 matches = 0; 454 if (!attempted_completion_function || 455 (over != NULL && !*over && !matches)) | 485 } else 486 matches = 0; 487 if (!attempted_completion_function || 488 (over != NULL && !*over && !matches)) |
456 matches = completion_matches(dequoted_temp ? dequoted_temp : temp, complet_func); | 489 matches = completion_matches( 490 ct_encode_string(dequoted_temp ? dequoted_temp : temp, 491 &el->el_scratch), complet_func); |
457 458 if (over != NULL) 459 *over = 0; 460 461 if (matches) { 462 int i; 463 size_t matches_num, maxlen, match_len, match_display=1; 464 --- 5 unchanged lines hidden (view full) --- 470 if (matches[0][0] != '\0') { 471 char *quoted_match; 472 if (quoting_func) { 473 quoted_match = quoting_func(matches[0]); 474 if (quoted_match == NULL) 475 goto free_matches; 476 } else 477 quoted_match = NULL; | 492 493 if (over != NULL) 494 *over = 0; 495 496 if (matches) { 497 int i; 498 size_t matches_num, maxlen, match_len, match_display=1; 499 --- 5 unchanged lines hidden (view full) --- 505 if (matches[0][0] != '\0') { 506 char *quoted_match; 507 if (quoting_func) { 508 quoted_match = quoting_func(matches[0]); 509 if (quoted_match == NULL) 510 goto free_matches; 511 } else 512 quoted_match = NULL; |
478 | |
479 el_deletestr(el, (int) len); | 513 el_deletestr(el, (int) len); |
480 el_insertstr(el, quoted_match ? quoted_match : matches[0]); 481 482 free(quoted_match); | 514 FUN(el,insertstr)(el, 515 ct_decode_string(quoted_match ? quoted_match : 516 matches[0] , &el->el_scratch)); |
483 } 484 485 if (what_to_do == '?') 486 goto display_matches; 487 | 517 } 518 519 if (what_to_do == '?') 520 goto display_matches; 521 |
488 if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { | 522 if (matches[2] == NULL && 523 (matches[1] == NULL || strcmp(matches[0], matches[1]) == 0)) { |
489 /* 490 * We found exact match. Add a space after 491 * it, unless we do filename completion and the 492 * object is a directory. 493 */ | 524 /* 525 * We found exact match. Add a space after 526 * it, unless we do filename completion and the 527 * object is a directory. 528 */ |
494 el_insertstr(el, (*app_func)(matches[0])); | 529 FUN(el,insertstr)(el, 530 ct_decode_string((*app_func)(matches[0]), 531 &el->el_scratch)); |
495 } else if (what_to_do == '!') { 496 display_matches: 497 /* 498 * More than one match and requested to list possible 499 * matches. 500 */ 501 502 for(i = 1, maxlen = 0; matches[i]; i++) { 503 match_len = strlen(matches[i]); 504 if (match_len > maxlen) 505 maxlen = match_len; 506 } | 532 } else if (what_to_do == '!') { 533 display_matches: 534 /* 535 * More than one match and requested to list possible 536 * matches. 537 */ 538 539 for(i = 1, maxlen = 0; matches[i]; i++) { 540 match_len = strlen(matches[i]); 541 if (match_len > maxlen) 542 maxlen = match_len; 543 } |
507 matches_num = i - 1; | 544 /* matches[1] through matches[i-1] are available */ 545 matches_num = (size_t)(i - 1); |
508 509 /* newline to get on next line from command line */ 510 (void)fprintf(el->el_outfile, "\n"); 511 512 /* 513 * If there are too many items, ask user for display 514 * confirmation. 515 */ 516 if (matches_num > query_items) { 517 (void)fprintf(el->el_outfile, 518 "Display all %zu possibilities? (y or n) ", 519 matches_num); 520 (void)fflush(el->el_outfile); 521 if (getc(stdin) != 'y') 522 match_display = 0; 523 (void)fprintf(el->el_outfile, "\n"); 524 } 525 | 546 547 /* newline to get on next line from command line */ 548 (void)fprintf(el->el_outfile, "\n"); 549 550 /* 551 * If there are too many items, ask user for display 552 * confirmation. 553 */ 554 if (matches_num > query_items) { 555 (void)fprintf(el->el_outfile, 556 "Display all %zu possibilities? (y or n) ", 557 matches_num); 558 (void)fflush(el->el_outfile); 559 if (getc(stdin) != 'y') 560 match_display = 0; 561 (void)fprintf(el->el_outfile, "\n"); 562 } 563 |
526 if (match_display) 527 fn_display_match_list(el, matches, matches_num, 528 maxlen); | 564 if (match_display) { 565 /* 566 * Interface of this function requires the 567 * strings be matches[1..num-1] for compat. 568 * We have matches_num strings not counting 569 * the prefix in matches[0], so we need to 570 * add 1 to matches_num for the call. 571 */ 572 fn_display_match_list(el, matches, 573 matches_num+1, maxlen); 574 } |
529 retval = CC_REDISPLAY; 530 } else if (matches[0][0]) { 531 /* 532 * There was some common match, but the name was 533 * not complete enough. Next tab will print possible 534 * completions. 535 */ 536 el_beep(el); 537 } else { 538 /* lcd is not a valid object - further specification */ 539 /* is needed */ 540 el_beep(el); 541 retval = CC_NORM; 542 } 543 544free_matches: 545 /* free elements of array and the array itself */ 546 for (i = 0; matches[i]; i++) | 575 retval = CC_REDISPLAY; 576 } else if (matches[0][0]) { 577 /* 578 * There was some common match, but the name was 579 * not complete enough. Next tab will print possible 580 * completions. 581 */ 582 el_beep(el); 583 } else { 584 /* lcd is not a valid object - further specification */ 585 /* is needed */ 586 el_beep(el); 587 retval = CC_NORM; 588 } 589 590free_matches: 591 /* free elements of array and the array itself */ 592 for (i = 0; matches[i]; i++) |
547 free(matches[i]); 548 free(matches); | 593 el_free(matches[i]); 594 el_free(matches); |
549 matches = NULL; 550 } 551 free(dequoted_temp); | 595 matches = NULL; 596 } 597 free(dequoted_temp); |
552#if defined(__SSP__) || defined(__SSP_ALL__) 553 free(temp); 554#endif | 598 el_free(temp); |
555 return retval; 556} 557 | 599 return retval; 600} 601 |
558 | |
559/* 560 * el-compatible wrapper around rl_complete; needed for key binding 561 */ 562/* ARGSUSED */ 563unsigned char 564_el_fn_complete(EditLine *el, int ch __attribute__((__unused__))) 565{ 566 return (unsigned char)fn_complete(el, NULL, NULL, | 602/* 603 * el-compatible wrapper around rl_complete; needed for key binding 604 */ 605/* ARGSUSED */ 606unsigned char 607_el_fn_complete(EditLine *el, int ch __attribute__((__unused__))) 608{ 609 return (unsigned char)fn_complete(el, NULL, NULL, |
567 break_chars, NULL, NULL, 100, | 610 break_chars, NULL, NULL, (size_t)100, |
568 NULL, NULL, NULL, NULL, 569 NULL, NULL, NULL); 570} 571 | 611 NULL, NULL, NULL, NULL, 612 NULL, NULL, NULL); 613} 614 |
572 573static const char * 574sh_find_word_start(const char *buffer, const char *cursor) | 615static const Char * 616sh_find_word_start(const Char *buffer, const Char *cursor) |
575{ | 617{ |
576 const char *word_start = buffer; | 618 const Char *word_start = buffer; |
577 578 while (buffer < cursor) { 579 if (*buffer == '\\') 580 buffer++; | 619 620 while (buffer < cursor) { 621 if (*buffer == '\\') 622 buffer++; |
581 else if (strchr(break_chars, *buffer)) | 623 else if (Strchr(break_chars, *buffer)) |
582 word_start = buffer + 1; | 624 word_start = buffer + 1; |
583 | |
584 buffer++; 585 } | 625 buffer++; 626 } |
586 | |
587 return word_start; 588} 589 | 627 return word_start; 628} 629 |
590 | |
591static char * 592sh_quote(const char *str) 593{ 594 const char *src; 595 int extra_len = 0; 596 char *quoted_str, *dst; 597 | 630static char * 631sh_quote(const char *str) 632{ 633 const char *src; 634 int extra_len = 0; 635 char *quoted_str, *dst; 636 |
598 if (*str == '-' || *str == '+') 599 extra_len += 2; 600 for (src = str; *src != '\0'; src++) 601 if (strchr(break_chars, *src) || 602 strchr(extra_quote_chars, *src)) | 637 for (src = str; *src != '\0'; src++) 638 if (Strchr(break_chars, *src) || 639 Strchr(extra_quote_chars, *src)) |
603 extra_len++; 604 605 quoted_str = malloc(sizeof(*quoted_str) * | 640 extra_len++; 641 642 quoted_str = malloc(sizeof(*quoted_str) * |
606 (strlen(str) + extra_len + 1)); | 643 (strlen(str) + extra_len + 1)); |
607 if (quoted_str == NULL) 608 return NULL; 609 610 dst = quoted_str; | 644 if (quoted_str == NULL) 645 return NULL; 646 647 dst = quoted_str; |
611 if (*str == '-' || *str == '+') 612 *dst++ = '.', *dst++ = '/'; | |
613 for (src = str; *src != '\0'; src++) { | 648 for (src = str; *src != '\0'; src++) { |
614 if (strchr(break_chars, *src) || 615 strchr(extra_quote_chars, *src)) | 649 if (Strchr(break_chars, *src) || 650 Strchr(extra_quote_chars, *src)) |
616 *dst++ = '\\'; 617 *dst++ = *src; 618 } 619 *dst = '\0'; 620 621 return quoted_str; 622} 623 | 651 *dst++ = '\\'; 652 *dst++ = *src; 653 } 654 *dst = '\0'; 655 656 return quoted_str; 657} 658 |
624 625static char * 626sh_dequote(const char *str) | 659static Char * 660sh_dequote(const Char *str) |
627{ | 661{ |
628 char *dequoted_str, *dst; | 662 Char *dequoted_str, *dst; |
629 630 /* save extra space to replace \~ with ./~ */ | 663 664 /* save extra space to replace \~ with ./~ */ |
631 dequoted_str = malloc(sizeof(*dequoted_str) * (strlen(str) + 1 + 1)); | 665 dequoted_str = malloc(sizeof(*dequoted_str) * (Strlen(str) + 1 + 1)); |
632 if (dequoted_str == NULL) 633 return NULL; 634 635 dst = dequoted_str; 636 637 /* dequote \~ at start as ./~ */ 638 if (*str == '\\' && str[1] == '~') { 639 str++; --- 7 unchanged lines hidden (view full) --- 647 if (*str) 648 *dst++ = *str++; 649 } 650 *dst = '\0'; 651 652 return dequoted_str; 653} 654 | 666 if (dequoted_str == NULL) 667 return NULL; 668 669 dst = dequoted_str; 670 671 /* dequote \~ at start as ./~ */ 672 if (*str == '\\' && str[1] == '~') { 673 str++; --- 7 unchanged lines hidden (view full) --- 681 if (*str) 682 *dst++ = *str++; 683 } 684 *dst = '\0'; 685 686 return dequoted_str; 687} 688 |
655 | |
656/* 657 * completion function using sh quoting rules; for key binding 658 */ 659/* ARGSUSED */ 660unsigned char 661_el_fn_sh_complete(EditLine *el, int ch __attribute__((__unused__))) 662{ 663 return (unsigned char)fn_complete(el, NULL, NULL, 664 break_chars, NULL, NULL, 100, 665 NULL, NULL, NULL, NULL, 666 sh_find_word_start, sh_dequote, sh_quote); 667} | 689/* 690 * completion function using sh quoting rules; for key binding 691 */ 692/* ARGSUSED */ 693unsigned char 694_el_fn_sh_complete(EditLine *el, int ch __attribute__((__unused__))) 695{ 696 return (unsigned char)fn_complete(el, NULL, NULL, 697 break_chars, NULL, NULL, 100, 698 NULL, NULL, NULL, NULL, 699 sh_find_word_start, sh_dequote, sh_quote); 700} |