readline:
[deliverable/binutils-gdb.git] / readline / tilde.c
CommitLineData
d60d9f65
SS
1/* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */
2
3/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
4
5 This file is part of GNU Readline, a library for reading lines
6 of text with interactive input and history editing.
7
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
1b17e766 10 Free Software Foundation; either version 2, or (at your option) any
d60d9f65
SS
11 later version.
12
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.
17
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
1b17e766 20 Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
d60d9f65
SS
21
22#if defined (HAVE_CONFIG_H)
23# include <config.h>
24#endif
25
26#if defined (HAVE_UNISTD_H)
27# ifdef _MINIX
28# include <sys/types.h>
29# endif
30# include <unistd.h>
31#endif
32
33#if defined (HAVE_STRING_H)
34# include <string.h>
35#else /* !HAVE_STRING_H */
36# include <strings.h>
37#endif /* !HAVE_STRING_H */
38
39#if defined (HAVE_STDLIB_H)
40# include <stdlib.h>
41#else
42# include "ansi_stdlib.h"
43#endif /* HAVE_STDLIB_H */
44
45#include <sys/types.h>
46#include <pwd.h>
47
48#include "tilde.h"
49
1b17e766
EZ
50#if defined (TEST) || defined (STATIC_MALLOC)
51static char *xmalloc (), *xrealloc ();
52#else
53# if defined __STDC__
54extern char *xmalloc (int);
55extern char *xrealloc (void *, int);
56# else
57extern char *xmalloc (), *xrealloc ();
58# endif /* !__STDC__ */
59#endif /* TEST || STATIC_MALLOC */
60
d60d9f65
SS
61#if !defined (HAVE_GETPW_DECLS)
62extern struct passwd *getpwuid (), *getpwnam ();
63#endif /* !HAVE_GETPW_DECLS */
64
65#if !defined (savestring)
d60d9f65
SS
66# ifndef strcpy
67extern char *strcpy ();
68# endif
69#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
70#endif /* !savestring */
71
72#if !defined (NULL)
73# if defined (__STDC__)
74# define NULL ((void *) 0)
75# else
76# define NULL 0x0
77# endif /* !__STDC__ */
78#endif /* !NULL */
79
c862e87b
JM
80/* If being compiled as part of bash, these will be satisfied from
81 variables.o. If being compiled as part of readline, they will
82 be satisfied from shell.o. */
1b17e766
EZ
83extern char *get_home_dir __P((void));
84extern char *get_env_value __P((char *));
c862e87b 85
d60d9f65
SS
86/* The default value of tilde_additional_prefixes. This is set to
87 whitespace preceding a tilde so that simple programs which do not
88 perform any word separation get desired behaviour. */
89static char *default_prefixes[] =
90 { " ~", "\t~", (char *)NULL };
91
92/* The default value of tilde_additional_suffixes. This is set to
93 whitespace or newline so that simple programs which do not
94 perform any word separation get desired behaviour. */
95static char *default_suffixes[] =
96 { " ", "\n", (char *)NULL };
97
98/* If non-null, this contains the address of a function that the application
99 wants called before trying the standard tilde expansions. The function
100 is called with the text sans tilde, and returns a malloc()'ed string
101 which is the expansion, or a NULL pointer if the expansion fails. */
102CPFunction *tilde_expansion_preexpansion_hook = (CPFunction *)NULL;
103
104/* If non-null, this contains the address of a function to call if the
105 standard meaning for expanding a tilde fails. The function is called
106 with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
107 which is the expansion, or a NULL pointer if there is no expansion. */
108CPFunction *tilde_expansion_failure_hook = (CPFunction *)NULL;
109
110/* When non-null, this is a NULL terminated array of strings which
111 are duplicates for a tilde prefix. Bash uses this to expand
112 `=~' and `:~'. */
113char **tilde_additional_prefixes = default_prefixes;
114
115/* When non-null, this is a NULL terminated array of strings which match
116 the end of a username, instead of just "/". Bash sets this to
117 `:' and `=~'. */
118char **tilde_additional_suffixes = default_suffixes;
119
120/* Find the start of a tilde expansion in STRING, and return the index of
121 the tilde which starts the expansion. Place the length of the text
122 which identified this tilde starter in LEN, excluding the tilde itself. */
123static int
124tilde_find_prefix (string, len)
125 char *string;
126 int *len;
127{
128 register int i, j, string_len;
1b17e766
EZ
129 register char **prefixes;
130
131 prefixes = tilde_additional_prefixes;
d60d9f65
SS
132
133 string_len = strlen (string);
134 *len = 0;
135
136 if (*string == '\0' || *string == '~')
137 return (0);
138
139 if (prefixes)
140 {
141 for (i = 0; i < string_len; i++)
142 {
143 for (j = 0; prefixes[j]; j++)
144 {
145 if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
146 {
147 *len = strlen (prefixes[j]) - 1;
148 return (i + *len);
149 }
150 }
151 }
152 }
153 return (string_len);
154}
155
156/* Find the end of a tilde expansion in STRING, and return the index of
157 the character which ends the tilde definition. */
158static int
159tilde_find_suffix (string)
160 char *string;
161{
162 register int i, j, string_len;
163 register char **suffixes;
164
165 suffixes = tilde_additional_suffixes;
166 string_len = strlen (string);
167
168 for (i = 0; i < string_len; i++)
169 {
1b17e766
EZ
170#if defined (__MSDOS__)
171 if (string[i] == '/' || string[i] == '\\' /* || !string[i] */)
172#else
d60d9f65 173 if (string[i] == '/' /* || !string[i] */)
1b17e766 174#endif
d60d9f65
SS
175 break;
176
177 for (j = 0; suffixes && suffixes[j]; j++)
178 {
179 if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
180 return (i);
181 }
182 }
183 return (i);
184}
185
d60d9f65
SS
186/* Return a new string which is the result of tilde expanding STRING. */
187char *
188tilde_expand (string)
189 char *string;
190{
191 char *result;
192 int result_size, result_index;
193
194 result_index = result_size = 0;
195 if (result = strchr (string, '~'))
196 result = xmalloc (result_size = (strlen (string) + 16));
197 else
198 result = xmalloc (result_size = (strlen (string) + 1));
199
200 /* Scan through STRING expanding tildes as we come to them. */
201 while (1)
202 {
203 register int start, end;
204 char *tilde_word, *expansion;
205 int len;
206
207 /* Make START point to the tilde which starts the expansion. */
208 start = tilde_find_prefix (string, &len);
209
210 /* Copy the skipped text into the result. */
211 if ((result_index + start + 1) > result_size)
212 result = xrealloc (result, 1 + (result_size += (start + 20)));
213
214 strncpy (result + result_index, string, start);
215 result_index += start;
216
217 /* Advance STRING to the starting tilde. */
218 string += start;
219
220 /* Make END be the index of one after the last character of the
221 username. */
222 end = tilde_find_suffix (string);
223
224 /* If both START and END are zero, we are all done. */
225 if (!start && !end)
226 break;
227
228 /* Expand the entire tilde word, and copy it into RESULT. */
229 tilde_word = xmalloc (1 + end);
230 strncpy (tilde_word, string, end);
231 tilde_word[end] = '\0';
232 string += end;
233
234 expansion = tilde_expand_word (tilde_word);
235 free (tilde_word);
236
237 len = strlen (expansion);
1b17e766
EZ
238#ifdef __CYGWIN32__
239 /* Fix for Cygwin to prevent ~user/xxx from expanding to //xxx when
240 $HOME for `user' is /. On cygwin, // denotes a network drive. */
241 if (len > 1 || *expansion != '/' || *string != '/')
242#endif
243 {
244 if ((result_index + len + 1) > result_size)
245 result = xrealloc (result, 1 + (result_size += (len + 20)));
d60d9f65 246
1b17e766
EZ
247 strcpy (result + result_index, expansion);
248 result_index += len;
249 }
d60d9f65
SS
250 free (expansion);
251 }
252
253 result[result_index] = '\0';
254
255 return (result);
256}
257
258/* Take FNAME and return the tilde prefix we want expanded. If LENP is
259 non-null, the index of the end of the prefix into FNAME is returned in
260 the location it points to. */
261static char *
262isolate_tilde_prefix (fname, lenp)
263 char *fname;
264 int *lenp;
265{
266 char *ret;
267 int i;
268
269 ret = xmalloc (strlen (fname));
1b17e766
EZ
270#if defined (__MSDOS__)
271 for (i = 1; fname[i] && fname[i] != '/' && fname[i] != '\\'; i++)
272#else
d60d9f65 273 for (i = 1; fname[i] && fname[i] != '/'; i++)
1b17e766 274#endif
d60d9f65
SS
275 ret[i - 1] = fname[i];
276 ret[i - 1] = '\0';
277 if (lenp)
278 *lenp = i;
279 return ret;
280}
281
282/* Return a string that is PREFIX concatenated with SUFFIX starting at
283 SUFFIND. */
284static char *
285glue_prefix_and_suffix (prefix, suffix, suffind)
286 char *prefix, *suffix;
287 int suffind;
288{
289 char *ret;
290 int plen, slen;
291
292 plen = (prefix && *prefix) ? strlen (prefix) : 0;
293 slen = strlen (suffix + suffind);
294 ret = xmalloc (plen + slen + 1);
1b17e766 295 if (plen)
d60d9f65
SS
296 strcpy (ret, prefix);
297 strcpy (ret + plen, suffix + suffind);
298 return ret;
299}
300
d60d9f65
SS
301/* Do the work of tilde expansion on FILENAME. FILENAME starts with a
302 tilde. If there is no expansion, call tilde_expansion_failure_hook.
303 This always returns a newly-allocated string, never static storage. */
304char *
305tilde_expand_word (filename)
306 char *filename;
307{
308 char *dirname, *expansion, *username;
309 int user_len;
310 struct passwd *user_entry;
311
312 if (filename == 0)
313 return ((char *)NULL);
314
315 if (*filename != '~')
316 return (savestring (filename));
317
318 /* A leading `~/' or a bare `~' is *always* translated to the value of
319 $HOME or the home directory of the current user, regardless of any
320 preexpansion hook. */
321 if (filename[1] == '\0' || filename[1] == '/')
322 {
323 /* Prefix $HOME to the rest of the string. */
c862e87b 324 expansion = get_env_value ("HOME");
d60d9f65
SS
325
326 /* If there is no HOME variable, look up the directory in
327 the password database. */
328 if (expansion == 0)
329 expansion = get_home_dir ();
330
331 return (glue_prefix_and_suffix (expansion, filename, 1));
332 }
333
334 username = isolate_tilde_prefix (filename, &user_len);
335
336 if (tilde_expansion_preexpansion_hook)
337 {
338 expansion = (*tilde_expansion_preexpansion_hook) (username);
339 if (expansion)
340 {
341 dirname = glue_prefix_and_suffix (expansion, filename, user_len);
342 free (username);
343 free (expansion);
344 return (dirname);
345 }
346 }
347
348 /* No preexpansion hook, or the preexpansion hook failed. Look in the
349 password database. */
350 dirname = (char *)NULL;
351 user_entry = getpwnam (username);
352 if (user_entry == 0)
353 {
354 /* If the calling program has a special syntax for expanding tildes,
355 and we couldn't find a standard expansion, then let them try. */
356 if (tilde_expansion_failure_hook)
357 {
358 expansion = (*tilde_expansion_failure_hook) (username);
359 if (expansion)
360 {
361 dirname = glue_prefix_and_suffix (expansion, filename, user_len);
362 free (expansion);
363 }
364 }
365 free (username);
366 /* If we don't have a failure hook, or if the failure hook did not
367 expand the tilde, return a copy of what we were passed. */
368 if (dirname == 0)
369 dirname = savestring (filename);
370 }
371 else
372 {
373 free (username);
374 dirname = glue_prefix_and_suffix (user_entry->pw_dir, filename, user_len);
375 }
376
377 endpwent ();
378 return (dirname);
379}
380
381\f
382#if defined (TEST)
383#undef NULL
384#include <stdio.h>
385
386main (argc, argv)
387 int argc;
388 char **argv;
389{
390 char *result, line[512];
391 int done = 0;
392
393 while (!done)
394 {
395 printf ("~expand: ");
396 fflush (stdout);
397
398 if (!gets (line))
399 strcpy (line, "done");
400
401 if ((strcmp (line, "done") == 0) ||
402 (strcmp (line, "quit") == 0) ||
403 (strcmp (line, "exit") == 0))
404 {
405 done = 1;
406 break;
407 }
408
409 result = tilde_expand (line);
410 printf (" --> %s\n", result);
411 free (result);
412 }
413 exit (0);
414}
415
416static void memory_error_and_abort ();
417
418static char *
419xmalloc (bytes)
420 int bytes;
421{
422 char *temp = (char *)malloc (bytes);
423
424 if (!temp)
425 memory_error_and_abort ();
426 return (temp);
427}
428
429static char *
430xrealloc (pointer, bytes)
431 char *pointer;
432 int bytes;
433{
434 char *temp;
435
436 if (!pointer)
437 temp = (char *)malloc (bytes);
438 else
439 temp = (char *)realloc (pointer, bytes);
440
441 if (!temp)
442 memory_error_and_abort ();
443
444 return (temp);
445}
446
447static void
448memory_error_and_abort ()
449{
450 fprintf (stderr, "readline: out of virtual memory\n");
451 abort ();
452}
453
454/*
455 * Local variables:
456 * compile-command: "gcc -g -DTEST -o tilde tilde.c"
457 * end:
458 */
459#endif /* TEST */
This page took 0.068319 seconds and 4 git commands to generate.