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_STRING_H)
24 #else /* !HAVE_STRING_H */
26 #endif /* !HAVE_STRING_H */
28 #if defined (HAVE_STDLIB_H)
31 # include "ansi_stdlib.h"
32 #endif /* HAVE_STDLIB_H */
35 #include <sys/types.h>
38 #if defined (USG) && !defined (HAVE_GETPW_DECLS)
39 extern struct passwd *getpwuid (), *getpwnam ();
40 #endif /* USG && !defined (HAVE_GETPW_DECLS) */
42 #if !defined (savestring)
43 extern char *xmalloc ();
45 extern char *strcpy ();
47 #define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
48 #endif /* !savestring */
51 # if defined (__STDC__)
52 # define NULL ((void *) 0)
55 # endif /* !__STDC__ */
58 #if defined (TEST) || defined (STATIC_MALLOC)
59 static char *xmalloc (), *xrealloc ();
61 extern char *xmalloc (), *xrealloc ();
62 #endif /* TEST || STATIC_MALLOC */
64 /* The default value of tilde_additional_prefixes. This is set to
65 whitespace preceding a tilde so that simple programs which do not
66 perform any word separation get desired behaviour. */
67 static char *default_prefixes[] =
68 { " ~", "\t~", (char *)NULL };
70 /* The default value of tilde_additional_suffixes. This is set to
71 whitespace or newline so that simple programs which do not
72 perform any word separation get desired behaviour. */
73 static char *default_suffixes[] =
74 { " ", "\n", (char *)NULL };
76 /* If non-null, this contains the address of a function to call if the
77 standard meaning for expanding a tilde fails. The function is called
78 with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
79 which is the expansion, or a NULL pointer if there is no expansion. */
80 CPFunction *tilde_expansion_failure_hook = (CPFunction *)NULL;
82 /* When non-null, this is a NULL terminated array of strings which
83 are duplicates for a tilde prefix. Bash uses this to expand
85 char **tilde_additional_prefixes = default_prefixes;
87 /* When non-null, this is a NULL terminated array of strings which match
88 the end of a username, instead of just "/". Bash sets this to
90 char **tilde_additional_suffixes = default_suffixes;
92 /* Find the start of a tilde expansion in STRING, and return the index of
93 the tilde which starts the expansion. Place the length of the text
94 which identified this tilde starter in LEN, excluding the tilde itself. */
96 tilde_find_prefix (string, len)
100 register int i, j, string_len;
101 register char **prefixes = tilde_additional_prefixes;
103 string_len = strlen (string);
106 if (!*string || *string == '~')
111 for (i = 0; i < string_len; i++)
113 for (j = 0; prefixes[j]; j++)
115 if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
117 *len = strlen (prefixes[j]) - 1;
126 /* Find the end of a tilde expansion in STRING, and return the index of
127 the character which ends the tilde definition. */
129 tilde_find_suffix (string)
132 register int i, j, string_len;
133 register char **suffixes = tilde_additional_suffixes;
135 string_len = strlen (string);
137 for (i = 0; i < string_len; i++)
139 if (string[i] == '/' || !string[i])
142 for (j = 0; suffixes && suffixes[j]; j++)
144 if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
151 /* Return a new string which is the result of tilde expanding STRING. */
153 tilde_expand (string)
156 char *result, *tilde_expand_word ();
157 int result_size, result_index;
159 result_size = result_index = 0;
160 result = (char *)NULL;
162 /* Scan through STRING expanding tildes as we come to them. */
165 register int start, end;
166 char *tilde_word, *expansion;
169 /* Make START point to the tilde which starts the expansion. */
170 start = tilde_find_prefix (string, &len);
172 /* Copy the skipped text into the result. */
173 if ((result_index + start + 1) > result_size)
174 result = (char *)xrealloc (result, 1 + (result_size += (start + 20)));
176 strncpy (result + result_index, string, start);
177 result_index += start;
179 /* Advance STRING to the starting tilde. */
182 /* Make END be the index of one after the last character of the
184 end = tilde_find_suffix (string);
186 /* If both START and END are zero, we are all done. */
190 /* Expand the entire tilde word, and copy it into RESULT. */
191 tilde_word = (char *)xmalloc (1 + end);
192 strncpy (tilde_word, string, end);
193 tilde_word[end] = '\0';
196 expansion = tilde_expand_word (tilde_word);
199 len = strlen (expansion);
200 if ((result_index + len + 1) > result_size)
201 result = (char *)xrealloc (result, 1 + (result_size += (len + 20)));
203 strcpy (result + result_index, expansion);
208 result[result_index] = '\0';
213 /* Do the work of tilde expansion on FILENAME. FILENAME starts with a
214 tilde. If there is no expansion, call tilde_expansion_failure_hook. */
216 tilde_expand_word (filename)
221 dirname = filename ? savestring (filename) : (char *)NULL;
223 if (dirname && *dirname == '~')
226 if (!dirname[1] || dirname[1] == '/')
228 /* Prepend $HOME to the rest of the string. */
229 char *temp_home = (char *)getenv ("HOME");
231 /* If there is no HOME variable, look up the directory in
232 the password database. */
235 struct passwd *entry;
237 entry = getpwuid (getuid ());
239 temp_home = entry->pw_dir;
242 temp_name = xmalloc (1 + strlen (&dirname[1])
243 + (temp_home ? strlen (temp_home) : 0));
246 strcpy (temp_name, temp_home);
247 strcat (temp_name, dirname + 1);
254 struct passwd *user_entry;
257 username = xmalloc (strlen (dirname));
258 for (i = 1; dirname[i] && dirname[i] != '/'; i++)
259 username[i - 1] = dirname[i];
260 username[i - 1] = '\0';
262 if ((user_entry = getpwnam (username)) == 0)
264 /* If the calling program has a special syntax for
265 expanding tildes, and we couldn't find a standard
266 expansion, then let them try. */
267 if (tilde_expansion_failure_hook)
271 expansion = (*tilde_expansion_failure_hook) (username);
275 temp_name = xmalloc (1 + strlen (expansion)
276 + strlen (&dirname[i]));
277 strcpy (temp_name, expansion);
278 strcat (temp_name, &dirname[i]);
284 /* We shouldn't report errors. */
288 temp_name = xmalloc (1 + strlen (user_entry->pw_dir)
289 + strlen (&dirname[i]));
290 strcpy (temp_name, user_entry->pw_dir);
291 strcat (temp_name, &dirname[i]);
311 char *result, line[512];
316 printf ("~expand: ");
320 strcpy (line, "done");
322 if ((strcmp (line, "done") == 0) ||
323 (strcmp (line, "quit") == 0) ||
324 (strcmp (line, "exit") == 0))
330 result = tilde_expand (line);
331 printf (" --> %s\n", result);
337 static void memory_error_and_abort ();
343 char *temp = (char *)malloc (bytes);
346 memory_error_and_abort ();
351 xrealloc (pointer, bytes)
358 temp = (char *)malloc (bytes);
360 temp = (char *)realloc (pointer, bytes);
363 memory_error_and_abort ();
369 memory_error_and_abort ()
371 fprintf (stderr, "readline: Out of virtual memory!\n");
377 * compile-command: "gcc -g -DTEST -o tilde tilde.c"