"Fossies" - the Fresh Open Source Software Archive

Member "which-2.21/tilde/tilde.c" (16 Jan 2008, 13226 Bytes) of package /linux/privat/which-2.21.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tilde.c" see the Fossies "Dox" file reference documentation.

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