#ifdef _AIX
#pragma alloca
#endif
#include "info.h"
#ifdef __GNUC__
# undef alloca
# define alloca __builtin_alloca
#else
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# else
# ifndef _AIX
char *alloca ();
# endif
# endif
#endif
#if defined (TEST) || defined (STATIC_MALLOC)
static void *xmalloc (), *xrealloc ();
#endif
static char *default_prefixes[] =
{ " ~", "\t~", (char *)NULL };
static char *default_suffixes[] =
{ " ", "\n", (char *)NULL };
CFunction *tilde_expansion_failure_hook = (CFunction *)NULL;
char **tilde_additional_prefixes = default_prefixes;
char **tilde_additional_suffixes = default_suffixes;
static int
tilde_find_prefix (string, len)
char *string;
int *len;
{
register int i, j, string_len;
register char **prefixes = tilde_additional_prefixes;
string_len = strlen (string);
*len = 0;
if (!*string || *string == '~')
return (0);
if (prefixes)
{
for (i = 0; i < string_len; i++)
{
for (j = 0; prefixes[j]; j++)
{
if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
{
*len = strlen (prefixes[j]) - 1;
return (i + *len);
}
}
}
}
return (string_len);
}
static int
tilde_find_suffix (string)
char *string;
{
register int i, j, string_len;
register char **suffixes = tilde_additional_suffixes;
string_len = strlen (string);
for (i = 0; i < string_len; i++)
{
if (string[i] == '/' || !string[i])
break;
for (j = 0; suffixes && suffixes[j]; j++)
{
if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
return (i);
}
}
return (i);
}
char *
tilde_expand (string)
char *string;
{
char *result, *tilde_expand_word ();
int result_size, result_index;
result_size = result_index = 0;
result = (char *)NULL;
while (1)
{
register int start, end;
char *tilde_word, *expansion;
int len;
start = tilde_find_prefix (string, &len);
if ((result_index + start + 1) > result_size)
result = (char *)xrealloc (result, 1 + (result_size += (start + 20)));
strncpy (result + result_index, string, start);
result_index += start;
string += start;
end = tilde_find_suffix (string);
if (!start && !end)
break;
tilde_word = (char *)xmalloc (1 + end);
strncpy (tilde_word, string, end);
tilde_word[end] = '\0';
string += end;
expansion = tilde_expand_word (tilde_word);
free (tilde_word);
len = strlen (expansion);
if ((result_index + len + 1) > result_size)
result = (char *)xrealloc (result, 1 + (result_size += (len + 20)));
strcpy (result + result_index, expansion);
result_index += len;
free (expansion);
}
result[result_index] = '\0';
return (result);
}
char *
tilde_expand_word (filename)
char *filename;
{
char *dirname;
dirname = filename ? xstrdup (filename) : (char *)NULL;
if (dirname && *dirname == '~')
{
char *temp_name;
if (!dirname[1] || dirname[1] == '/')
{
char *temp_home = getenv ("HOME");
if (!temp_home)
{
struct passwd *entry;
entry = (struct passwd *) getpwuid (getuid ());
if (entry)
temp_home = entry->pw_dir;
}
temp_name = (char *)
alloca (1 + strlen (&dirname[1])
+ (temp_home ? strlen (temp_home) : 0));
temp_name[0] = '\0';
if (temp_home)
strcpy (temp_name, temp_home);
strcat (temp_name, &dirname[1]);
free (dirname);
dirname = xstrdup (temp_name);
}
else
{
struct passwd *user_entry;
char *username = (char *)alloca (257);
int i, c;
for (i = 1; (c = dirname[i]); i++)
{
if (c == '/')
break;
else
username[i - 1] = c;
}
username[i - 1] = '\0';
if (!(user_entry = (struct passwd *) getpwnam (username)))
{
if (tilde_expansion_failure_hook)
{
char *expansion;
expansion = (*tilde_expansion_failure_hook) (username);
if (expansion)
{
temp_name = (char *)alloca
(1 + strlen (expansion) + strlen (&dirname[i]));
strcpy (temp_name, expansion);
strcat (temp_name, &dirname[i]);
free (expansion);
goto return_name;
}
}
}
else
{
temp_name = (char *)alloca
(1 + strlen (user_entry->pw_dir) + strlen (&dirname[i]));
strcpy (temp_name, user_entry->pw_dir);
strcat (temp_name, &dirname[i]);
return_name:
free (dirname);
dirname = xstrdup (temp_name);
}
endpwent ();
}
}
return (dirname);
}
#if defined (TEST)
#undef NULL
#include <stdio.h>
main (argc, argv)
int argc;
char **argv;
{
char *result, line[512];
int done = 0;
while (!done)
{
printf ("~expand: ");
fflush (stdout);
if (!gets (line))
strcpy (line, "done");
if ((strcmp (line, "done") == 0) ||
(strcmp (line, "quit") == 0) ||
(strcmp (line, "exit") == 0))
{
done = 1;
break;
}
result = tilde_expand (line);
printf (" --> %s\n", result);
free (result);
}
exit (0);
}
static void memory_error_and_abort ();
static void *
xmalloc (bytes)
int bytes;
{
void *temp = (void *)malloc (bytes);
if (!temp)
memory_error_and_abort ();
return (temp);
}
static void *
xrealloc (pointer, bytes)
void *pointer;
int bytes;
{
void *temp;
if (!pointer)
temp = (char *)malloc (bytes);
else
temp = (char *)realloc (pointer, bytes);
if (!temp)
memory_error_and_abort ();
return (temp);
}
static void
memory_error_and_abort ()
{
fprintf (stderr, _("readline: Out of virtual memory!\n"));
abort ();
}
#endif