]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - readline/readline/tilde.c
Move readline to the readline/readline subdirectory
[thirdparty/binutils-gdb.git] / readline / readline / tilde.c
CommitLineData
d60d9f65
SS
1/* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */
2
cb41b9e7 3/* Copyright (C) 1988-2017 Free Software Foundation, Inc.
d60d9f65 4
cc88a640
JK
5 This file is part of the GNU Readline Library (Readline), a library
6 for reading lines of text with interactive input and history editing.
d60d9f65 7
cc88a640
JK
8 Readline is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
d60d9f65 12
cc88a640
JK
13 Readline is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
d60d9f65
SS
17
18 You should have received a copy of the GNU General Public License
cc88a640
JK
19 along with Readline. If not, see <http://www.gnu.org/licenses/>.
20*/
d60d9f65
SS
21
22#if defined (HAVE_CONFIG_H)
23# include <config.h>
24#endif
25
26#if defined (HAVE_UNISTD_H)
27# ifdef _MINIX
28# include <sys/types.h>
29# endif
30# include <unistd.h>
31#endif
32
33#if defined (HAVE_STRING_H)
34# include <string.h>
35#else /* !HAVE_STRING_H */
36# include <strings.h>
37#endif /* !HAVE_STRING_H */
38
39#if defined (HAVE_STDLIB_H)
40# include <stdlib.h>
41#else
42# include "ansi_stdlib.h"
43#endif /* HAVE_STDLIB_H */
44
45#include <sys/types.h>
5bdf8622 46#if defined (HAVE_PWD_H)
d60d9f65 47#include <pwd.h>
5bdf8622 48#endif
d60d9f65
SS
49
50#include "tilde.h"
51
1b17e766 52#if defined (TEST) || defined (STATIC_MALLOC)
9255ee31 53static void *xmalloc (), *xrealloc ();
1b17e766 54#else
9255ee31 55# include "xmalloc.h"
1b17e766
EZ
56#endif /* TEST || STATIC_MALLOC */
57
5bdf8622
DJ
58#if !defined (HAVE_GETPW_DECLS)
59# if defined (HAVE_GETPWUID)
9255ee31 60extern struct passwd *getpwuid PARAMS((uid_t));
5bdf8622
DJ
61# endif
62# if defined (HAVE_GETPWNAM)
9255ee31 63extern struct passwd *getpwnam PARAMS((const char *));
5bdf8622
DJ
64# endif
65#endif /* !HAVE_GETPW_DECLS */
d60d9f65
SS
66
67#if !defined (savestring)
9255ee31 68#define savestring(x) strcpy ((char *)xmalloc (1 + strlen (x)), (x))
d60d9f65
SS
69#endif /* !savestring */
70
71#if !defined (NULL)
72# if defined (__STDC__)
73# define NULL ((void *) 0)
74# else
75# define NULL 0x0
76# endif /* !__STDC__ */
77#endif /* !NULL */
78
c862e87b
JM
79/* If being compiled as part of bash, these will be satisfied from
80 variables.o. If being compiled as part of readline, they will
81 be satisfied from shell.o. */
9255ee31
EZ
82extern char *sh_get_home_dir PARAMS((void));
83extern char *sh_get_env_value PARAMS((const char *));
c862e87b 84
d60d9f65
SS
85/* The default value of tilde_additional_prefixes. This is set to
86 whitespace preceding a tilde so that simple programs which do not
87 perform any word separation get desired behaviour. */
9255ee31
EZ
88static const char *default_prefixes[] =
89 { " ~", "\t~", (const char *)NULL };
d60d9f65
SS
90
91/* The default value of tilde_additional_suffixes. This is set to
92 whitespace or newline so that simple programs which do not
93 perform any word separation get desired behaviour. */
9255ee31
EZ
94static const char *default_suffixes[] =
95 { " ", "\n", (const char *)NULL };
d60d9f65
SS
96
97/* If non-null, this contains the address of a function that the application
98 wants called before trying the standard tilde expansions. The function
99 is called with the text sans tilde, and returns a malloc()'ed string
100 which is the expansion, or a NULL pointer if the expansion fails. */
9255ee31 101tilde_hook_func_t *tilde_expansion_preexpansion_hook = (tilde_hook_func_t *)NULL;
d60d9f65
SS
102
103/* If non-null, this contains the address of a function to call if the
104 standard meaning for expanding a tilde fails. The function is called
105 with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
106 which is the expansion, or a NULL pointer if there is no expansion. */
9255ee31 107tilde_hook_func_t *tilde_expansion_failure_hook = (tilde_hook_func_t *)NULL;
d60d9f65
SS
108
109/* When non-null, this is a NULL terminated array of strings which
110 are duplicates for a tilde prefix. Bash uses this to expand
111 `=~' and `:~'. */
9255ee31 112char **tilde_additional_prefixes = (char **)default_prefixes;
d60d9f65
SS
113
114/* When non-null, this is a NULL terminated array of strings which match
115 the end of a username, instead of just "/". Bash sets this to
116 `:' and `=~'. */
9255ee31
EZ
117char **tilde_additional_suffixes = (char **)default_suffixes;
118
119static int tilde_find_prefix PARAMS((const char *, int *));
120static int tilde_find_suffix PARAMS((const char *));
121static char *isolate_tilde_prefix PARAMS((const char *, int *));
122static char *glue_prefix_and_suffix PARAMS((char *, const char *, int));
d60d9f65
SS
123
124/* Find the start of a tilde expansion in STRING, and return the index of
125 the tilde which starts the expansion. Place the length of the text
126 which identified this tilde starter in LEN, excluding the tilde itself. */
127static int
cb41b9e7 128tilde_find_prefix (const char *string, int *len)
d60d9f65
SS
129{
130 register int i, j, string_len;
1b17e766
EZ
131 register char **prefixes;
132
133 prefixes = tilde_additional_prefixes;
d60d9f65
SS
134
135 string_len = strlen (string);
136 *len = 0;
137
138 if (*string == '\0' || *string == '~')
139 return (0);
140
141 if (prefixes)
142 {
143 for (i = 0; i < string_len; i++)
144 {
145 for (j = 0; prefixes[j]; j++)
146 {
147 if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
148 {
149 *len = strlen (prefixes[j]) - 1;
150 return (i + *len);
151 }
152 }
153 }
154 }
155 return (string_len);
156}
157
158/* Find the end of a tilde expansion in STRING, and return the index of
159 the character which ends the tilde definition. */
160static int
cb41b9e7 161tilde_find_suffix (const char *string)
d60d9f65
SS
162{
163 register int i, j, string_len;
164 register char **suffixes;
165
166 suffixes = tilde_additional_suffixes;
167 string_len = strlen (string);
168
169 for (i = 0; i < string_len; i++)
170 {
1b17e766
EZ
171#if defined (__MSDOS__)
172 if (string[i] == '/' || string[i] == '\\' /* || !string[i] */)
173#else
d60d9f65 174 if (string[i] == '/' /* || !string[i] */)
1b17e766 175#endif
d60d9f65
SS
176 break;
177
178 for (j = 0; suffixes && suffixes[j]; j++)
179 {
180 if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
181 return (i);
182 }
183 }
184 return (i);
185}
186
d60d9f65
SS
187/* Return a new string which is the result of tilde expanding STRING. */
188char *
cb41b9e7 189tilde_expand (const char *string)
d60d9f65
SS
190{
191 char *result;
192 int result_size, result_index;
193
194 result_index = result_size = 0;
195 if (result = strchr (string, '~'))
9255ee31 196 result = (char *)xmalloc (result_size = (strlen (string) + 16));
d60d9f65 197 else
9255ee31 198 result = (char *)xmalloc (result_size = (strlen (string) + 1));
d60d9f65
SS
199
200 /* Scan through STRING expanding tildes as we come to them. */
201 while (1)
202 {
203 register int start, end;
204 char *tilde_word, *expansion;
205 int len;
206
207 /* Make START point to the tilde which starts the expansion. */
208 start = tilde_find_prefix (string, &len);
209
210 /* Copy the skipped text into the result. */
211 if ((result_index + start + 1) > result_size)
9255ee31 212 result = (char *)xrealloc (result, 1 + (result_size += (start + 20)));
d60d9f65
SS
213
214 strncpy (result + result_index, string, start);
215 result_index += start;
216
217 /* Advance STRING to the starting tilde. */
218 string += start;
219
220 /* Make END be the index of one after the last character of the
221 username. */
222 end = tilde_find_suffix (string);
223
224 /* If both START and END are zero, we are all done. */
225 if (!start && !end)
226 break;
227
228 /* Expand the entire tilde word, and copy it into RESULT. */
9255ee31 229 tilde_word = (char *)xmalloc (1 + end);
d60d9f65
SS
230 strncpy (tilde_word, string, end);
231 tilde_word[end] = '\0';
232 string += end;
233
234 expansion = tilde_expand_word (tilde_word);
775e241e
TT
235
236 if (expansion == 0)
237 expansion = tilde_word;
238 else
239 xfree (tilde_word);
d60d9f65
SS
240
241 len = strlen (expansion);
9255ee31 242#ifdef __CYGWIN__
1b17e766 243 /* Fix for Cygwin to prevent ~user/xxx from expanding to //xxx when
9255ee31 244 $HOME for `user' is /. On cygwin, // denotes a network drive. */
1b17e766
EZ
245 if (len > 1 || *expansion != '/' || *string != '/')
246#endif
247 {
248 if ((result_index + len + 1) > result_size)
9255ee31 249 result = (char *)xrealloc (result, 1 + (result_size += (len + 20)));
d60d9f65 250
1b17e766
EZ
251 strcpy (result + result_index, expansion);
252 result_index += len;
253 }
cc88a640 254 xfree (expansion);
d60d9f65
SS
255 }
256
257 result[result_index] = '\0';
258
259 return (result);
260}
261
262/* Take FNAME and return the tilde prefix we want expanded. If LENP is
263 non-null, the index of the end of the prefix into FNAME is returned in
264 the location it points to. */
265static char *
cb41b9e7 266isolate_tilde_prefix (const char *fname, int *lenp)
d60d9f65
SS
267{
268 char *ret;
269 int i;
270
9255ee31 271 ret = (char *)xmalloc (strlen (fname));
1b17e766
EZ
272#if defined (__MSDOS__)
273 for (i = 1; fname[i] && fname[i] != '/' && fname[i] != '\\'; i++)
274#else
d60d9f65 275 for (i = 1; fname[i] && fname[i] != '/'; i++)
1b17e766 276#endif
d60d9f65
SS
277 ret[i - 1] = fname[i];
278 ret[i - 1] = '\0';
279 if (lenp)
280 *lenp = i;
281 return ret;
282}
283
5bdf8622
DJ
284#if 0
285/* Public function to scan a string (FNAME) beginning with a tilde and find
286 the portion of the string that should be passed to the tilde expansion
287 function. Right now, it just calls tilde_find_suffix and allocates new
288 memory, but it can be expanded to do different things later. */
289char *
cb41b9e7 290tilde_find_word (const char *fname, int flags, int *lenp)
5bdf8622
DJ
291{
292 int x;
293 char *r;
294
295 x = tilde_find_suffix (fname);
296 if (x == 0)
297 {
298 r = savestring (fname);
299 if (lenp)
300 *lenp = 0;
301 }
302 else
303 {
304 r = (char *)xmalloc (1 + x);
305 strncpy (r, fname, x);
306 r[x] = '\0';
307 if (lenp)
308 *lenp = x;
309 }
310
311 return r;
312}
313#endif
314
d60d9f65
SS
315/* Return a string that is PREFIX concatenated with SUFFIX starting at
316 SUFFIND. */
317static char *
cb41b9e7 318glue_prefix_and_suffix (char *prefix, const char *suffix, int suffind)
d60d9f65
SS
319{
320 char *ret;
321 int plen, slen;
322
323 plen = (prefix && *prefix) ? strlen (prefix) : 0;
324 slen = strlen (suffix + suffind);
9255ee31 325 ret = (char *)xmalloc (plen + slen + 1);
1b17e766 326 if (plen)
d60d9f65
SS
327 strcpy (ret, prefix);
328 strcpy (ret + plen, suffix + suffind);
329 return ret;
330}
331
d60d9f65
SS
332/* Do the work of tilde expansion on FILENAME. FILENAME starts with a
333 tilde. If there is no expansion, call tilde_expansion_failure_hook.
334 This always returns a newly-allocated string, never static storage. */
335char *
cb41b9e7 336tilde_expand_word (const char *filename)
d60d9f65
SS
337{
338 char *dirname, *expansion, *username;
339 int user_len;
340 struct passwd *user_entry;
341
342 if (filename == 0)
343 return ((char *)NULL);
344
345 if (*filename != '~')
346 return (savestring (filename));
347
348 /* A leading `~/' or a bare `~' is *always* translated to the value of
349 $HOME or the home directory of the current user, regardless of any
350 preexpansion hook. */
351 if (filename[1] == '\0' || filename[1] == '/')
352 {
353 /* Prefix $HOME to the rest of the string. */
9255ee31 354 expansion = sh_get_env_value ("HOME");
775e241e
TT
355#if defined (_WIN32)
356 if (expansion == 0)
7f3c5ec8
EZ
357 expansion = sh_get_env_value ("APPDATA");
358#endif
d60d9f65
SS
359
360 /* If there is no HOME variable, look up the directory in
361 the password database. */
362 if (expansion == 0)
9255ee31 363 expansion = sh_get_home_dir ();
d60d9f65
SS
364
365 return (glue_prefix_and_suffix (expansion, filename, 1));
366 }
367
368 username = isolate_tilde_prefix (filename, &user_len);
369
370 if (tilde_expansion_preexpansion_hook)
371 {
372 expansion = (*tilde_expansion_preexpansion_hook) (username);
373 if (expansion)
374 {
375 dirname = glue_prefix_and_suffix (expansion, filename, user_len);
cc88a640
JK
376 xfree (username);
377 xfree (expansion);
d60d9f65
SS
378 return (dirname);
379 }
380 }
381
382 /* No preexpansion hook, or the preexpansion hook failed. Look in the
383 password database. */
384 dirname = (char *)NULL;
5bdf8622 385#if defined (HAVE_GETPWNAM)
d60d9f65 386 user_entry = getpwnam (username);
5bdf8622
DJ
387#else
388 user_entry = 0;
389#endif
d60d9f65
SS
390 if (user_entry == 0)
391 {
392 /* If the calling program has a special syntax for expanding tildes,
393 and we couldn't find a standard expansion, then let them try. */
394 if (tilde_expansion_failure_hook)
395 {
396 expansion = (*tilde_expansion_failure_hook) (username);
397 if (expansion)
398 {
399 dirname = glue_prefix_and_suffix (expansion, filename, user_len);
cc88a640 400 xfree (expansion);
d60d9f65
SS
401 }
402 }
d60d9f65
SS
403 /* If we don't have a failure hook, or if the failure hook did not
404 expand the tilde, return a copy of what we were passed. */
405 if (dirname == 0)
406 dirname = savestring (filename);
407 }
5bdf8622 408#if defined (HAVE_GETPWENT)
d60d9f65 409 else
cc88a640
JK
410 dirname = glue_prefix_and_suffix (user_entry->pw_dir, filename, user_len);
411#endif
412
413 xfree (username);
414#if defined (HAVE_GETPWENT)
d60d9f65 415 endpwent ();
430b7832 416#endif
d60d9f65
SS
417 return (dirname);
418}
419
420\f
421#if defined (TEST)
422#undef NULL
423#include <stdio.h>
424
cb41b9e7 425main (int argc, char **argv)
d60d9f65
SS
426{
427 char *result, line[512];
428 int done = 0;
429
430 while (!done)
431 {
432 printf ("~expand: ");
433 fflush (stdout);
434
435 if (!gets (line))
436 strcpy (line, "done");
437
438 if ((strcmp (line, "done") == 0) ||
439 (strcmp (line, "quit") == 0) ||
440 (strcmp (line, "exit") == 0))
441 {
442 done = 1;
443 break;
444 }
445
446 result = tilde_expand (line);
447 printf (" --> %s\n", result);
448 free (result);
449 }
450 exit (0);
451}
452
cb41b9e7 453static void memory_error_and_abort (void);
d60d9f65 454
9255ee31 455static void *
cb41b9e7 456xmalloc (size_t bytes)
d60d9f65 457{
9255ee31 458 void *temp = (char *)malloc (bytes);
d60d9f65
SS
459
460 if (!temp)
461 memory_error_and_abort ();
462 return (temp);
463}
464
9255ee31 465static void *
cb41b9e7 466xrealloc (void *pointer, int bytes)
d60d9f65 467{
9255ee31 468 void *temp;
d60d9f65
SS
469
470 if (!pointer)
9255ee31 471 temp = malloc (bytes);
d60d9f65 472 else
9255ee31 473 temp = realloc (pointer, bytes);
d60d9f65
SS
474
475 if (!temp)
476 memory_error_and_abort ();
477
478 return (temp);
479}
480
481static void
cb41b9e7 482memory_error_and_abort (void)
d60d9f65
SS
483{
484 fprintf (stderr, "readline: out of virtual memory\n");
485 abort ();
486}
487
488/*
489 * Local variables:
490 * compile-command: "gcc -g -DTEST -o tilde tilde.c"
491 * end:
492 */
493#endif /* TEST */