1 /* tilde.c -- tilde expansion code (~/foo := $HOME/foo).
2 $Id: tilde.c,v 1.3 2004/04/11 17:56:46 karl Exp $
4 Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1996, 1998, 1999,
5 2002, 2004 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. */
27 #if defined (TEST) || defined (STATIC_MALLOC)
28 static void *xmalloc (), *xrealloc ();
29 #endif /* TEST || STATIC_MALLOC */
31 /* The default value of tilde_additional_prefixes. This is set to
32 whitespace preceding a tilde so that simple programs which do not
33 perform any word separation get desired behaviour. */
34 static char *default_prefixes[] =
35 { " ~", "\t~", (char *)NULL };
37 /* The default value of tilde_additional_suffixes. This is set to
38 whitespace or newline so that simple programs which do not
39 perform any word separation get desired behaviour. */
40 static char *default_suffixes[] =
41 { " ", "\n", (char *)NULL };
43 /* If non-null, this contains the address of a function to call if the
44 standard meaning for expanding a tilde fails. The function is called
45 with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
46 which is the expansion, or a NULL pointer if there is no expansion. */
47 CFunction *tilde_expansion_failure_hook = (CFunction *)NULL;
49 /* When non-null, this is a NULL terminated array of strings which
50 are duplicates for a tilde prefix. Bash uses this to expand
52 char **tilde_additional_prefixes = default_prefixes;
54 /* When non-null, this is a NULL terminated array of strings which match
55 the end of a username, instead of just "/". Bash sets this to
57 char **tilde_additional_suffixes = default_suffixes;
59 /* Find the start of a tilde expansion in STRING, and return the index of
60 the tilde which starts the expansion. Place the length of the text
61 which identified this tilde starter in LEN, excluding the tilde itself. */
63 tilde_find_prefix (char *string, int *len)
65 register int i, j, string_len;
66 register char **prefixes = tilde_additional_prefixes;
68 string_len = strlen (string);
71 if (!*string || *string == '~')
76 for (i = 0; i < string_len; i++)
78 for (j = 0; prefixes[j]; j++)
80 if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
82 *len = strlen (prefixes[j]) - 1;
91 /* Find the end of a tilde expansion in STRING, and return the index of
92 the character which ends the tilde definition. */
94 tilde_find_suffix (char *string)
96 register int i, j, string_len;
97 register char **suffixes = tilde_additional_suffixes;
99 string_len = strlen (string);
101 for (i = 0; i < string_len; i++)
103 if (IS_SLASH (string[i]) || !string[i])
106 for (j = 0; suffixes && suffixes[j]; j++)
108 if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
115 /* Return a new string which is the result of tilde expanding STRING. */
117 tilde_expand (char *string)
120 int result_size, result_index;
122 result_size = result_index = 0;
123 result = (char *)NULL;
125 /* Scan through STRING expanding tildes as we come to them. */
128 register int start, end;
129 char *tilde_word, *expansion;
132 /* Make START point to the tilde which starts the expansion. */
133 start = tilde_find_prefix (string, &len);
135 /* Copy the skipped text into the result. */
136 if ((result_index + start + 1) > result_size)
137 result = (char *)xrealloc (result, 1 + (result_size += (start + 20)));
139 strncpy (result + result_index, string, start);
140 result_index += start;
142 /* Advance STRING to the starting tilde. */
145 /* Make END be the index of one after the last character of the
147 end = tilde_find_suffix (string);
149 /* If both START and END are zero, we are all done. */
153 /* Expand the entire tilde word, and copy it into RESULT. */
154 tilde_word = (char *)xmalloc (1 + end);
155 strncpy (tilde_word, string, end);
156 tilde_word[end] = '\0';
159 expansion = tilde_expand_word (tilde_word);
162 len = strlen (expansion);
163 if ((result_index + len + 1) > result_size)
164 result = (char *)xrealloc (result, 1 + (result_size += (len + 20)));
166 strcpy (result + result_index, expansion);
171 result[result_index] = '\0';
176 /* Do the work of tilde expansion on FILENAME. FILENAME starts with a
177 tilde. If there is no expansion, call tilde_expansion_failure_hook. */
179 tilde_expand_word (char *filename)
181 char *dirname = filename ? xstrdup (filename) : NULL;
183 if (dirname && *dirname == '~')
186 if (!dirname[1] || IS_SLASH (dirname[1]))
188 /* Prepend $HOME to the rest of the string. */
189 char *temp_home = getenv ("HOME");
191 /* If there is no HOME variable, look up the directory in
192 the password database. */
195 struct passwd *entry;
197 entry = (struct passwd *) getpwuid (getuid ());
199 temp_home = entry->pw_dir;
202 temp_name = xmalloc (1 + strlen (&dirname[1])
203 + (temp_home ? strlen (temp_home) : 0));
205 strcpy (temp_name, temp_home);
208 strcat (temp_name, &dirname[1]);
210 dirname = xstrdup (temp_name);
215 struct passwd *user_entry;
216 char *username = xmalloc (257);
219 for (i = 1; (c = dirname[i]); i++)
228 if (!(user_entry = (struct passwd *) getpwnam (username)))
230 /* If the calling program has a special syntax for
231 expanding tildes, and we couldn't find a standard
232 expansion, then let them try. */
233 if (tilde_expansion_failure_hook)
235 char *expansion = (*tilde_expansion_failure_hook) (username);
239 temp_name = xmalloc (1 + strlen (expansion)
240 + strlen (&dirname[i]));
241 strcpy (temp_name, expansion);
242 strcat (temp_name, &dirname[i]);
247 /* We shouldn't report errors. */
251 temp_name = xmalloc (1 + strlen (user_entry->pw_dir)
252 + strlen (&dirname[i]));
253 strcpy (temp_name, user_entry->pw_dir);
254 strcat (temp_name, &dirname[i]);
258 dirname = xstrdup (temp_name);
278 char *result, line[512];
283 printf ("~expand: ");
287 strcpy (line, "done");
289 if ((strcmp (line, "done") == 0) ||
290 (strcmp (line, "quit") == 0) ||
291 (strcmp (line, "exit") == 0))
297 result = tilde_expand (line);
298 printf (" --> %s\n", result);
304 static void memory_error_and_abort ();
310 void *temp = (void *)malloc (bytes);
313 memory_error_and_abort ();
318 xrealloc (pointer, bytes)
325 temp = (char *)malloc (bytes);
327 temp = (char *)realloc (pointer, bytes);
330 memory_error_and_abort ();
336 memory_error_and_abort ()
338 fprintf (stderr, _("readline: Out of virtual memory!\n"));