No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / dist / texinfo / info / tilde.c
blob323ea0cf7a988ad46973cb1b85dc70347dbddccf
1 /* $NetBSD$ */
3 /* tilde.c -- tilde expansion code (~/foo := $HOME/foo).
4 Id: tilde.c,v 1.3 2004/04/11 17:56:46 karl Exp
6 Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1996, 1998, 1999,
7 2002, 2004 Free Software Foundation, Inc.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 Written by Brian Fox (bfox@ai.mit.edu). */
25 /* Include config.h before doing alloca. */
26 #include "info.h"
27 #include "tilde.h"
29 #if defined (TEST) || defined (STATIC_MALLOC)
30 static void *xmalloc (), *xrealloc ();
31 #endif /* TEST || STATIC_MALLOC */
33 /* The default value of tilde_additional_prefixes. This is set to
34 whitespace preceding a tilde so that simple programs which do not
35 perform any word separation get desired behaviour. */
36 static char *default_prefixes[] =
37 { " ~", "\t~", (char *)NULL };
39 /* The default value of tilde_additional_suffixes. This is set to
40 whitespace or newline so that simple programs which do not
41 perform any word separation get desired behaviour. */
42 static char *default_suffixes[] =
43 { " ", "\n", (char *)NULL };
45 /* If non-null, this contains the address of a function to call if the
46 standard meaning for expanding a tilde fails. The function is called
47 with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
48 which is the expansion, or a NULL pointer if there is no expansion. */
49 CFunction *tilde_expansion_failure_hook = (CFunction *)NULL;
51 /* When non-null, this is a NULL terminated array of strings which
52 are duplicates for a tilde prefix. Bash uses this to expand
53 `=~' and `:~'. */
54 char **tilde_additional_prefixes = default_prefixes;
56 /* When non-null, this is a NULL terminated array of strings which match
57 the end of a username, instead of just "/". Bash sets this to
58 `:' and `=~'. */
59 char **tilde_additional_suffixes = default_suffixes;
61 /* Find the start of a tilde expansion in STRING, and return the index of
62 the tilde which starts the expansion. Place the length of the text
63 which identified this tilde starter in LEN, excluding the tilde itself. */
64 static int
65 tilde_find_prefix (char *string, int *len)
67 register int i, j, string_len;
68 register char **prefixes = tilde_additional_prefixes;
70 string_len = strlen (string);
71 *len = 0;
73 if (!*string || *string == '~')
74 return (0);
76 if (prefixes)
78 for (i = 0; i < string_len; i++)
80 for (j = 0; prefixes[j]; j++)
82 if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
84 *len = strlen (prefixes[j]) - 1;
85 return (i + *len);
90 return (string_len);
93 /* Find the end of a tilde expansion in STRING, and return the index of
94 the character which ends the tilde definition. */
95 static int
96 tilde_find_suffix (char *string)
98 register int i, j, string_len;
99 register char **suffixes = tilde_additional_suffixes;
101 string_len = strlen (string);
103 for (i = 0; i < string_len; i++)
105 if (IS_SLASH (string[i]) || !string[i])
106 break;
108 for (j = 0; suffixes && suffixes[j]; j++)
110 if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
111 return (i);
114 return (i);
117 /* Return a new string which is the result of tilde expanding STRING. */
118 char *
119 tilde_expand (char *string)
121 char *result;
122 int result_size, result_index;
124 result_size = result_index = 0;
125 result = (char *)NULL;
127 /* Scan through STRING expanding tildes as we come to them. */
128 while (1)
130 register int start, end;
131 char *tilde_word, *expansion;
132 int len;
134 /* Make START point to the tilde which starts the expansion. */
135 start = tilde_find_prefix (string, &len);
137 /* Copy the skipped text into the result. */
138 if ((result_index + start + 1) > result_size)
139 result = (char *)xrealloc (result, 1 + (result_size += (start + 20)));
141 strncpy (result + result_index, string, start);
142 result_index += start;
144 /* Advance STRING to the starting tilde. */
145 string += start;
147 /* Make END be the index of one after the last character of the
148 username. */
149 end = tilde_find_suffix (string);
151 /* If both START and END are zero, we are all done. */
152 if (!start && !end)
153 break;
155 /* Expand the entire tilde word, and copy it into RESULT. */
156 tilde_word = (char *)xmalloc (1 + end);
157 strncpy (tilde_word, string, end);
158 tilde_word[end] = '\0';
159 string += end;
161 expansion = tilde_expand_word (tilde_word);
162 free (tilde_word);
164 len = strlen (expansion);
165 if ((result_index + len + 1) > result_size)
166 result = (char *)xrealloc (result, 1 + (result_size += (len + 20)));
168 strcpy (result + result_index, expansion);
169 result_index += len;
170 free (expansion);
173 result[result_index] = '\0';
175 return (result);
178 /* Do the work of tilde expansion on FILENAME. FILENAME starts with a
179 tilde. If there is no expansion, call tilde_expansion_failure_hook. */
180 char *
181 tilde_expand_word (char *filename)
183 char *dirname = filename ? xstrdup (filename) : NULL;
185 if (dirname && *dirname == '~')
187 char *temp_name;
188 if (!dirname[1] || IS_SLASH (dirname[1]))
190 /* Prepend $HOME to the rest of the string. */
191 char *temp_home = getenv ("HOME");
193 /* If there is no HOME variable, look up the directory in
194 the password database. */
195 if (!temp_home)
197 struct passwd *entry;
199 entry = (struct passwd *) getpwuid (getuid ());
200 if (entry)
201 temp_home = entry->pw_dir;
204 temp_name = xmalloc (1 + strlen (&dirname[1])
205 + (temp_home ? strlen (temp_home) : 0));
206 if (temp_home)
207 strcpy (temp_name, temp_home);
208 else
209 temp_name[0] = 0;
210 strcat (temp_name, &dirname[1]);
211 free (dirname);
212 dirname = xstrdup (temp_name);
213 free (temp_name);
215 else
217 struct passwd *user_entry;
218 char *username = xmalloc (257);
219 int i, c;
221 for (i = 1; (c = dirname[i]); i++)
223 if (IS_SLASH (c))
224 break;
225 else
226 username[i - 1] = c;
228 username[i - 1] = 0;
230 if (!(user_entry = (struct passwd *) getpwnam (username)))
232 /* If the calling program has a special syntax for
233 expanding tildes, and we couldn't find a standard
234 expansion, then let them try. */
235 if (tilde_expansion_failure_hook)
237 char *expansion = (*tilde_expansion_failure_hook) (username);
239 if (expansion)
241 temp_name = xmalloc (1 + strlen (expansion)
242 + strlen (&dirname[i]));
243 strcpy (temp_name, expansion);
244 strcat (temp_name, &dirname[i]);
245 free (expansion);
246 goto return_name;
249 /* We shouldn't report errors. */
251 else
253 temp_name = xmalloc (1 + strlen (user_entry->pw_dir)
254 + strlen (&dirname[i]));
255 strcpy (temp_name, user_entry->pw_dir);
256 strcat (temp_name, &dirname[i]);
258 return_name:
259 free (dirname);
260 dirname = xstrdup (temp_name);
261 free (temp_name);
264 endpwent ();
265 free (username);
268 return dirname;
272 #if defined (TEST)
273 #undef NULL
274 #include <stdio.h>
276 main (argc, argv)
277 int argc;
278 char **argv;
280 char *result, line[512];
281 int done = 0;
283 while (!done)
285 printf ("~expand: ");
286 fflush (stdout);
288 if (!gets (line))
289 strcpy (line, "done");
291 if ((strcmp (line, "done") == 0) ||
292 (strcmp (line, "quit") == 0) ||
293 (strcmp (line, "exit") == 0))
295 done = 1;
296 break;
299 result = tilde_expand (line);
300 printf (" --> %s\n", result);
301 free (result);
303 xexit (0);
306 static void memory_error_and_abort ();
308 static void *
309 xmalloc (bytes)
310 int bytes;
312 void *temp = (void *)malloc (bytes);
314 if (!temp)
315 memory_error_and_abort ();
316 return (temp);
319 static void *
320 xrealloc (pointer, bytes)
321 void *pointer;
322 int bytes;
324 void *temp;
326 if (!pointer)
327 temp = (char *)malloc (bytes);
328 else
329 temp = (char *)realloc (pointer, bytes);
331 if (!temp)
332 memory_error_and_abort ();
334 return (temp);
337 static void
338 memory_error_and_abort ()
340 fprintf (stderr, _("readline: Out of virtual memory!\n"));
341 abort ();
343 #endif /* TEST */