]> git.ipfire.org Git - thirdparty/bash.git/blame - lib/readline/tilde.c
updated translations; remove unneeded files
[thirdparty/bash.git] / lib / readline / tilde.c
CommitLineData
726f6388
JA
1/* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */
2
8868edaf 3/* Copyright (C) 1988-2020 Free Software Foundation, Inc.
726f6388 4
3185942a
JA
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.
726f6388 7
3185942a
JA
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.
726f6388 12
3185942a
JA
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.
726f6388
JA
17
18 You should have received a copy of the GNU General Public License
3185942a
JA
19 along with Readline. If not, see <http://www.gnu.org/licenses/>.
20*/
726f6388 21
ccc6cda3
JA
22#if defined (HAVE_CONFIG_H)
23# include <config.h>
24#endif
25
d166f048 26#if defined (HAVE_UNISTD_H)
cce855bc
JA
27# ifdef _MINIX
28# include <sys/types.h>
29# endif
d166f048
JA
30# include <unistd.h>
31#endif
32
726f6388
JA
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
726f6388 45#include <sys/types.h>
95732b49 46#if defined (HAVE_PWD_H)
726f6388 47#include <pwd.h>
95732b49 48#endif
726f6388 49
ccc6cda3
JA
50#include "tilde.h"
51
bb70624e 52#if defined (TEST) || defined (STATIC_MALLOC)
f73dda09 53static void *xmalloc (), *xrealloc ();
bb70624e 54#else
f73dda09 55# include "xmalloc.h"
bb70624e
JA
56#endif /* TEST || STATIC_MALLOC */
57
ccc6cda3 58#if !defined (HAVE_GETPW_DECLS)
95732b49 59# if defined (HAVE_GETPWUID)
8868edaf 60extern struct passwd *getpwuid (uid_t);
95732b49
JA
61# endif
62# if defined (HAVE_GETPWNAM)
8868edaf 63extern struct passwd *getpwnam (const char *);
95732b49 64# endif
ccc6cda3 65#endif /* !HAVE_GETPW_DECLS */
726f6388
JA
66
67#if !defined (savestring)
f73dda09 68#define savestring(x) strcpy ((char *)xmalloc (1 + strlen (x)), (x))
726f6388
JA
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
b72432fd
JA
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. */
8868edaf
CR
82extern char *sh_get_home_dir (void);
83extern char *sh_get_env_value (const char *);
b72432fd 84
726f6388
JA
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. */
28ef6c31
JA
88static const char *default_prefixes[] =
89 { " ~", "\t~", (const char *)NULL };
726f6388
JA
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. */
28ef6c31
JA
94static const char *default_suffixes[] =
95 { " ", "\n", (const char *)NULL };
726f6388 96
d166f048
JA
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. */
28ef6c31 101tilde_hook_func_t *tilde_expansion_preexpansion_hook = (tilde_hook_func_t *)NULL;
d166f048 102
726f6388
JA
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. */
28ef6c31 107tilde_hook_func_t *tilde_expansion_failure_hook = (tilde_hook_func_t *)NULL;
726f6388
JA
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 `:~'. */
28ef6c31 112char **tilde_additional_prefixes = (char **)default_prefixes;
726f6388
JA
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 `=~'. */
28ef6c31 117char **tilde_additional_suffixes = (char **)default_suffixes;
726f6388 118
8868edaf
CR
119static int tilde_find_prefix (const char *, int *);
120static int tilde_find_suffix (const char *);
121static char *isolate_tilde_prefix (const char *, int *);
122static char *glue_prefix_and_suffix (char *, const char *, int);
f73dda09 123
726f6388
JA
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
d233b485 128tilde_find_prefix (const char *string, int *len)
726f6388
JA
129{
130 register int i, j, string_len;
bb70624e
JA
131 register char **prefixes;
132
133 prefixes = tilde_additional_prefixes;
726f6388
JA
134
135 string_len = strlen (string);
136 *len = 0;
137
d166f048 138 if (*string == '\0' || *string == '~')
726f6388
JA
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
d233b485 161tilde_find_suffix (const char *string)
726f6388
JA
162{
163 register int i, j, string_len;
d166f048 164 register char **suffixes;
726f6388 165
d166f048 166 suffixes = tilde_additional_suffixes;
726f6388
JA
167 string_len = strlen (string);
168
169 for (i = 0; i < string_len; i++)
170 {
bb70624e
JA
171#if defined (__MSDOS__)
172 if (string[i] == '/' || string[i] == '\\' /* || !string[i] */)
173#else
d166f048 174 if (string[i] == '/' /* || !string[i] */)
bb70624e 175#endif
726f6388
JA
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
187/* Return a new string which is the result of tilde expanding STRING. */
188char *
d233b485 189tilde_expand (const char *string)
726f6388 190{
d166f048 191 char *result;
726f6388
JA
192 int result_size, result_index;
193
d166f048
JA
194 result_index = result_size = 0;
195 if (result = strchr (string, '~'))
f73dda09 196 result = (char *)xmalloc (result_size = (strlen (string) + 16));
d166f048 197 else
f73dda09 198 result = (char *)xmalloc (result_size = (strlen (string) + 1));
726f6388
JA
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)
f73dda09 212 result = (char *)xrealloc (result, 1 + (result_size += (start + 20)));
726f6388
JA
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. */
f73dda09 229 tilde_word = (char *)xmalloc (1 + end);
726f6388
JA
230 strncpy (tilde_word, string, end);
231 tilde_word[end] = '\0';
232 string += end;
233
234 expansion = tilde_expand_word (tilde_word);
a0c0a00f
CR
235
236 if (expansion == 0)
237 expansion = tilde_word;
238 else
239 xfree (tilde_word);
726f6388
JA
240
241 len = strlen (expansion);
28ef6c31 242#ifdef __CYGWIN__
bb70624e 243 /* Fix for Cygwin to prevent ~user/xxx from expanding to //xxx when
28ef6c31 244 $HOME for `user' is /. On cygwin, // denotes a network drive. */
bb70624e
JA
245 if (len > 1 || *expansion != '/' || *string != '/')
246#endif
247 {
248 if ((result_index + len + 1) > result_size)
f73dda09 249 result = (char *)xrealloc (result, 1 + (result_size += (len + 20)));
726f6388 250
bb70624e
JA
251 strcpy (result + result_index, expansion);
252 result_index += len;
253 }
3185942a 254 xfree (expansion);
726f6388
JA
255 }
256
257 result[result_index] = '\0';
258
259 return (result);
260}
261
d166f048
JA
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 *
d233b485 266isolate_tilde_prefix (const char *fname, int *lenp)
d166f048
JA
267{
268 char *ret;
269 int i;
270
f73dda09 271 ret = (char *)xmalloc (strlen (fname));
bb70624e
JA
272#if defined (__MSDOS__)
273 for (i = 1; fname[i] && fname[i] != '/' && fname[i] != '\\'; i++)
274#else
d166f048 275 for (i = 1; fname[i] && fname[i] != '/'; i++)
bb70624e 276#endif
d166f048
JA
277 ret[i - 1] = fname[i];
278 ret[i - 1] = '\0';
279 if (lenp)
280 *lenp = i;
281 return ret;
282}
283
95732b49
JA
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 *
d233b485 290tilde_find_word (const char *fname, int flags, int *lenp)
95732b49
JA
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
d166f048
JA
315/* Return a string that is PREFIX concatenated with SUFFIX starting at
316 SUFFIND. */
317static char *
d233b485 318glue_prefix_and_suffix (char *prefix, const char *suffix, int suffind)
d166f048
JA
319{
320 char *ret;
321 int plen, slen;
322
323 plen = (prefix && *prefix) ? strlen (prefix) : 0;
324 slen = strlen (suffix + suffind);
f73dda09 325 ret = (char *)xmalloc (plen + slen + 1);
bb70624e 326 if (plen)
d166f048
JA
327 strcpy (ret, prefix);
328 strcpy (ret + plen, suffix + suffind);
329 return ret;
330}
331
726f6388 332/* Do the work of tilde expansion on FILENAME. FILENAME starts with a
d166f048
JA
333 tilde. If there is no expansion, call tilde_expansion_failure_hook.
334 This always returns a newly-allocated string, never static storage. */
726f6388 335char *
d233b485 336tilde_expand_word (const char *filename)
726f6388 337{
d166f048
JA
338 char *dirname, *expansion, *username;
339 int user_len;
340 struct passwd *user_entry;
726f6388 341
d166f048 342 if (filename == 0)
ccc6cda3 343 return ((char *)NULL);
726f6388 344
d166f048
JA
345 if (*filename != '~')
346 return (savestring (filename));
ccc6cda3 347
d166f048
JA
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] == '/')
726f6388 352 {
d166f048 353 /* Prefix $HOME to the rest of the string. */
28ef6c31 354 expansion = sh_get_env_value ("HOME");
a0c0a00f
CR
355#if defined (_WIN32)
356 if (expansion == 0)
357 expansion = sh_get_env_value ("APPDATA");
358#endif
ccc6cda3
JA
359
360 /* If there is no HOME variable, look up the directory in
361 the password database. */
d166f048 362 if (expansion == 0)
28ef6c31 363 expansion = sh_get_home_dir ();
726f6388 364
d166f048 365 return (glue_prefix_and_suffix (expansion, filename, 1));
ccc6cda3 366 }
726f6388 367
d166f048 368 username = isolate_tilde_prefix (filename, &user_len);
ccc6cda3 369
d166f048
JA
370 if (tilde_expansion_preexpansion_hook)
371 {
372 expansion = (*tilde_expansion_preexpansion_hook) (username);
373 if (expansion)
726f6388 374 {
d166f048 375 dirname = glue_prefix_and_suffix (expansion, filename, user_len);
3185942a 376 xfree (username);
495aee44 377 xfree (expansion);
d166f048 378 return (dirname);
726f6388 379 }
d166f048
JA
380 }
381
382 /* No preexpansion hook, or the preexpansion hook failed. Look in the
383 password database. */
384 dirname = (char *)NULL;
95732b49 385#if defined (HAVE_GETPWNAM)
d166f048 386 user_entry = getpwnam (username);
95732b49
JA
387#else
388 user_entry = 0;
389#endif
d166f048
JA
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)
ccc6cda3 395 {
d166f048
JA
396 expansion = (*tilde_expansion_failure_hook) (username);
397 if (expansion)
398 {
399 dirname = glue_prefix_and_suffix (expansion, filename, user_len);
495aee44 400 xfree (expansion);
d166f048 401 }
ccc6cda3 402 }
d166f048
JA
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 }
0628567a 408#if defined (HAVE_GETPWENT)
d166f048 409 else
0628567a
JA
410 dirname = glue_prefix_and_suffix (user_entry->pw_dir, filename, user_len);
411#endif
412
3185942a 413 xfree (username);
95732b49 414#if defined (HAVE_GETPWENT)
d166f048 415 endpwent ();
95732b49 416#endif
726f6388
JA
417 return (dirname);
418}
419
420\f
421#if defined (TEST)
422#undef NULL
423#include <stdio.h>
424
d233b485 425main (int argc, char **argv)
726f6388
JA
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
d233b485 453static void memory_error_and_abort (void);
726f6388 454
f73dda09 455static void *
d233b485 456xmalloc (size_t bytes)
726f6388 457{
f73dda09 458 void *temp = (char *)malloc (bytes);
726f6388
JA
459
460 if (!temp)
461 memory_error_and_abort ();
462 return (temp);
463}
464
f73dda09 465static void *
d233b485 466xrealloc (void *pointer, int bytes)
726f6388 467{
f73dda09 468 void *temp;
726f6388
JA
469
470 if (!pointer)
f73dda09 471 temp = malloc (bytes);
726f6388 472 else
f73dda09 473 temp = realloc (pointer, bytes);
726f6388
JA
474
475 if (!temp)
476 memory_error_and_abort ();
477
478 return (temp);
479}
480
481static void
d233b485 482memory_error_and_abort (void)
726f6388 483{
ccc6cda3 484 fprintf (stderr, "readline: out of virtual memory\n");
726f6388
JA
485 abort ();
486}
487
488/*
489 * Local variables:
490 * compile-command: "gcc -g -DTEST -o tilde tilde.c"
491 * end:
492 */
493#endif /* TEST */