home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / cvs-1.8.7-src.tgz / tar.out / fsf / cvs / src / expand_path.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  6KB  |  244 lines

  1. /* expand_path.c -- expand environmental variables in passed in string
  2.  *
  3.  * The main routine is expand_path(), it is the routine that handles
  4.  * the '~' character in four forms: 
  5.  *     ~name
  6.  *     ~name/
  7.  *     ~/
  8.  *     ~
  9.  * and handles environment variables contained within the pathname
  10.  * which are defined by:
  11.  *     ${var_name}   (var_name is the name of the environ variable)
  12.  *     $var_name     (var_name ends w/ non-alphanumeric char other than '_')
  13.  */
  14.  
  15. #include "cvs.h"
  16. #include <sys/types.h>
  17.  
  18. static char *expand_variable PROTO((char *env, char *file, int line));
  19.  
  20.  
  21. /* User variables.  */
  22.  
  23. List *variable_list = NULL;
  24.  
  25. static void variable_delproc PROTO ((Node *));
  26.  
  27. static void
  28. variable_delproc (node)
  29.     Node *node;
  30. {
  31.     free (node->data);
  32. }
  33.  
  34. /* Currently used by -s option; we might want a way to set user
  35.    variables in a file in the $CVSROOT/CVSROOT directory too.  */
  36.  
  37. void
  38. variable_set (nameval)
  39.     char *nameval;
  40. {
  41.     char *p;
  42.     char *name;
  43.     Node *node;
  44.  
  45.     p = nameval;
  46.     while (isalnum (*p) || *p == '_')
  47.     ++p;
  48.     if (*p != '=')
  49.     error (1, 0, "illegal character in user variable name in %s", nameval);
  50.     if (p == nameval)
  51.     error (1, 0, "empty user variable name in %s", nameval);
  52.     name = xmalloc (p - nameval + 1);
  53.     strncpy (name, nameval, p - nameval);
  54.     name[p - nameval] = '\0';
  55.     /* Make p point to the value.  */
  56.     ++p;
  57.     if (strchr (p, '\012') != NULL)
  58.     error (1, 0, "linefeed in user variable value in %s", nameval);
  59.  
  60.     if (variable_list == NULL)
  61.     variable_list = getlist ();
  62.  
  63.     node = findnode (variable_list, name);
  64.     if (node == NULL)
  65.     {
  66.     node = getnode ();
  67.     node->type = VARIABLE;
  68.     node->delproc = variable_delproc;
  69.     node->key = name;
  70.     node->data = xstrdup (p);
  71.     (void) addnode (variable_list, node);
  72.     }
  73.     else
  74.     {
  75.     /* Replace the old value.  For example, this means that -s
  76.        options on the command line override ones from .cvsrc.  */
  77.     free (node->data);
  78.     node->data = xstrdup (p);
  79.     free (name);
  80.     }
  81. }
  82.  
  83. /* This routine will expand the pathname to account for ~ and $
  84.    characters as described above.  Returns a pointer to a newly
  85.    malloc'd string.  If an error occurs, an error message is printed
  86.    via error() and NULL is returned.  FILE and LINE are the filename
  87.    and linenumber to include in the error message.  FILE must point
  88.    to something; LINE can be zero to indicate the line number is not
  89.    known.  */
  90. char *
  91. expand_path (name, file, line)
  92.     char *name;
  93.     char *file;
  94.     int line;
  95. {
  96.     char *s;
  97.     char *d;
  98.     /* FIXME: arbitrary limit.  */
  99.     char  mybuf[PATH_MAX];
  100.     char  buf[PATH_MAX];
  101.     char *result;
  102.     s = name;
  103.     d = mybuf;
  104.     while ((*d++ = *s))
  105.     if (*s++ == '$')
  106.     {
  107.         char *p = d;
  108.         char *e;
  109.         int flag = (*s == '{');
  110.  
  111.         for (; (*d++ = *s); s++)
  112.         if (flag
  113.             ? *s =='}'
  114.             : isalnum (*s) == 0 && *s != '_')
  115.             break;
  116.         *--d = 0;
  117.         e = expand_variable (&p[flag], file, line);
  118.  
  119.         if (e)
  120.         {
  121.         for (d = &p[-1]; (*d++ = *e++);)
  122.             ;
  123.         --d;
  124.         if (flag && *s)
  125.             s++;
  126.         }
  127.         else
  128.         /* expand_variable has already printed an error message.  */
  129.         return NULL;
  130.     }
  131.     *d = 0;
  132.     s = mybuf;
  133.     d = buf;
  134.     /* If you don't want ~username ~/ to be expanded simply remove
  135.      * This entire if statement including the else portion
  136.      */
  137.     if (*s++ == '~')
  138.     {
  139.     char *t;
  140.     char *p=s;
  141.     if (*s=='/' || *s==0)
  142.         t = get_homedir ();
  143.     else
  144.     {
  145.         struct passwd *ps;
  146.         for (; *p!='/' && *p; p++)
  147.         ;
  148.         *p = 0;
  149.         ps = getpwnam (s);
  150.         if (ps == 0)
  151.         {
  152.         if (line != 0)
  153.             error (0, 0, "%s:%d: no such user %s",
  154.                file, line, s);
  155.         else
  156.             error (0, 0, "%s: no such user %s", file, s);
  157.         return NULL;
  158.         }
  159.         t = ps->pw_dir;
  160.     }
  161.     while ((*d++ = *t++))
  162.         ;
  163.     --d;
  164.     if (*p == 0)
  165.         *p = '/';           /* always add / */
  166.     s=p;
  167.     }
  168.     else
  169.     --s;
  170.     /* Kill up to here */
  171.     while ((*d++ = *s++))
  172.     ;
  173.     *d=0;
  174.     result = xmalloc (sizeof(char) * strlen(buf)+1);
  175.     strcpy (result, buf);
  176.     return result;
  177. }
  178.  
  179. static char *
  180. expand_variable (name, file, line)
  181.     char *name;
  182.     char *file;
  183.     int line;
  184. {
  185.     if (strcmp (name, CVSROOT_ENV) == 0)
  186.     return CVSroot_original;
  187.     else if (strcmp (name, RCSBIN_ENV)  == 0)
  188.     return Rcsbin;
  189.     else if (strcmp (name, EDITOR1_ENV) == 0)
  190.     return Editor;
  191.     else if (strcmp (name, EDITOR2_ENV) == 0)
  192.     return Editor;
  193.     else if (strcmp (name, EDITOR3_ENV) == 0)
  194.     return Editor;
  195.     else if (strcmp (name, "USER") == 0)
  196.     return getcaller ();
  197.     else if (isalpha (name[0]))
  198.     {
  199.     /* These names are reserved for future versions of CVS,
  200.        so that is why it is an error.  */
  201.     if (line != 0)
  202.         error (0, 0, "%s:%d: no such internal variable $%s",
  203.            file, line, name);
  204.     else
  205.         error (0, 0, "%s: no such internal variable $%s",
  206.            file, name);
  207.     return NULL;
  208.     }
  209.     else if (name[0] == '=')
  210.     {
  211.     Node *node;
  212.     /* Crazy syntax for a user variable.  But we want
  213.        *something* that lets the user name a user variable
  214.        anything he wants, without interference from
  215.        (existing or future) internal variables.  */
  216.     node = findnode (variable_list, name + 1);
  217.     if (node == NULL)
  218.     {
  219.         if (line != 0)
  220.         error (0, 0, "%s:%d: no such user variable ${%s}",
  221.                file, line, name);
  222.         else
  223.         error (0, 0, "%s: no such user variable ${%s}",
  224.                file, name);
  225.         return NULL;
  226.     }
  227.     return node->data;
  228.     }
  229.     else
  230.     {
  231.     /* It is an unrecognized character.  We return an error to
  232.        reserve these for future versions of CVS; it is plausible
  233.        that various crazy syntaxes might be invented for inserting
  234.        information about revisions, branches, etc.  */
  235.     if (line != 0)
  236.         error (0, 0, "%s:%d: unrecognized variable syntax %s",
  237.            file, line, name);
  238.     else
  239.         error (0, 0, "%s: unrecognized variable syntax %s",
  240.            file, name);
  241.     return NULL;
  242.     }
  243. }
  244.