1 /* tilde.c -- Tilde expansion code (~/foo := $HOME/foo).
2 $Id: tilde.c,v 1.1.1.3 1998/03/24 18:20:19 law Exp $
4 This file is part of GNU Info, a program for reading online documentation
7 Copyright (C) 1988, 89, 90, 91, 92, 93, 96, 98
8 Free Software Foundation, Inc.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 Written by Brian Fox (bfox@ai.mit.edu). */
26 /* Indent #pragma so that older Cpp's don't try to parse it. */
31 /* Include config.h before doing alloca. */
36 # define alloca __builtin_alloca
47 #if defined (TEST) || defined (STATIC_MALLOC)
48 static void *xmalloc (), *xrealloc ();
49 #endif /* TEST || STATIC_MALLOC */
51 /* The default value of tilde_additional_prefixes. This is set to
52 whitespace preceding a tilde so that simple programs which do not
53 perform any word separation get desired behaviour. */
54 static char *default_prefixes
[] =
55 { " ~", "\t~", (char *)NULL
};
57 /* The default value of tilde_additional_suffixes. This is set to
58 whitespace or newline so that simple programs which do not
59 perform any word separation get desired behaviour. */
60 static char *default_suffixes
[] =
61 { " ", "\n", (char *)NULL
};
63 /* If non-null, this contains the address of a function to call if the
64 standard meaning for expanding a tilde fails. The function is called
65 with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
66 which is the expansion, or a NULL pointer if there is no expansion. */
67 CFunction
*tilde_expansion_failure_hook
= (CFunction
*)NULL
;
69 /* When non-null, this is a NULL terminated array of strings which
70 are duplicates for a tilde prefix. Bash uses this to expand
72 char **tilde_additional_prefixes
= default_prefixes
;
74 /* When non-null, this is a NULL terminated array of strings which match
75 the end of a username, instead of just "/". Bash sets this to
77 char **tilde_additional_suffixes
= default_suffixes
;
79 /* Find the start of a tilde expansion in STRING, and return the index of
80 the tilde which starts the expansion. Place the length of the text
81 which identified this tilde starter in LEN, excluding the tilde itself. */
83 tilde_find_prefix (string
, len
)
87 register int i
, j
, string_len
;
88 register char **prefixes
= tilde_additional_prefixes
;
90 string_len
= strlen (string
);
93 if (!*string
|| *string
== '~')
98 for (i
= 0; i
< string_len
; i
++)
100 for (j
= 0; prefixes
[j
]; j
++)
102 if (strncmp (string
+ i
, prefixes
[j
], strlen (prefixes
[j
])) == 0)
104 *len
= strlen (prefixes
[j
]) - 1;
113 /* Find the end of a tilde expansion in STRING, and return the index of
114 the character which ends the tilde definition. */
116 tilde_find_suffix (string
)
119 register int i
, j
, string_len
;
120 register char **suffixes
= tilde_additional_suffixes
;
122 string_len
= strlen (string
);
124 for (i
= 0; i
< string_len
; i
++)
126 if (string
[i
] == '/' || !string
[i
])
129 for (j
= 0; suffixes
&& suffixes
[j
]; j
++)
131 if (strncmp (string
+ i
, suffixes
[j
], strlen (suffixes
[j
])) == 0)
138 /* Return a new string which is the result of tilde expanding STRING. */
140 tilde_expand (string
)
143 char *result
, *tilde_expand_word ();
144 int result_size
, result_index
;
146 result_size
= result_index
= 0;
147 result
= (char *)NULL
;
149 /* Scan through STRING expanding tildes as we come to them. */
152 register int start
, end
;
153 char *tilde_word
, *expansion
;
156 /* Make START point to the tilde which starts the expansion. */
157 start
= tilde_find_prefix (string
, &len
);
159 /* Copy the skipped text into the result. */
160 if ((result_index
+ start
+ 1) > result_size
)
161 result
= (char *)xrealloc (result
, 1 + (result_size
+= (start
+ 20)));
163 strncpy (result
+ result_index
, string
, start
);
164 result_index
+= start
;
166 /* Advance STRING to the starting tilde. */
169 /* Make END be the index of one after the last character of the
171 end
= tilde_find_suffix (string
);
173 /* If both START and END are zero, we are all done. */
177 /* Expand the entire tilde word, and copy it into RESULT. */
178 tilde_word
= (char *)xmalloc (1 + end
);
179 strncpy (tilde_word
, string
, end
);
180 tilde_word
[end
] = '\0';
183 expansion
= tilde_expand_word (tilde_word
);
186 len
= strlen (expansion
);
187 if ((result_index
+ len
+ 1) > result_size
)
188 result
= (char *)xrealloc (result
, 1 + (result_size
+= (len
+ 20)));
190 strcpy (result
+ result_index
, expansion
);
195 result
[result_index
] = '\0';
200 /* Do the work of tilde expansion on FILENAME. FILENAME starts with a
201 tilde. If there is no expansion, call tilde_expansion_failure_hook. */
203 tilde_expand_word (filename
)
208 dirname
= filename
? xstrdup (filename
) : (char *)NULL
;
210 if (dirname
&& *dirname
== '~')
213 if (!dirname
[1] || dirname
[1] == '/')
215 /* Prepend $HOME to the rest of the string. */
216 char *temp_home
= getenv ("HOME");
218 /* If there is no HOME variable, look up the directory in
219 the password database. */
222 struct passwd
*entry
;
224 entry
= (struct passwd
*) getpwuid (getuid ());
226 temp_home
= entry
->pw_dir
;
230 alloca (1 + strlen (&dirname
[1])
231 + (temp_home
? strlen (temp_home
) : 0));
234 strcpy (temp_name
, temp_home
);
235 strcat (temp_name
, &dirname
[1]);
237 dirname
= xstrdup (temp_name
);
241 struct passwd
*user_entry
;
242 char *username
= (char *)alloca (257);
245 for (i
= 1; (c
= dirname
[i
]); i
++)
252 username
[i
- 1] = '\0';
254 if (!(user_entry
= (struct passwd
*) getpwnam (username
)))
256 /* If the calling program has a special syntax for
257 expanding tildes, and we couldn't find a standard
258 expansion, then let them try. */
259 if (tilde_expansion_failure_hook
)
263 expansion
= (*tilde_expansion_failure_hook
) (username
);
267 temp_name
= (char *)alloca
268 (1 + strlen (expansion
) + strlen (&dirname
[i
]));
269 strcpy (temp_name
, expansion
);
270 strcat (temp_name
, &dirname
[i
]);
275 /* We shouldn't report errors. */
279 temp_name
= (char *)alloca
280 (1 + strlen (user_entry
->pw_dir
) + strlen (&dirname
[i
]));
281 strcpy (temp_name
, user_entry
->pw_dir
);
282 strcat (temp_name
, &dirname
[i
]);
285 dirname
= xstrdup (temp_name
);
302 char *result
, line
[512];
307 printf ("~expand: ");
311 strcpy (line
, "done");
313 if ((strcmp (line
, "done") == 0) ||
314 (strcmp (line
, "quit") == 0) ||
315 (strcmp (line
, "exit") == 0))
321 result
= tilde_expand (line
);
322 printf (" --> %s\n", result
);
328 static void memory_error_and_abort ();
334 void *temp
= (void *)malloc (bytes
);
337 memory_error_and_abort ();
342 xrealloc (pointer
, bytes
)
349 temp
= (char *)malloc (bytes
);
351 temp
= (char *)realloc (pointer
, bytes
);
354 memory_error_and_abort ();
360 memory_error_and_abort ()
362 fprintf (stderr
, _("readline: Out of virtual memory!\n"));