11acd27e7Smillert /* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */
21acd27e7Smillert
31acd27e7Smillert /* Copyright (C) 1988,1989 Free Software Foundation, Inc.
41acd27e7Smillert
51acd27e7Smillert This file is part of GNU Readline, a library for reading lines
61acd27e7Smillert of text with interactive input and history editing.
71acd27e7Smillert
81acd27e7Smillert Readline is free software; you can redistribute it and/or modify it
91acd27e7Smillert under the terms of the GNU General Public License as published by the
101acd27e7Smillert Free Software Foundation; either version 2, or (at your option) any
111acd27e7Smillert later version.
121acd27e7Smillert
131acd27e7Smillert Readline is distributed in the hope that it will be useful, but
141acd27e7Smillert WITHOUT ANY WARRANTY; without even the implied warranty of
151acd27e7Smillert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
161acd27e7Smillert General Public License for more details.
171acd27e7Smillert
181acd27e7Smillert You should have received a copy of the GNU General Public License
191acd27e7Smillert along with Readline; see the file COPYING. If not, write to the Free
201acd27e7Smillert Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
211acd27e7Smillert
221acd27e7Smillert #if defined (HAVE_CONFIG_H)
231acd27e7Smillert # include <config.h>
241acd27e7Smillert #endif
251acd27e7Smillert
261acd27e7Smillert #if defined (HAVE_UNISTD_H)
271acd27e7Smillert # ifdef _MINIX
281acd27e7Smillert # include <sys/types.h>
291acd27e7Smillert # endif
301acd27e7Smillert # include <unistd.h>
311acd27e7Smillert #endif
321acd27e7Smillert
331acd27e7Smillert #if defined (HAVE_STRING_H)
341acd27e7Smillert # include <string.h>
351acd27e7Smillert #else /* !HAVE_STRING_H */
361acd27e7Smillert # include <strings.h>
371acd27e7Smillert #endif /* !HAVE_STRING_H */
381acd27e7Smillert
391acd27e7Smillert #if defined (HAVE_STDLIB_H)
401acd27e7Smillert # include <stdlib.h>
411acd27e7Smillert #else
421acd27e7Smillert # include "ansi_stdlib.h"
431acd27e7Smillert #endif /* HAVE_STDLIB_H */
441acd27e7Smillert
451acd27e7Smillert #include <sys/types.h>
461acd27e7Smillert #include <pwd.h>
471acd27e7Smillert
481acd27e7Smillert #include "tilde.h"
491acd27e7Smillert
501acd27e7Smillert #if defined (TEST) || defined (STATIC_MALLOC)
51af70c2dfSkettenis static void *xmalloc (), *xrealloc ();
521acd27e7Smillert #else
53af70c2dfSkettenis # include "xmalloc.h"
541acd27e7Smillert #endif /* TEST || STATIC_MALLOC */
551acd27e7Smillert
561acd27e7Smillert #if !defined (HAVE_GETPW_DECLS)
57af70c2dfSkettenis extern struct passwd *getpwuid PARAMS((uid_t));
58af70c2dfSkettenis extern struct passwd *getpwnam PARAMS((const char *));
591acd27e7Smillert #endif /* !HAVE_GETPW_DECLS */
601acd27e7Smillert
611acd27e7Smillert #if !defined (savestring)
6263bef317Sbeck #include <stdio.h>
6363bef317Sbeck static char *
xstrdup(const char * s)64af70c2dfSkettenis xstrdup(const char *s)
6563bef317Sbeck {
6663bef317Sbeck char * cp;
6763bef317Sbeck cp = strdup(s);
6863bef317Sbeck if (cp == NULL) {
6963bef317Sbeck fprintf (stderr, "xstrdup: out of virtual memory\n");
7063bef317Sbeck exit (2);
7163bef317Sbeck }
7263bef317Sbeck return(cp);
7363bef317Sbeck }
7463bef317Sbeck #define savestring(x) xstrdup(x)
751acd27e7Smillert #endif /* !savestring */
761acd27e7Smillert
771acd27e7Smillert #if !defined (NULL)
781acd27e7Smillert # if defined (__STDC__)
791acd27e7Smillert # define NULL ((void *) 0)
801acd27e7Smillert # else
811acd27e7Smillert # define NULL 0x0
821acd27e7Smillert # endif /* !__STDC__ */
831acd27e7Smillert #endif /* !NULL */
841acd27e7Smillert
851acd27e7Smillert /* If being compiled as part of bash, these will be satisfied from
861acd27e7Smillert variables.o. If being compiled as part of readline, they will
871acd27e7Smillert be satisfied from shell.o. */
88af70c2dfSkettenis extern char *sh_get_home_dir PARAMS((void));
89af70c2dfSkettenis extern char *sh_get_env_value PARAMS((const char *));
901acd27e7Smillert
911acd27e7Smillert /* The default value of tilde_additional_prefixes. This is set to
921acd27e7Smillert whitespace preceding a tilde so that simple programs which do not
931acd27e7Smillert perform any word separation get desired behaviour. */
94af70c2dfSkettenis static const char *default_prefixes[] =
95af70c2dfSkettenis { " ~", "\t~", (const char *)NULL };
961acd27e7Smillert
971acd27e7Smillert /* The default value of tilde_additional_suffixes. This is set to
981acd27e7Smillert whitespace or newline so that simple programs which do not
991acd27e7Smillert perform any word separation get desired behaviour. */
100af70c2dfSkettenis static const char *default_suffixes[] =
101af70c2dfSkettenis { " ", "\n", (const char *)NULL };
1021acd27e7Smillert
1031acd27e7Smillert /* If non-null, this contains the address of a function that the application
1041acd27e7Smillert wants called before trying the standard tilde expansions. The function
1051acd27e7Smillert is called with the text sans tilde, and returns a malloc()'ed string
1061acd27e7Smillert which is the expansion, or a NULL pointer if the expansion fails. */
107af70c2dfSkettenis tilde_hook_func_t *tilde_expansion_preexpansion_hook = (tilde_hook_func_t *)NULL;
1081acd27e7Smillert
1091acd27e7Smillert /* If non-null, this contains the address of a function to call if the
1101acd27e7Smillert standard meaning for expanding a tilde fails. The function is called
1111acd27e7Smillert with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
1121acd27e7Smillert which is the expansion, or a NULL pointer if there is no expansion. */
113af70c2dfSkettenis tilde_hook_func_t *tilde_expansion_failure_hook = (tilde_hook_func_t *)NULL;
1141acd27e7Smillert
1151acd27e7Smillert /* When non-null, this is a NULL terminated array of strings which
1161acd27e7Smillert are duplicates for a tilde prefix. Bash uses this to expand
1171acd27e7Smillert `=~' and `:~'. */
118af70c2dfSkettenis char **tilde_additional_prefixes = (char **)default_prefixes;
1191acd27e7Smillert
1201acd27e7Smillert /* When non-null, this is a NULL terminated array of strings which match
1211acd27e7Smillert the end of a username, instead of just "/". Bash sets this to
1221acd27e7Smillert `:' and `=~'. */
123af70c2dfSkettenis char **tilde_additional_suffixes = (char **)default_suffixes;
124af70c2dfSkettenis
125af70c2dfSkettenis static int tilde_find_prefix PARAMS((const char *, int *));
126af70c2dfSkettenis static int tilde_find_suffix PARAMS((const char *));
127af70c2dfSkettenis static char *isolate_tilde_prefix PARAMS((const char *, int *));
128af70c2dfSkettenis static char *glue_prefix_and_suffix PARAMS((char *, const char *, int));
1291acd27e7Smillert
1301acd27e7Smillert /* Find the start of a tilde expansion in STRING, and return the index of
1311acd27e7Smillert the tilde which starts the expansion. Place the length of the text
1321acd27e7Smillert which identified this tilde starter in LEN, excluding the tilde itself. */
1331acd27e7Smillert static int
tilde_find_prefix(string,len)1341acd27e7Smillert tilde_find_prefix (string, len)
135af70c2dfSkettenis const char *string;
1361acd27e7Smillert int *len;
1371acd27e7Smillert {
1381acd27e7Smillert register int i, j, string_len;
1391acd27e7Smillert register char **prefixes;
1401acd27e7Smillert
1411acd27e7Smillert prefixes = tilde_additional_prefixes;
1421acd27e7Smillert
1431acd27e7Smillert string_len = strlen (string);
1441acd27e7Smillert *len = 0;
1451acd27e7Smillert
1461acd27e7Smillert if (*string == '\0' || *string == '~')
1471acd27e7Smillert return (0);
1481acd27e7Smillert
1491acd27e7Smillert if (prefixes)
1501acd27e7Smillert {
1511acd27e7Smillert for (i = 0; i < string_len; i++)
1521acd27e7Smillert {
1531acd27e7Smillert for (j = 0; prefixes[j]; j++)
1541acd27e7Smillert {
1551acd27e7Smillert if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
1561acd27e7Smillert {
1571acd27e7Smillert *len = strlen (prefixes[j]) - 1;
1581acd27e7Smillert return (i + *len);
1591acd27e7Smillert }
1601acd27e7Smillert }
1611acd27e7Smillert }
1621acd27e7Smillert }
1631acd27e7Smillert return (string_len);
1641acd27e7Smillert }
1651acd27e7Smillert
1661acd27e7Smillert /* Find the end of a tilde expansion in STRING, and return the index of
1671acd27e7Smillert the character which ends the tilde definition. */
1681acd27e7Smillert static int
tilde_find_suffix(string)1691acd27e7Smillert tilde_find_suffix (string)
170af70c2dfSkettenis const char *string;
1711acd27e7Smillert {
1721acd27e7Smillert register int i, j, string_len;
1731acd27e7Smillert register char **suffixes;
1741acd27e7Smillert
1751acd27e7Smillert suffixes = tilde_additional_suffixes;
1761acd27e7Smillert string_len = strlen (string);
1771acd27e7Smillert
1781acd27e7Smillert for (i = 0; i < string_len; i++)
1791acd27e7Smillert {
1801acd27e7Smillert #if defined (__MSDOS__)
1811acd27e7Smillert if (string[i] == '/' || string[i] == '\\' /* || !string[i] */)
1821acd27e7Smillert #else
1831acd27e7Smillert if (string[i] == '/' /* || !string[i] */)
1841acd27e7Smillert #endif
1851acd27e7Smillert break;
1861acd27e7Smillert
1871acd27e7Smillert for (j = 0; suffixes && suffixes[j]; j++)
1881acd27e7Smillert {
1891acd27e7Smillert if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
1901acd27e7Smillert return (i);
1911acd27e7Smillert }
1921acd27e7Smillert }
1931acd27e7Smillert return (i);
1941acd27e7Smillert }
1951acd27e7Smillert
1961acd27e7Smillert /* Return a new string which is the result of tilde expanding STRING. */
1971acd27e7Smillert char *
tilde_expand(string)1981acd27e7Smillert tilde_expand (string)
199af70c2dfSkettenis const char *string;
2001acd27e7Smillert {
2011acd27e7Smillert char *result;
2021acd27e7Smillert int result_size, result_index;
2031acd27e7Smillert
2041acd27e7Smillert result_index = result_size = 0;
205*af1e7b8cSkrw if ((result = strchr (string, '~')))
206af70c2dfSkettenis result = (char *)xmalloc (result_size = (strlen (string) + 16));
2071acd27e7Smillert else
208af70c2dfSkettenis result = (char *)xmalloc (result_size = (strlen (string) + 1));
2091acd27e7Smillert
2101acd27e7Smillert /* Scan through STRING expanding tildes as we come to them. */
2111acd27e7Smillert while (1)
2121acd27e7Smillert {
2131acd27e7Smillert register int start, end;
2141acd27e7Smillert char *tilde_word, *expansion;
2151acd27e7Smillert int len;
2161acd27e7Smillert
2171acd27e7Smillert /* Make START point to the tilde which starts the expansion. */
2181acd27e7Smillert start = tilde_find_prefix (string, &len);
2191acd27e7Smillert
2201acd27e7Smillert /* Copy the skipped text into the result. */
2211acd27e7Smillert if ((result_index + start + 1) > result_size)
222af70c2dfSkettenis result = (char *)xrealloc (result, 1 + (result_size += (start + 20)));
2231acd27e7Smillert
2241acd27e7Smillert strncpy (result + result_index, string, start);
2251acd27e7Smillert result_index += start;
2261acd27e7Smillert
2271acd27e7Smillert /* Advance STRING to the starting tilde. */
2281acd27e7Smillert string += start;
2291acd27e7Smillert
2301acd27e7Smillert /* Make END be the index of one after the last character of the
2311acd27e7Smillert username. */
2321acd27e7Smillert end = tilde_find_suffix (string);
2331acd27e7Smillert
2341acd27e7Smillert /* If both START and END are zero, we are all done. */
2351acd27e7Smillert if (!start && !end)
2361acd27e7Smillert break;
2371acd27e7Smillert
2381acd27e7Smillert /* Expand the entire tilde word, and copy it into RESULT. */
239af70c2dfSkettenis tilde_word = (char *)xmalloc (1 + end);
2401acd27e7Smillert strncpy (tilde_word, string, end);
2411acd27e7Smillert tilde_word[end] = '\0';
2421acd27e7Smillert string += end;
2431acd27e7Smillert
2441acd27e7Smillert expansion = tilde_expand_word (tilde_word);
2451acd27e7Smillert free (tilde_word);
2461acd27e7Smillert
2471acd27e7Smillert len = strlen (expansion);
248af70c2dfSkettenis #ifdef __CYGWIN__
2491acd27e7Smillert /* Fix for Cygwin to prevent ~user/xxx from expanding to //xxx when
2501acd27e7Smillert $HOME for `user' is /. On cygwin, // denotes a network drive. */
2511acd27e7Smillert if (len > 1 || *expansion != '/' || *string != '/')
2521acd27e7Smillert #endif
2531acd27e7Smillert {
2541acd27e7Smillert if ((result_index + len + 1) > result_size)
255af70c2dfSkettenis result = (char *)xrealloc (result, 1 + (result_size += (len + 20)));
2561acd27e7Smillert
25763bef317Sbeck strlcpy (result + result_index, expansion,
25863bef317Sbeck result_size - result_index);
2591acd27e7Smillert result_index += len;
2601acd27e7Smillert }
2611acd27e7Smillert free (expansion);
2621acd27e7Smillert }
2631acd27e7Smillert
2641acd27e7Smillert result[result_index] = '\0';
2651acd27e7Smillert
2661acd27e7Smillert return (result);
2671acd27e7Smillert }
2681acd27e7Smillert
2691acd27e7Smillert /* Take FNAME and return the tilde prefix we want expanded. If LENP is
2701acd27e7Smillert non-null, the index of the end of the prefix into FNAME is returned in
2711acd27e7Smillert the location it points to. */
2721acd27e7Smillert static char *
isolate_tilde_prefix(fname,lenp)2731acd27e7Smillert isolate_tilde_prefix (fname, lenp)
274af70c2dfSkettenis const char *fname;
2751acd27e7Smillert int *lenp;
2761acd27e7Smillert {
2771acd27e7Smillert char *ret;
2781acd27e7Smillert int i;
2791acd27e7Smillert
280af70c2dfSkettenis ret = (char *)xmalloc (strlen (fname));
2811acd27e7Smillert #if defined (__MSDOS__)
2821acd27e7Smillert for (i = 1; fname[i] && fname[i] != '/' && fname[i] != '\\'; i++)
2831acd27e7Smillert #else
2841acd27e7Smillert for (i = 1; fname[i] && fname[i] != '/'; i++)
2851acd27e7Smillert #endif
2861acd27e7Smillert ret[i - 1] = fname[i];
2871acd27e7Smillert ret[i - 1] = '\0';
2881acd27e7Smillert if (lenp)
2891acd27e7Smillert *lenp = i;
2901acd27e7Smillert return ret;
2911acd27e7Smillert }
2921acd27e7Smillert
2931acd27e7Smillert /* Return a string that is PREFIX concatenated with SUFFIX starting at
2941acd27e7Smillert SUFFIND. */
2951acd27e7Smillert static char *
glue_prefix_and_suffix(prefix,suffix,suffind)2961acd27e7Smillert glue_prefix_and_suffix (prefix, suffix, suffind)
297af70c2dfSkettenis char *prefix;
298af70c2dfSkettenis const char *suffix;
2991acd27e7Smillert int suffind;
3001acd27e7Smillert {
3011acd27e7Smillert char *ret;
3021acd27e7Smillert int plen, slen;
3031acd27e7Smillert
3041acd27e7Smillert plen = (prefix && *prefix) ? strlen (prefix) : 0;
3051acd27e7Smillert slen = strlen (suffix + suffind);
306af70c2dfSkettenis ret = (char *)xmalloc (plen + slen + 1);
3071acd27e7Smillert if (plen)
30863bef317Sbeck strlcpy (ret, prefix, plen + slen + 1);
30963bef317Sbeck strlcat (ret, suffix + suffind, plen + slen + 1);
3101acd27e7Smillert return ret;
3111acd27e7Smillert }
3121acd27e7Smillert
3131acd27e7Smillert /* Do the work of tilde expansion on FILENAME. FILENAME starts with a
3141acd27e7Smillert tilde. If there is no expansion, call tilde_expansion_failure_hook.
3151acd27e7Smillert This always returns a newly-allocated string, never static storage. */
3161acd27e7Smillert char *
tilde_expand_word(filename)3171acd27e7Smillert tilde_expand_word (filename)
318af70c2dfSkettenis const char *filename;
3191acd27e7Smillert {
3201acd27e7Smillert char *dirname, *expansion, *username;
3211acd27e7Smillert int user_len;
3221acd27e7Smillert struct passwd *user_entry;
3231acd27e7Smillert
3241acd27e7Smillert if (filename == 0)
3251acd27e7Smillert return ((char *)NULL);
3261acd27e7Smillert
3271acd27e7Smillert if (*filename != '~')
3281acd27e7Smillert return (savestring (filename));
3291acd27e7Smillert
3301acd27e7Smillert /* A leading `~/' or a bare `~' is *always* translated to the value of
3311acd27e7Smillert $HOME or the home directory of the current user, regardless of any
3321acd27e7Smillert preexpansion hook. */
3331acd27e7Smillert if (filename[1] == '\0' || filename[1] == '/')
3341acd27e7Smillert {
3351acd27e7Smillert /* Prefix $HOME to the rest of the string. */
336af70c2dfSkettenis expansion = sh_get_env_value ("HOME");
3371acd27e7Smillert
3381acd27e7Smillert /* If there is no HOME variable, look up the directory in
3391acd27e7Smillert the password database. */
34094bc1d69Smillert if (expansion == 0 || *expansion == '\0')
341af70c2dfSkettenis expansion = sh_get_home_dir ();
3421acd27e7Smillert
3431acd27e7Smillert return (glue_prefix_and_suffix (expansion, filename, 1));
3441acd27e7Smillert }
3451acd27e7Smillert
3461acd27e7Smillert username = isolate_tilde_prefix (filename, &user_len);
3471acd27e7Smillert
3481acd27e7Smillert if (tilde_expansion_preexpansion_hook)
3491acd27e7Smillert {
3501acd27e7Smillert expansion = (*tilde_expansion_preexpansion_hook) (username);
3511acd27e7Smillert if (expansion)
3521acd27e7Smillert {
3531acd27e7Smillert dirname = glue_prefix_and_suffix (expansion, filename, user_len);
3541acd27e7Smillert free (username);
3551acd27e7Smillert free (expansion);
3561acd27e7Smillert return (dirname);
3571acd27e7Smillert }
3581acd27e7Smillert }
3591acd27e7Smillert
3601acd27e7Smillert /* No preexpansion hook, or the preexpansion hook failed. Look in the
3611acd27e7Smillert password database. */
3621acd27e7Smillert dirname = (char *)NULL;
3631acd27e7Smillert user_entry = getpwnam (username);
3641acd27e7Smillert if (user_entry == 0)
3651acd27e7Smillert {
3661acd27e7Smillert /* If the calling program has a special syntax for expanding tildes,
3671acd27e7Smillert and we couldn't find a standard expansion, then let them try. */
3681acd27e7Smillert if (tilde_expansion_failure_hook)
3691acd27e7Smillert {
3701acd27e7Smillert expansion = (*tilde_expansion_failure_hook) (username);
3711acd27e7Smillert if (expansion)
3721acd27e7Smillert {
3731acd27e7Smillert dirname = glue_prefix_and_suffix (expansion, filename, user_len);
3741acd27e7Smillert free (expansion);
3751acd27e7Smillert }
3761acd27e7Smillert }
3771acd27e7Smillert free (username);
3781acd27e7Smillert /* If we don't have a failure hook, or if the failure hook did not
3791acd27e7Smillert expand the tilde, return a copy of what we were passed. */
3801acd27e7Smillert if (dirname == 0)
3811acd27e7Smillert dirname = savestring (filename);
3821acd27e7Smillert }
3831acd27e7Smillert else
3841acd27e7Smillert {
3851acd27e7Smillert free (username);
3861acd27e7Smillert dirname = glue_prefix_and_suffix (user_entry->pw_dir, filename, user_len);
3871acd27e7Smillert }
3881acd27e7Smillert
3891acd27e7Smillert endpwent ();
3901acd27e7Smillert return (dirname);
3911acd27e7Smillert }
3921acd27e7Smillert
3931acd27e7Smillert
3941acd27e7Smillert #if defined (TEST)
3951acd27e7Smillert #undef NULL
3961acd27e7Smillert #include <stdio.h>
3971acd27e7Smillert
main(argc,argv)3981acd27e7Smillert main (argc, argv)
3991acd27e7Smillert int argc;
4001acd27e7Smillert char **argv;
4011acd27e7Smillert {
4021acd27e7Smillert char *result, line[512];
4031acd27e7Smillert int done = 0;
4041acd27e7Smillert
4051acd27e7Smillert while (!done)
4061acd27e7Smillert {
4071acd27e7Smillert printf ("~expand: ");
4081acd27e7Smillert fflush (stdout);
4091acd27e7Smillert
41063bef317Sbeck if (!fgets (line, sizeof(line), stdin))
41163bef317Sbeck strlcpy (line, "done", sizeof(line));
41263bef317Sbeck else if (line[strlen(line) - 1] == '\n')
41363bef317Sbeck line[strlen(line) - 1] = '\0';
4141acd27e7Smillert if ((strcmp (line, "done") == 0) ||
4151acd27e7Smillert (strcmp (line, "quit") == 0) ||
4161acd27e7Smillert (strcmp (line, "exit") == 0))
4171acd27e7Smillert {
4181acd27e7Smillert done = 1;
4191acd27e7Smillert break;
4201acd27e7Smillert }
4211acd27e7Smillert
4221acd27e7Smillert result = tilde_expand (line);
4231acd27e7Smillert printf (" --> %s\n", result);
4241acd27e7Smillert free (result);
4251acd27e7Smillert }
4261acd27e7Smillert exit (0);
4271acd27e7Smillert }
4281acd27e7Smillert
4291acd27e7Smillert static void memory_error_and_abort ();
4301acd27e7Smillert
431af70c2dfSkettenis static void *
xmalloc(bytes)4321acd27e7Smillert xmalloc (bytes)
433af70c2dfSkettenis size_t bytes;
4341acd27e7Smillert {
435af70c2dfSkettenis void *temp = (char *)malloc (bytes);
4361acd27e7Smillert
4371acd27e7Smillert if (!temp)
4381acd27e7Smillert memory_error_and_abort ();
4391acd27e7Smillert return (temp);
4401acd27e7Smillert }
4411acd27e7Smillert
442af70c2dfSkettenis static void *
xrealloc(pointer,bytes)4431acd27e7Smillert xrealloc (pointer, bytes)
444af70c2dfSkettenis void *pointer;
4451acd27e7Smillert int bytes;
4461acd27e7Smillert {
447af70c2dfSkettenis void *temp;
4481acd27e7Smillert
4491acd27e7Smillert if (!pointer)
450af70c2dfSkettenis temp = malloc (bytes);
4511acd27e7Smillert else
452af70c2dfSkettenis temp = realloc (pointer, bytes);
4531acd27e7Smillert
4541acd27e7Smillert if (!temp)
4551acd27e7Smillert memory_error_and_abort ();
4561acd27e7Smillert
4571acd27e7Smillert return (temp);
4581acd27e7Smillert }
4591acd27e7Smillert
4601acd27e7Smillert static void
memory_error_and_abort()4611acd27e7Smillert memory_error_and_abort ()
4621acd27e7Smillert {
4631acd27e7Smillert fprintf (stderr, "readline: out of virtual memory\n");
4641acd27e7Smillert abort ();
4651acd27e7Smillert }
4661acd27e7Smillert
4671acd27e7Smillert /*
4681acd27e7Smillert * Local variables:
4691acd27e7Smillert * compile-command: "gcc -g -DTEST -o tilde tilde.c"
4701acd27e7Smillert * end:
4711acd27e7Smillert */
4721acd27e7Smillert #endif /* TEST */
473