3 /* tilde.c -- tilde expansion code (~/foo := $HOME/foo).
4 Id: tilde.c,v 1.3 2004/04/11 17:56:46 karl Exp
6 Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1996, 1998, 1999,
7 2002, 2004 Free Software Foundation, Inc.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 Written by Brian Fox (bfox@ai.mit.edu). */
25 /* Include config.h before doing alloca. */
29 #if defined (TEST) || defined (STATIC_MALLOC)
30 static void *xmalloc (), *xrealloc ();
31 #endif /* TEST || STATIC_MALLOC */
33 /* The default value of tilde_additional_prefixes. This is set to
34 whitespace preceding a tilde so that simple programs which do not
35 perform any word separation get desired behaviour. */
36 static char *default_prefixes
[] =
37 { " ~", "\t~", (char *)NULL
};
39 /* The default value of tilde_additional_suffixes. This is set to
40 whitespace or newline so that simple programs which do not
41 perform any word separation get desired behaviour. */
42 static char *default_suffixes
[] =
43 { " ", "\n", (char *)NULL
};
45 /* If non-null, this contains the address of a function to call if the
46 standard meaning for expanding a tilde fails. The function is called
47 with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
48 which is the expansion, or a NULL pointer if there is no expansion. */
49 CFunction
*tilde_expansion_failure_hook
= (CFunction
*)NULL
;
51 /* When non-null, this is a NULL terminated array of strings which
52 are duplicates for a tilde prefix. Bash uses this to expand
54 char **tilde_additional_prefixes
= default_prefixes
;
56 /* When non-null, this is a NULL terminated array of strings which match
57 the end of a username, instead of just "/". Bash sets this to
59 char **tilde_additional_suffixes
= default_suffixes
;
61 /* Find the start of a tilde expansion in STRING, and return the index of
62 the tilde which starts the expansion. Place the length of the text
63 which identified this tilde starter in LEN, excluding the tilde itself. */
65 tilde_find_prefix (char *string
, int *len
)
67 register int i
, j
, string_len
;
68 register char **prefixes
= tilde_additional_prefixes
;
70 string_len
= strlen (string
);
73 if (!*string
|| *string
== '~')
78 for (i
= 0; i
< string_len
; i
++)
80 for (j
= 0; prefixes
[j
]; j
++)
82 if (strncmp (string
+ i
, prefixes
[j
], strlen (prefixes
[j
])) == 0)
84 *len
= strlen (prefixes
[j
]) - 1;
93 /* Find the end of a tilde expansion in STRING, and return the index of
94 the character which ends the tilde definition. */
96 tilde_find_suffix (char *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 (char *string
)
122 int result_size
, result_index
;
124 result_size
= result_index
= 0;
125 result
= (char *)NULL
;
127 /* Scan through STRING expanding tildes as we come to them. */
130 register int start
, end
;
131 char *tilde_word
, *expansion
;
134 /* Make START point to the tilde which starts the expansion. */
135 start
= tilde_find_prefix (string
, &len
);
137 /* Copy the skipped text into the result. */
138 if ((result_index
+ start
+ 1) > result_size
)
139 result
= (char *)xrealloc (result
, 1 + (result_size
+= (start
+ 20)));
141 strncpy (result
+ result_index
, string
, start
);
142 result_index
+= start
;
144 /* Advance STRING to the starting tilde. */
147 /* Make END be the index of one after the last character of the
149 end
= tilde_find_suffix (string
);
151 /* If both START and END are zero, we are all done. */
155 /* Expand the entire tilde word, and copy it into RESULT. */
156 tilde_word
= (char *)xmalloc (1 + end
);
157 strncpy (tilde_word
, string
, end
);
158 tilde_word
[end
] = '\0';
161 expansion
= tilde_expand_word (tilde_word
);
164 len
= strlen (expansion
);
165 if ((result_index
+ len
+ 1) > result_size
)
166 result
= (char *)xrealloc (result
, 1 + (result_size
+= (len
+ 20)));
168 strcpy (result
+ result_index
, expansion
);
173 result
[result_index
] = '\0';
178 /* Do the work of tilde expansion on FILENAME. FILENAME starts with a
179 tilde. If there is no expansion, call tilde_expansion_failure_hook. */
181 tilde_expand_word (char *filename
)
183 char *dirname
= filename
? xstrdup (filename
) : NULL
;
185 if (dirname
&& *dirname
== '~')
188 if (!dirname
[1] || IS_SLASH (dirname
[1]))
190 /* Prepend $HOME to the rest of the string. */
191 char *temp_home
= getenv ("HOME");
193 /* If there is no HOME variable, look up the directory in
194 the password database. */
197 struct passwd
*entry
;
199 entry
= (struct passwd
*) getpwuid (getuid ());
201 temp_home
= entry
->pw_dir
;
204 temp_name
= xmalloc (1 + strlen (&dirname
[1])
205 + (temp_home
? strlen (temp_home
) : 0));
207 strcpy (temp_name
, temp_home
);
210 strcat (temp_name
, &dirname
[1]);
212 dirname
= xstrdup (temp_name
);
217 struct passwd
*user_entry
;
218 char *username
= xmalloc (257);
221 for (i
= 1; (c
= dirname
[i
]); i
++)
230 if (!(user_entry
= (struct passwd
*) getpwnam (username
)))
232 /* If the calling program has a special syntax for
233 expanding tildes, and we couldn't find a standard
234 expansion, then let them try. */
235 if (tilde_expansion_failure_hook
)
237 char *expansion
= (*tilde_expansion_failure_hook
) (username
);
241 temp_name
= xmalloc (1 + strlen (expansion
)
242 + strlen (&dirname
[i
]));
243 strcpy (temp_name
, expansion
);
244 strcat (temp_name
, &dirname
[i
]);
249 /* We shouldn't report errors. */
253 temp_name
= xmalloc (1 + strlen (user_entry
->pw_dir
)
254 + strlen (&dirname
[i
]));
255 strcpy (temp_name
, user_entry
->pw_dir
);
256 strcat (temp_name
, &dirname
[i
]);
260 dirname
= xstrdup (temp_name
);
280 char *result
, line
[512];
285 printf ("~expand: ");
289 strcpy (line
, "done");
291 if ((strcmp (line
, "done") == 0) ||
292 (strcmp (line
, "quit") == 0) ||
293 (strcmp (line
, "exit") == 0))
299 result
= tilde_expand (line
);
300 printf (" --> %s\n", result
);
306 static void memory_error_and_abort ();
312 void *temp
= (void *)malloc (bytes
);
315 memory_error_and_abort ();
320 xrealloc (pointer
, bytes
)
327 temp
= (char *)malloc (bytes
);
329 temp
= (char *)realloc (pointer
, bytes
);
332 memory_error_and_abort ();
338 memory_error_and_abort ()
340 fprintf (stderr
, _("readline: Out of virtual memory!\n"));