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_CONFIG_H)
26 #if defined (HAVE_UNISTD_H)
30 #if defined (HAVE_STRING_H)
32 #else /* !HAVE_STRING_H */
34 #endif /* !HAVE_STRING_H */
36 #if defined (HAVE_STDLIB_H)
39 # include "ansi_stdlib.h"
40 #endif /* HAVE_STDLIB_H */
42 #include <sys/types.h>
51 #if !defined (HAVE_GETPW_DECLS)
52 extern struct passwd
*getpwuid (), *getpwnam ();
53 #endif /* !HAVE_GETPW_DECLS */
55 #if !defined (savestring)
56 extern char *xmalloc ();
58 extern char *strcpy ();
60 #define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
61 #endif /* !savestring */
64 # if defined (__STDC__)
65 # define NULL ((void *) 0)
68 # endif /* !__STDC__ */
71 #if defined (TEST) || defined (STATIC_MALLOC)
72 static char *xmalloc (), *xrealloc ();
74 extern char *xmalloc (), *xrealloc ();
75 #endif /* TEST || STATIC_MALLOC */
77 /* The default value of tilde_additional_prefixes. This is set to
78 whitespace preceding a tilde so that simple programs which do not
79 perform any word separation get desired behaviour. */
80 static char *default_prefixes
[] =
81 { " ~", "\t~", (char *)NULL
};
83 /* The default value of tilde_additional_suffixes. This is set to
84 whitespace or newline so that simple programs which do not
85 perform any word separation get desired behaviour. */
86 static char *default_suffixes
[] =
87 { " ", "\n", (char *)NULL
};
89 /* If non-null, this contains the address of a function that the application
90 wants called before trying the standard tilde expansions. The function
91 is called with the text sans tilde, and returns a malloc()'ed string
92 which is the expansion, or a NULL pointer if the expansion fails. */
93 CPFunction
*tilde_expansion_preexpansion_hook
= (CPFunction
*)NULL
;
95 /* If non-null, this contains the address of a function to call if the
96 standard meaning for expanding a tilde fails. The function is called
97 with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
98 which is the expansion, or a NULL pointer if there is no expansion. */
99 CPFunction
*tilde_expansion_failure_hook
= (CPFunction
*)NULL
;
101 /* When non-null, this is a NULL terminated array of strings which
102 are duplicates for a tilde prefix. Bash uses this to expand
104 char **tilde_additional_prefixes
= default_prefixes
;
106 /* When non-null, this is a NULL terminated array of strings which match
107 the end of a username, instead of just "/". Bash sets this to
109 char **tilde_additional_suffixes
= default_suffixes
;
111 /* Find the start of a tilde expansion in STRING, and return the index of
112 the tilde which starts the expansion. Place the length of the text
113 which identified this tilde starter in LEN, excluding the tilde itself. */
115 tilde_find_prefix (string
, len
)
119 register int i
, j
, string_len
;
120 register char **prefixes
= tilde_additional_prefixes
;
122 string_len
= strlen (string
);
125 if (*string
== '\0' || *string
== '~')
130 for (i
= 0; i
< string_len
; i
++)
132 for (j
= 0; prefixes
[j
]; j
++)
134 if (strncmp (string
+ i
, prefixes
[j
], strlen (prefixes
[j
])) == 0)
136 *len
= strlen (prefixes
[j
]) - 1;
145 /* Find the end of a tilde expansion in STRING, and return the index of
146 the character which ends the tilde definition. */
148 tilde_find_suffix (string
)
151 register int i
, j
, string_len
;
152 register char **suffixes
;
154 suffixes
= tilde_additional_suffixes
;
155 string_len
= strlen (string
);
157 for (i
= 0; i
< string_len
; i
++)
159 if (string
[i
] == '/' /* || !string[i] */)
162 for (j
= 0; suffixes
&& suffixes
[j
]; j
++)
164 if (strncmp (string
+ i
, suffixes
[j
], strlen (suffixes
[j
])) == 0)
173 get_string_value (varname
)
176 return ((char *)getenv (varname
));
180 /* Return a new string which is the result of tilde expanding STRING. */
182 tilde_expand (string
)
186 int result_size
, result_index
;
188 result_index
= result_size
= 0;
189 if (result
= strchr (string
, '~'))
190 result
= xmalloc (result_size
= (strlen (string
) + 16));
192 result
= xmalloc (result_size
= (strlen (string
) + 1));
194 /* Scan through STRING expanding tildes as we come to them. */
197 register int start
, end
;
198 char *tilde_word
, *expansion
;
201 /* Make START point to the tilde which starts the expansion. */
202 start
= tilde_find_prefix (string
, &len
);
204 /* Copy the skipped text into the result. */
205 if ((result_index
+ start
+ 1) > result_size
)
206 result
= xrealloc (result
, 1 + (result_size
+= (start
+ 20)));
208 strncpy (result
+ result_index
, string
, start
);
209 result_index
+= start
;
211 /* Advance STRING to the starting tilde. */
214 /* Make END be the index of one after the last character of the
216 end
= tilde_find_suffix (string
);
218 /* If both START and END are zero, we are all done. */
222 /* Expand the entire tilde word, and copy it into RESULT. */
223 tilde_word
= xmalloc (1 + end
);
224 strncpy (tilde_word
, string
, end
);
225 tilde_word
[end
] = '\0';
228 expansion
= tilde_expand_word (tilde_word
);
231 len
= strlen (expansion
);
232 if ((result_index
+ len
+ 1) > result_size
)
233 result
= xrealloc (result
, 1 + (result_size
+= (len
+ 20)));
235 strcpy (result
+ result_index
, expansion
);
240 result
[result_index
] = '\0';
245 /* Take FNAME and return the tilde prefix we want expanded. If LENP is
246 non-null, the index of the end of the prefix into FNAME is returned in
247 the location it points to. */
249 isolate_tilde_prefix (fname
, lenp
)
256 ret
= xmalloc (strlen (fname
));
257 for (i
= 1; fname
[i
] && fname
[i
] != '/'; i
++)
258 ret
[i
- 1] = fname
[i
];
265 /* Return a string that is PREFIX concatenated with SUFFIX starting at
268 glue_prefix_and_suffix (prefix
, suffix
, suffind
)
269 char *prefix
, *suffix
;
275 plen
= (prefix
&& *prefix
) ? strlen (prefix
) : 0;
276 slen
= strlen (suffix
+ suffind
);
277 ret
= xmalloc (plen
+ slen
+ 1);
278 if (prefix
&& *prefix
)
279 strcpy (ret
, prefix
);
280 strcpy (ret
+ plen
, suffix
+ suffind
);
290 home_dir
= (char *)NULL
;
291 if (current_user
.home_dir
== 0)
292 get_current_user_info ();
293 home_dir
= current_user
.home_dir
;
295 struct passwd
*entry
;
297 home_dir
= (char *)NULL
;
298 entry
= getpwuid (getuid ());
300 home_dir
= entry
->pw_dir
;
305 /* Do the work of tilde expansion on FILENAME. FILENAME starts with a
306 tilde. If there is no expansion, call tilde_expansion_failure_hook.
307 This always returns a newly-allocated string, never static storage. */
309 tilde_expand_word (filename
)
312 char *dirname
, *expansion
, *username
;
314 struct passwd
*user_entry
;
317 return ((char *)NULL
);
319 if (*filename
!= '~')
320 return (savestring (filename
));
322 /* A leading `~/' or a bare `~' is *always* translated to the value of
323 $HOME or the home directory of the current user, regardless of any
324 preexpansion hook. */
325 if (filename
[1] == '\0' || filename
[1] == '/')
327 /* Prefix $HOME to the rest of the string. */
328 expansion
= get_string_value ("HOME");
330 /* If there is no HOME variable, look up the directory in
331 the password database. */
333 expansion
= get_home_dir ();
335 return (glue_prefix_and_suffix (expansion
, filename
, 1));
338 username
= isolate_tilde_prefix (filename
, &user_len
);
340 if (tilde_expansion_preexpansion_hook
)
342 expansion
= (*tilde_expansion_preexpansion_hook
) (username
);
345 dirname
= glue_prefix_and_suffix (expansion
, filename
, user_len
);
352 /* No preexpansion hook, or the preexpansion hook failed. Look in the
353 password database. */
354 dirname
= (char *)NULL
;
355 user_entry
= getpwnam (username
);
358 /* If the calling program has a special syntax for expanding tildes,
359 and we couldn't find a standard expansion, then let them try. */
360 if (tilde_expansion_failure_hook
)
362 expansion
= (*tilde_expansion_failure_hook
) (username
);
365 dirname
= glue_prefix_and_suffix (expansion
, filename
, user_len
);
370 /* If we don't have a failure hook, or if the failure hook did not
371 expand the tilde, return a copy of what we were passed. */
373 dirname
= savestring (filename
);
378 dirname
= glue_prefix_and_suffix (user_entry
->pw_dir
, filename
, user_len
);
394 char *result
, line
[512];
399 printf ("~expand: ");
403 strcpy (line
, "done");
405 if ((strcmp (line
, "done") == 0) ||
406 (strcmp (line
, "quit") == 0) ||
407 (strcmp (line
, "exit") == 0))
413 result
= tilde_expand (line
);
414 printf (" --> %s\n", result
);
420 static void memory_error_and_abort ();
426 char *temp
= (char *)malloc (bytes
);
429 memory_error_and_abort ();
434 xrealloc (pointer
, bytes
)
441 temp
= (char *)malloc (bytes
);
443 temp
= (char *)realloc (pointer
, bytes
);
446 memory_error_and_abort ();
452 memory_error_and_abort ()
454 fprintf (stderr
, "readline: out of virtual memory\n");
460 * compile-command: "gcc -g -DTEST -o tilde tilde.c"