1 /* variable.c: variable expansion.
3 Copyright 1993, 1994, 1995, 1996, 2008 Karl Berry.
4 Copyright 1997, 1999, 2001, 2002, 2005 Olaf Weber.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with this library; if not, see <http://www.gnu.org/licenses/>. */
19 #include <kpathsea/config.h>
21 #include <kpathsea/c-ctype.h>
22 #include <kpathsea/cnf.h>
23 #include <kpathsea/fn.h>
24 #include <kpathsea/tilde.h>
25 #include <kpathsea/variable.h>
28 /* Here's the simple one, when a program just wants a value. */
31 kpse_var_value P1C(const_string, var)
35 assert (kpse_program_name);
37 /* First look for VAR.progname. */
38 vtry = concat3 (var, ".", kpse_program_name);
43 /* Now look for VAR_progname. */
44 vtry = concat3 (var, "_", kpse_program_name);
53 /* Not in the environment; check a config file. */
55 ret = kpse_cnf_get (var);
57 /* We have a value; do variable and tilde expansion. We want to use ~
58 in the cnf files, to adapt nicely to Windows and to avoid extra /'s
59 (see tilde.c), but we also want kpsewhich -var-value=foo to not
60 have any literal ~ characters, so our shell scripts don't have to
61 worry about doing the ~ expansion. */
63 string tmp = kpse_var_expand (ret);
64 /* We don't want to free the previous value of ret here; apparently
65 it's used later, somewhere, somehow. (The end result was a crash
66 when making tex.fmt.) Sigh. */
67 ret = kpse_tilde_expand (tmp);
74 if (KPSE_DEBUG_P (KPSE_DEBUG_VARS))
75 DEBUGF2("variable: %s = %s\n", var, ret ? ret : "(nil)");
81 /* We have to keep track of variables being expanded, otherwise
82 constructs like TEXINPUTS = $TEXINPUTS result in an infinite loop.
83 (Or indirectly recursive variables, etc.) Our simple solution is to
84 add to a list each time an expansion is started, and check the list
91 static expansion_type *expansions; /* The sole variable of this type. */
92 static unsigned expansion_len = 0;
95 expanding P2C(const_string, var, boolean, xp)
98 for (e = 0; e < expansion_len; e++) {
99 if (STREQ (expansions[e].var, var)) {
100 expansions[e].expanding = xp;
105 /* New variable, add it to the list. */
107 XRETALLOC (expansions, expansion_len, expansion_type);
108 expansions[expansion_len - 1].var = xstrdup (var);
109 expansions[expansion_len - 1].expanding = xp;
113 /* Return whether VAR is currently being expanding. */
116 expanding_p P1C(const_string, var)
119 for (e = 0; e < expansion_len; e++) {
120 if (STREQ (expansions[e].var, var))
121 return expansions[e].expanding;
127 /* Append the result of value of `var' to EXPANSION, where `var' begins
128 at START and ends at END. If `var' is not set, do not complain.
129 This is a subroutine for the more complicated expansion function. */
132 expand P3C(fn_type *, expansion, const_string, start, const_string, end)
135 unsigned len = end - start + 1;
136 string var = (string)xmalloc (len + 1);
137 strncpy (var, start, len);
140 if (expanding_p (var)) {
141 WARNING1 ("kpathsea: variable `%s' references itself (eventually)", var);
143 string vtry = concat3 (var, "_", kpse_program_name);
144 /* Check for an environment variable. */
145 value = getenv (vtry);
148 if (!value || !*value)
149 value = getenv (var);
151 /* If no envvar, check the config files. */
152 if (!value || !*value)
153 value = kpse_cnf_get (var);
156 expanding (var, true);
157 value = kpse_var_expand (value);
158 expanding (var, false);
160 { /* Do tilde expansion; see explanation above in kpse_var_value. */
161 string tmp = kpse_tilde_expand (value);
168 fn_grow (expansion, value, strlen (value));
176 /* Can't think of when it would be useful to change these (and the
177 diagnostic messages assume them), but ... */
178 #ifndef IS_VAR_START /* starts all variable references */
179 #define IS_VAR_START(c) ((c) == '$')
181 #ifndef IS_VAR_CHAR /* variable name constituent */
182 #define IS_VAR_CHAR(c) (ISALNUM (c) || (c) == '_')
184 #ifndef IS_VAR_BEGIN_DELIMITER /* start delimited variable name (after $) */
185 #define IS_VAR_BEGIN_DELIMITER(c) ((c) == '{')
187 #ifndef IS_VAR_END_DELIMITER
188 #define IS_VAR_END_DELIMITER(c) ((c) == '}')
192 /* Maybe we should support some or all of the various shell ${...}
193 constructs, especially ${var-value}. We do do ~ expansion. */
196 kpse_var_expand P1C(const_string, src)
201 expansion = fn_init ();
203 /* Copy everything but variable constructs. */
204 for (s = src; *s; s++) {
205 if (IS_VAR_START (*s)) {
208 /* Three cases: `$VAR', `${VAR}', `$<anything-else>'. */
209 if (IS_VAR_CHAR (*s)) {
210 /* $V: collect name constituents, then expand. */
211 const_string var_end = s;
215 } while (IS_VAR_CHAR (*var_end));
217 var_end--; /* had to go one past */
218 expand (&expansion, s, var_end);
221 } else if (IS_VAR_BEGIN_DELIMITER (*s)) {
222 /* ${: scan ahead for matching delimiter, then expand. */
223 const_string var_end = ++s;
225 while (*var_end && !IS_VAR_END_DELIMITER (*var_end))
229 WARNING1 ("%s: No matching } for ${", src);
230 s = var_end - 1; /* will incr to null at top of loop */
232 expand (&expansion, s, var_end - 1);
233 s = var_end; /* will incr past } at top of loop*/
237 /* $<something-else>: error. */
238 WARNING2 ("%s: Unrecognized variable construct `$%c'", src, *s);
239 /* Just ignore those chars and keep going. */
242 fn_1grow (&expansion, *s);
244 fn_1grow (&expansion, 0);
246 ret = FN_STRING (expansion);
253 test_var (string test, string right_answer)
255 string result = kpse_var_expand (test);
257 printf ("expansion of `%s'\t=> %s", test, result);
258 if (!STREQ (result, right_answer))
259 printf (" [should be `%s']", right_answer);
268 test_var ("$foo", "");
269 test_var ("a$foo", "a");
270 test_var ("$foo a", " a");
271 test_var ("a$foo b", "a b");
273 xputenv ("FOO", "foo value");
274 test_var ("a$FOO", "afoo value");
276 xputenv ("Dollar", "$");
277 test_var ("$Dollar a", "$ a");
279 test_var ("a${FOO}b", "afoo valueb");
280 test_var ("a${}b", "ab");
282 test_var ("$$", ""); /* and error */
283 test_var ("a${oops", "a"); /* and error */
293 standalone-compile-command: "gcc -g -I. -I.. -DTEST variable.c kpathsea.a"