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