1 /* tilde.c -- tilde expansion code (~/foo := $HOME/foo).
2 $Id: tilde.c,v 1.13 1999/03/03 22:42:21 karl Exp $
4 Copyright (C) 1988, 89, 90, 91, 92, 93, 96, 98, 99
5 Free Software Foundation, Inc.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 Written by Brian Fox (bfox@ai.mit.edu). */
23 /* Include config.h before doing alloca. */
26 #if defined (TEST) || defined (STATIC_MALLOC)
27 static void *xmalloc (), *xrealloc ();
28 #endif /* TEST || STATIC_MALLOC */
30 /* The default value of tilde_additional_prefixes. This is set to
31 whitespace preceding a tilde so that simple programs which do not
32 perform any word separation get desired behaviour. */
33 static char *default_prefixes[] =
34 { " ~", "\t~", (char *)NULL };
36 /* The default value of tilde_additional_suffixes. This is set to
37 whitespace or newline so that simple programs which do not
38 perform any word separation get desired behaviour. */
39 static char *default_suffixes[] =
40 { " ", "\n", (char *)NULL };
42 /* If non-null, this contains the address of a function to call if the
43 standard meaning for expanding a tilde fails. The function is called
44 with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
45 which is the expansion, or a NULL pointer if there is no expansion. */
46 CFunction *tilde_expansion_failure_hook = (CFunction *)NULL;
48 /* When non-null, this is a NULL terminated array of strings which
49 are duplicates for a tilde prefix. Bash uses this to expand
51 char **tilde_additional_prefixes = default_prefixes;
53 /* When non-null, this is a NULL terminated array of strings which match
54 the end of a username, instead of just "/". Bash sets this to
56 char **tilde_additional_suffixes = default_suffixes;
58 /* Find the start of a tilde expansion in STRING, and return the index of
59 the tilde which starts the expansion. Place the length of the text
60 which identified this tilde starter in LEN, excluding the tilde itself. */
62 tilde_find_prefix (string, len)
66 register int i, j, string_len;
67 register char **prefixes = tilde_additional_prefixes;
69 string_len = strlen (string);
72 if (!*string || *string == '~')
77 for (i = 0; i < string_len; i++)
79 for (j = 0; prefixes[j]; j++)
81 if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
83 *len = strlen (prefixes[j]) - 1;
92 /* Find the end of a tilde expansion in STRING, and return the index of
93 the character which ends the tilde definition. */
95 tilde_find_suffix (string)
98 register int i, j, string_len;
99 register char **suffixes = tilde_additional_suffixes;
101 string_len = strlen (string);
103 for (i = 0; i < string_len; i++)
105 if (IS_SLASH (string[i]) || !string[i])
108 for (j = 0; suffixes && suffixes[j]; j++)
110 if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
117 /* Return a new string which is the result of tilde expanding STRING. */
119 tilde_expand (string)
122 char *result, *tilde_expand_word ();
123 int result_size, result_index;
125 result_size = result_index = 0;
126 result = (char *)NULL;
128 /* Scan through STRING expanding tildes as we come to them. */
131 register int start, end;
132 char *tilde_word, *expansion;
135 /* Make START point to the tilde which starts the expansion. */
136 start = tilde_find_prefix (string, &len);
138 /* Copy the skipped text into the result. */
139 if ((result_index + start + 1) > result_size)
140 result = (char *)xrealloc (result, 1 + (result_size += (start + 20)));
142 strncpy (result + result_index, string, start);
143 result_index += start;
145 /* Advance STRING to the starting tilde. */
148 /* Make END be the index of one after the last character of the
150 end = tilde_find_suffix (string);
152 /* If both START and END are zero, we are all done. */
156 /* Expand the entire tilde word, and copy it into RESULT. */
157 tilde_word = (char *)xmalloc (1 + end);
158 strncpy (tilde_word, string, end);
159 tilde_word[end] = '\0';
162 expansion = tilde_expand_word (tilde_word);
165 len = strlen (expansion);
166 if ((result_index + len + 1) > result_size)
167 result = (char *)xrealloc (result, 1 + (result_size += (len + 20)));
169 strcpy (result + result_index, expansion);
174 result[result_index] = '\0';
179 /* Do the work of tilde expansion on FILENAME. FILENAME starts with a
180 tilde. If there is no expansion, call tilde_expansion_failure_hook. */
182 tilde_expand_word (filename)
185 char *dirname = filename ? xstrdup (filename) : NULL;
187 if (dirname && *dirname == '~')
190 if (!dirname[1] || IS_SLASH (dirname[1]))
192 /* Prepend $HOME to the rest of the string. */
193 char *temp_home = getenv ("HOME");
195 /* If there is no HOME variable, look up the directory in
196 the password database. */
199 struct passwd *entry;
201 entry = (struct passwd *) getpwuid (getuid ());
203 temp_home = entry->pw_dir;
206 temp_name = xmalloc (1 + strlen (&dirname[1])
207 + (temp_home ? strlen (temp_home) : 0));
209 strcpy (temp_name, temp_home);
212 strcat (temp_name, &dirname[1]);
214 dirname = xstrdup (temp_name);
219 struct passwd *user_entry;
220 char *username = xmalloc (257);
223 for (i = 1; (c = dirname[i]); i++)
232 if (!(user_entry = (struct passwd *) getpwnam (username)))
234 /* If the calling program has a special syntax for
235 expanding tildes, and we couldn't find a standard
236 expansion, then let them try. */
237 if (tilde_expansion_failure_hook)
241 expansion = (*tilde_expansion_failure_hook) (username);
245 temp_name = xmalloc (1 + strlen (expansion)
246 + strlen (&dirname[i]));
247 strcpy (temp_name, expansion);
248 strcat (temp_name, &dirname[i]);
253 /* We shouldn't report errors. */
257 temp_name = xmalloc (1 + strlen (user_entry->pw_dir)
258 + strlen (&dirname[i]));
259 strcpy (temp_name, user_entry->pw_dir);
260 strcat (temp_name, &dirname[i]);
264 dirname = xstrdup (temp_name);
284 char *result, line[512];
289 printf ("~expand: ");
293 strcpy (line, "done");
295 if ((strcmp (line, "done") == 0) ||
296 (strcmp (line, "quit") == 0) ||
297 (strcmp (line, "exit") == 0))
303 result = tilde_expand (line);
304 printf (" --> %s\n", result);
310 static void memory_error_and_abort ();
316 void *temp = (void *)malloc (bytes);
319 memory_error_and_abort ();
324 xrealloc (pointer, bytes)
331 temp = (char *)malloc (bytes);
333 temp = (char *)realloc (pointer, bytes);
336 memory_error_and_abort ();
342 memory_error_and_abort ()
344 fprintf (stderr, _("readline: Out of virtual memory!\n"));