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