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_STRING_H)
28 #else /* !HAVE_STRING_H */
30 #endif /* !HAVE_STRING_H */
32 #if defined (HAVE_STDLIB_H)
35 # include "ansi_stdlib.h"
36 #endif /* HAVE_STDLIB_H */
38 #include <sys/types.h>
43 #if !defined (HAVE_GETPW_DECLS)
44 extern struct passwd
*getpwuid (), *getpwnam ();
45 #endif /* !HAVE_GETPW_DECLS */
47 #if !defined (savestring)
48 extern char *xmalloc ();
50 extern char *strcpy ();
52 #define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
53 #endif /* !savestring */
56 # if defined (__STDC__)
57 # define NULL ((void *) 0)
60 # endif /* !__STDC__ */
63 #if defined (TEST) || defined (STATIC_MALLOC)
64 static char *xmalloc (), *xrealloc ();
66 extern char *xmalloc (), *xrealloc ();
67 #endif /* TEST || STATIC_MALLOC */
69 /* The default value of tilde_additional_prefixes. This is set to
70 whitespace preceding a tilde so that simple programs which do not
71 perform any word separation get desired behaviour. */
72 static char *default_prefixes
[] =
73 { " ~", "\t~", (char *)NULL
};
75 /* The default value of tilde_additional_suffixes. This is set to
76 whitespace or newline so that simple programs which do not
77 perform any word separation get desired behaviour. */
78 static char *default_suffixes
[] =
79 { " ", "\n", (char *)NULL
};
81 /* If non-null, this contains the address of a function to call if the
82 standard meaning for expanding a tilde fails. The function is called
83 with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
84 which is the expansion, or a NULL pointer if there is no expansion. */
85 CPFunction
*tilde_expansion_failure_hook
= (CPFunction
*)NULL
;
87 /* When non-null, this is a NULL terminated array of strings which
88 are duplicates for a tilde prefix. Bash uses this to expand
90 char **tilde_additional_prefixes
= default_prefixes
;
92 /* When non-null, this is a NULL terminated array of strings which match
93 the end of a username, instead of just "/". Bash sets this to
95 char **tilde_additional_suffixes
= default_suffixes
;
97 /* Find the start of a tilde expansion in STRING, and return the index of
98 the tilde which starts the expansion. Place the length of the text
99 which identified this tilde starter in LEN, excluding the tilde itself. */
101 tilde_find_prefix (string
, len
)
105 register int i
, j
, string_len
;
106 register char **prefixes
= tilde_additional_prefixes
;
108 string_len
= strlen (string
);
111 if (!*string
|| *string
== '~')
116 for (i
= 0; i
< string_len
; i
++)
118 for (j
= 0; prefixes
[j
]; j
++)
120 if (strncmp (string
+ i
, prefixes
[j
], strlen (prefixes
[j
])) == 0)
122 *len
= strlen (prefixes
[j
]) - 1;
131 /* Find the end of a tilde expansion in STRING, and return the index of
132 the character which ends the tilde definition. */
134 tilde_find_suffix (string
)
137 register int i
, j
, string_len
;
138 register char **suffixes
= tilde_additional_suffixes
;
140 string_len
= strlen (string
);
142 for (i
= 0; i
< string_len
; i
++)
144 if (string
[i
] == '/' || !string
[i
])
147 for (j
= 0; suffixes
&& suffixes
[j
]; j
++)
149 if (strncmp (string
+ i
, suffixes
[j
], strlen (suffixes
[j
])) == 0)
156 /* Return a new string which is the result of tilde expanding STRING. */
158 tilde_expand (string
)
161 char *result
, *tilde_expand_word ();
162 int result_size
, result_index
;
164 result_size
= result_index
= 0;
165 result
= (char *)NULL
;
167 /* Scan through STRING expanding tildes as we come to them. */
170 register int start
, end
;
171 char *tilde_word
, *expansion
;
174 /* Make START point to the tilde which starts the expansion. */
175 start
= tilde_find_prefix (string
, &len
);
177 /* Copy the skipped text into the result. */
178 if ((result_index
+ start
+ 1) > result_size
)
179 result
= xrealloc (result
, 1 + (result_size
+= (start
+ 20)));
181 strncpy (result
+ result_index
, string
, start
);
182 result_index
+= start
;
184 /* Advance STRING to the starting tilde. */
187 /* Make END be the index of one after the last character of the
189 end
= tilde_find_suffix (string
);
191 /* If both START and END are zero, we are all done. */
195 /* Expand the entire tilde word, and copy it into RESULT. */
196 tilde_word
= xmalloc (1 + end
);
197 strncpy (tilde_word
, string
, end
);
198 tilde_word
[end
] = '\0';
201 expansion
= tilde_expand_word (tilde_word
);
204 len
= strlen (expansion
);
205 if ((result_index
+ len
+ 1) > result_size
)
206 result
= xrealloc (result
, 1 + (result_size
+= (len
+ 20)));
208 strcpy (result
+ result_index
, expansion
);
213 result
[result_index
] = '\0';
218 /* Do the work of tilde expansion on FILENAME. FILENAME starts with a
219 tilde. If there is no expansion, call tilde_expansion_failure_hook. */
221 tilde_expand_word (filename
)
227 if (filename
== (char *)0)
228 return ((char *)NULL
);
230 dirname
= savestring (filename
);
235 if (!dirname
[1] || dirname
[1] == '/')
237 /* Prepend $HOME to the rest of the string. */
238 char *temp_home
= (char *)getenv ("HOME");
241 /* If there is no HOME variable, look up the directory in
242 the password database. */
245 struct passwd
*entry
;
247 entry
= getpwuid (getuid ());
249 temp_home
= entry
->pw_dir
;
252 home_len
= temp_home
? strlen (temp_home
) : 0;
253 temp_name
= xmalloc (1 + strlen (dirname
+ 1) + home_len
);
256 strcpy (temp_name
, temp_home
);
257 strcpy (temp_name
+ home_len
, dirname
+ 1);
264 struct passwd
*user_entry
;
267 username
= xmalloc (strlen (dirname
));
268 for (i
= 1; dirname
[i
] && dirname
[i
] != '/'; i
++)
269 username
[i
- 1] = dirname
[i
];
270 username
[i
- 1] = '\0';
272 if ((user_entry
= getpwnam (username
)) == (struct passwd
*)0)
274 /* If the calling program has a special syntax for
275 expanding tildes, and we couldn't find a standard
276 expansion, then let them try. */
277 if (tilde_expansion_failure_hook
)
281 expansion
= (*tilde_expansion_failure_hook
) (username
);
285 len
= strlen (expansion
);
286 temp_name
= xmalloc (1 + len
+ strlen (dirname
+ i
));
287 strcpy (temp_name
, expansion
);
288 strcpy (temp_name
+ len
, dirname
+ i
);
294 /* We shouldn't report errors. */
298 len
= strlen (user_entry
->pw_dir
);
299 temp_name
= xmalloc (1 + len
+ strlen (dirname
+ i
));
300 strcpy (temp_name
, user_entry
->pw_dir
);
301 strcpy (temp_name
+ len
, dirname
+ i
);
321 char *result
, line
[512];
326 printf ("~expand: ");
330 strcpy (line
, "done");
332 if ((strcmp (line
, "done") == 0) ||
333 (strcmp (line
, "quit") == 0) ||
334 (strcmp (line
, "exit") == 0))
340 result
= tilde_expand (line
);
341 printf (" --> %s\n", result
);
347 static void memory_error_and_abort ();
353 char *temp
= (char *)malloc (bytes
);
356 memory_error_and_abort ();
361 xrealloc (pointer
, bytes
)
368 temp
= (char *)malloc (bytes
);
370 temp
= (char *)realloc (pointer
, bytes
);
373 memory_error_and_abort ();
379 memory_error_and_abort ()
381 fprintf (stderr
, "readline: out of virtual memory\n");
387 * compile-command: "gcc -g -DTEST -o tilde tilde.c"