1 /* expand_path.c -- expand environmental variables in passed in string
3 * The main routine is expand_path(), it is the routine that handles
4 * the '~' character in four forms:
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 '_')
16 #include <sys/types.h>
18 static char *expand_variable PROTO((const char *env, const char *file,
25 List *variable_list = NULL;
27 static void variable_delproc PROTO ((Node *));
30 variable_delproc (node)
36 /* Currently used by -s option; we might want a way to set user
37 variables in a file in the $CVSROOT/CVSROOT directory too. */
40 variable_set (nameval)
48 while (isalnum ((unsigned char) *p) || *p == '_')
51 error (1, 0, "illegal character in user variable name in %s", nameval);
53 error (1, 0, "empty user variable name in %s", nameval);
54 name = xmalloc (p - nameval + 1);
55 strncpy (name, nameval, p - nameval);
56 name[p - nameval] = '\0';
57 /* Make p point to the value. */
59 if (strchr (p, '\012') != NULL)
60 error (1, 0, "linefeed in user variable value in %s", nameval);
62 if (variable_list == NULL)
63 variable_list = getlist ();
65 node = findnode (variable_list, name);
69 node->type = VARIABLE;
70 node->delproc = variable_delproc;
72 node->data = xstrdup (p);
73 (void) addnode (variable_list, node);
77 /* Replace the old value. For example, this means that -s
78 options on the command line override ones from .cvsrc. */
80 node->data = xstrdup (p);
87 /* This routine will expand the pathname to account for ~ and $
88 characters as described above. Returns a pointer to a newly
89 malloc'd string. If an error occurs, an error message is printed
90 via error() and NULL is returned. FILE and LINE are the filename
91 and linenumber to include in the error message. FILE must point
92 to something; LINE can be zero to indicate the line number is not
95 expand_path (name, file, line)
104 size_t mybuf_size = 0;
112 /* Sorry this routine is so ugly; it is a head-on collision
113 between the `traditional' unix *d++ style and the need to
114 dynamically allocate. It would be much cleaner (and probably
115 faster, not that this is a bottleneck for CVS) with more use of
116 strcpy & friends, but I haven't taken the effort to rewrite it
119 /* First copy from NAME to MYBUF, expanding $<foo> as we go. */
123 expand_string (&mybuf, &mybuf_size, doff + 1);
131 int flag = (*s == '{');
134 expand_string (&mybuf, &mybuf_size, doff + 1);
136 for (; (*d++ = *s); s++)
140 : isalnum ((unsigned char) *s) == 0 && *s != '_')
143 expand_string (&mybuf, &mybuf_size, doff + 1);
147 e = expand_variable (&p[flag], file, line);
152 expand_string (&mybuf, &mybuf_size, doff + 1);
154 for (d = &p[-1]; (*d++ = *e++);)
157 expand_string (&mybuf, &mybuf_size, doff + 1);
165 /* expand_variable has already printed an error message. */
169 expand_string (&mybuf, &mybuf_size, doff + 1);
173 expand_string (&mybuf, &mybuf_size, doff + 1);
177 /* Then copy from MYBUF to BUF, expanding ~. */
180 /* If you don't want ~username ~/ to be expanded simply remove
181 * This entire if statement including the else portion
187 pstart = p = xstrdup (s);
188 if (*pstart=='/' || *pstart==0)
192 #ifdef GETPWNAM_MISSING
193 for (; *p!='/' && *p; p++)
198 "%s:%d:tilde expansion not supported on this system",
201 error (0, 0, "%s:tilde expansion not supported on this system",
206 for (; *p!='/' && *p; p++)
209 ps = getpwnam (pstart);
213 error (0, 0, "%s:%d: no such user %s",
216 error (0, 0, "%s: no such user %s", file, pstart);
223 error (1, 0, "cannot find home directory");
226 expand_string (&buf, &buf_size, doff + 1);
228 while ((*d++ = *t++))
231 expand_string (&buf, &buf_size, doff + 1);
240 /* Kill up to here */
242 expand_string (&buf, &buf_size, doff + 1);
244 while ((*d++ = *s++))
247 expand_string (&buf, &buf_size, doff + 1);
251 expand_string (&buf, &buf_size, doff + 1);
255 /* OK, buf contains the value we want to return. Clean up and return
258 /* Save a little memory with xstrdup; buf will tend to allocate
259 more than it needs to. */
260 result = xstrdup (buf);
273 expand_variable (name, file, line)
278 if (strcmp (name, CVSROOT_ENV) == 0)
279 return current_parsed_root->directory;
280 else if (strcmp (name, "RCSBIN") == 0)
282 error (0, 0, "RCSBIN internal variable is no longer supported");
285 else if (strcmp (name, EDITOR1_ENV) == 0)
287 else if (strcmp (name, EDITOR2_ENV) == 0)
289 else if (strcmp (name, EDITOR3_ENV) == 0)
291 else if (strcmp (name, "USER") == 0)
293 else if (isalpha ((unsigned char) name[0]))
295 /* These names are reserved for future versions of CVS,
296 so that is why it is an error. */
298 error (0, 0, "%s:%d: no such internal variable $%s",
301 error (0, 0, "%s: no such internal variable $%s",
305 else if (name[0] == '=')
308 /* Crazy syntax for a user variable. But we want
309 *something* that lets the user name a user variable
310 anything he wants, without interference from
311 (existing or future) internal variables. */
312 node = findnode (variable_list, name + 1);
316 error (0, 0, "%s:%d: no such user variable ${%s}",
319 error (0, 0, "%s: no such user variable ${%s}",
327 /* It is an unrecognized character. We return an error to
328 reserve these for future versions of CVS; it is plausible
329 that various crazy syntaxes might be invented for inserting
330 information about revisions, branches, etc. */
332 error (0, 0, "%s:%d: unrecognized variable syntax %s",
335 error (0, 0, "%s: unrecognized variable syntax %s",