1 /* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */
3 /* Copyright (C) 1988,1989 Free Software Foundation, Inc.
5 This file is part of GNU Readline, a library for reading lines
6 of text with interactive input and history editing.
8 Readline is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 1, or (at your option) any
13 Readline is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Readline; see the file COPYING. If not, write to the Free
20 Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
22 #if defined (HAVE_CONFIG_H)
26 #if defined (HAVE_UNISTD_H)
28 # include <sys/types.h>
33 #if defined (HAVE_STRING_H)
35 #else /* !HAVE_STRING_H */
37 #endif /* !HAVE_STRING_H */
39 #if defined (HAVE_STDLIB_H)
42 # include "ansi_stdlib.h"
43 #endif /* HAVE_STDLIB_H */
45 #include <sys/types.h>
54 #if !defined (HAVE_GETPW_DECLS)
55 extern struct passwd *getpwuid (), *getpwnam ();
56 #endif /* !HAVE_GETPW_DECLS */
58 #if !defined (savestring)
59 extern char *xmalloc ();
61 extern char *strcpy ();
63 #define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
64 #endif /* !savestring */
67 # if defined (__STDC__)
68 # define NULL ((void *) 0)
71 # endif /* !__STDC__ */
74 #if defined (TEST) || defined (STATIC_MALLOC)
75 static char *xmalloc (), *xrealloc ();
77 extern char *xmalloc (), *xrealloc ();
78 #endif /* TEST || STATIC_MALLOC */
80 /* The default value of tilde_additional_prefixes. This is set to
81 whitespace preceding a tilde so that simple programs which do not
82 perform any word separation get desired behaviour. */
83 static char *default_prefixes[] =
84 { " ~", "\t~", (char *)NULL };
86 /* The default value of tilde_additional_suffixes. This is set to
87 whitespace or newline so that simple programs which do not
88 perform any word separation get desired behaviour. */
89 static char *default_suffixes[] =
90 { " ", "\n", (char *)NULL };
92 /* If non-null, this contains the address of a function that the application
93 wants called before trying the standard tilde expansions. The function
94 is called with the text sans tilde, and returns a malloc()'ed string
95 which is the expansion, or a NULL pointer if the expansion fails. */
96 CPFunction *tilde_expansion_preexpansion_hook = (CPFunction *)NULL;
98 /* If non-null, this contains the address of a function to call if the
99 standard meaning for expanding a tilde fails. The function is called
100 with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
101 which is the expansion, or a NULL pointer if there is no expansion. */
102 CPFunction *tilde_expansion_failure_hook = (CPFunction *)NULL;
104 /* When non-null, this is a NULL terminated array of strings which
105 are duplicates for a tilde prefix. Bash uses this to expand
107 char **tilde_additional_prefixes = default_prefixes;
109 /* When non-null, this is a NULL terminated array of strings which match
110 the end of a username, instead of just "/". Bash sets this to
112 char **tilde_additional_suffixes = default_suffixes;
114 /* Find the start of a tilde expansion in STRING, and return the index of
115 the tilde which starts the expansion. Place the length of the text
116 which identified this tilde starter in LEN, excluding the tilde itself. */
118 tilde_find_prefix (string, len)
122 register int i, j, string_len;
123 register char **prefixes = tilde_additional_prefixes;
125 string_len = strlen (string);
128 if (*string == '\0' || *string == '~')
133 for (i = 0; i < string_len; i++)
135 for (j = 0; prefixes[j]; j++)
137 if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
139 *len = strlen (prefixes[j]) - 1;
148 /* Find the end of a tilde expansion in STRING, and return the index of
149 the character which ends the tilde definition. */
151 tilde_find_suffix (string)
154 register int i, j, string_len;
155 register char **suffixes;
157 suffixes = tilde_additional_suffixes;
158 string_len = strlen (string);
160 for (i = 0; i < string_len; i++)
162 if (string[i] == '/' /* || !string[i] */)
165 for (j = 0; suffixes && suffixes[j]; j++)
167 if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
176 get_string_value (varname)
179 return ((char *)getenv (varname));
183 /* Return a new string which is the result of tilde expanding STRING. */
185 tilde_expand (string)
189 int result_size, result_index;
191 result_index = result_size = 0;
192 if (result = strchr (string, '~'))
193 result = xmalloc (result_size = (strlen (string) + 16));
195 result = xmalloc (result_size = (strlen (string) + 1));
197 /* Scan through STRING expanding tildes as we come to them. */
200 register int start, end;
201 char *tilde_word, *expansion;
204 /* Make START point to the tilde which starts the expansion. */
205 start = tilde_find_prefix (string, &len);
207 /* Copy the skipped text into the result. */
208 if ((result_index + start + 1) > result_size)
209 result = xrealloc (result, 1 + (result_size += (start + 20)));
211 strncpy (result + result_index, string, start);
212 result_index += start;
214 /* Advance STRING to the starting tilde. */
217 /* Make END be the index of one after the last character of the
219 end = tilde_find_suffix (string);
221 /* If both START and END are zero, we are all done. */
225 /* Expand the entire tilde word, and copy it into RESULT. */
226 tilde_word = xmalloc (1 + end);
227 strncpy (tilde_word, string, end);
228 tilde_word[end] = '\0';
231 expansion = tilde_expand_word (tilde_word);
234 len = strlen (expansion);
235 if ((result_index + len + 1) > result_size)
236 result = xrealloc (result, 1 + (result_size += (len + 20)));
238 strcpy (result + result_index, expansion);
243 result[result_index] = '\0';
248 /* Take FNAME and return the tilde prefix we want expanded. If LENP is
249 non-null, the index of the end of the prefix into FNAME is returned in
250 the location it points to. */
252 isolate_tilde_prefix (fname, lenp)
259 ret = xmalloc (strlen (fname));
260 for (i = 1; fname[i] && fname[i] != '/'; i++)
261 ret[i - 1] = fname[i];
268 /* Return a string that is PREFIX concatenated with SUFFIX starting at
271 glue_prefix_and_suffix (prefix, suffix, suffind)
272 char *prefix, *suffix;
278 plen = (prefix && *prefix) ? strlen (prefix) : 0;
279 slen = strlen (suffix + suffind);
280 ret = xmalloc (plen + slen + 1);
281 if (prefix && *prefix)
282 strcpy (ret, prefix);
283 strcpy (ret + plen, suffix + suffind);
293 home_dir = (char *)NULL;
294 if (current_user.home_dir == 0)
295 get_current_user_info ();
296 home_dir = current_user.home_dir;
298 struct passwd *entry;
300 home_dir = (char *)NULL;
301 entry = getpwuid (getuid ());
303 home_dir = entry->pw_dir;
308 /* Do the work of tilde expansion on FILENAME. FILENAME starts with a
309 tilde. If there is no expansion, call tilde_expansion_failure_hook.
310 This always returns a newly-allocated string, never static storage. */
312 tilde_expand_word (filename)
315 char *dirname, *expansion, *username;
317 struct passwd *user_entry;
320 return ((char *)NULL);
322 if (*filename != '~')
323 return (savestring (filename));
325 /* A leading `~/' or a bare `~' is *always* translated to the value of
326 $HOME or the home directory of the current user, regardless of any
327 preexpansion hook. */
328 if (filename[1] == '\0' || filename[1] == '/')
330 /* Prefix $HOME to the rest of the string. */
331 expansion = get_string_value ("HOME");
333 /* If there is no HOME variable, look up the directory in
334 the password database. */
336 expansion = get_home_dir ();
338 return (glue_prefix_and_suffix (expansion, filename, 1));
341 username = isolate_tilde_prefix (filename, &user_len);
343 if (tilde_expansion_preexpansion_hook)
345 expansion = (*tilde_expansion_preexpansion_hook) (username);
348 dirname = glue_prefix_and_suffix (expansion, filename, user_len);
355 /* No preexpansion hook, or the preexpansion hook failed. Look in the
356 password database. */
357 dirname = (char *)NULL;
358 user_entry = getpwnam (username);
361 /* If the calling program has a special syntax for expanding tildes,
362 and we couldn't find a standard expansion, then let them try. */
363 if (tilde_expansion_failure_hook)
365 expansion = (*tilde_expansion_failure_hook) (username);
368 dirname = glue_prefix_and_suffix (expansion, filename, user_len);
373 /* If we don't have a failure hook, or if the failure hook did not
374 expand the tilde, return a copy of what we were passed. */
376 dirname = savestring (filename);
381 dirname = glue_prefix_and_suffix (user_entry->pw_dir, filename, user_len);
397 char *result, line[512];
402 printf ("~expand: ");
406 strcpy (line, "done");
408 if ((strcmp (line, "done") == 0) ||
409 (strcmp (line, "quit") == 0) ||
410 (strcmp (line, "exit") == 0))
416 result = tilde_expand (line);
417 printf (" --> %s\n", result);
423 static void memory_error_and_abort ();
429 char *temp = (char *)malloc (bytes);
432 memory_error_and_abort ();
437 xrealloc (pointer, bytes)
444 temp = (char *)malloc (bytes);
446 temp = (char *)realloc (pointer, bytes);
449 memory_error_and_abort ();
455 memory_error_and_abort ()
457 fprintf (stderr, "readline: out of virtual memory\n");
463 * compile-command: "gcc -g -DTEST -o tilde tilde.c"