beta-0.89.2
[luatex.git] / source / texk / kpathsea / variable.c
blobf2072441ab8b033fbadd4cb8a6ac1d93c71d3826
1 /* variable.c: variable expansion.
3 Copyright 1993, 1994, 1995, 1996, 2008, 2009, 2011, 2012 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/expand.h>
25 #include <kpathsea/variable.h>
28 /* Here's the simple one, when a program just wants a value. */
30 string
31 kpathsea_var_value (kpathsea kpse, const_string var)
33 string vtry, ret;
34 const_string value;
36 assert (kpse->program_name);
38 /* First look for VAR.progname. */
39 vtry = concat3 (var, ".", kpse->program_name);
40 value = getenv (vtry);
41 free (vtry);
43 if (!value || !*value) {
44 /* Now look for VAR_progname. */
45 vtry = concat3 (var, "_", kpse->program_name);
46 value = getenv (vtry);
47 free (vtry);
50 /* Just plain VAR. */
51 if (!value || !*value)
52 value = getenv (var);
54 /* Not in the environment; check a config file. */
55 if (!value || !*value)
56 value = kpathsea_cnf_get (kpse, var);
58 /* We have a value; do variable and tilde expansion. We want to use ~
59 in the cnf files, to adapt nicely to Windows and to avoid extra /'s
60 (see tilde.c), but we also want kpsewhich -var-value=foo to not
61 have any literal ~ characters, so our shell scripts don't have to
62 worry about doing the ~ expansion. */
63 ret = value ? kpathsea_expand (kpse, value) : NULL;
65 #ifdef KPSE_DEBUG
66 if (KPATHSEA_DEBUG_P (KPSE_DEBUG_VARS))
67 DEBUGF2("variable: %s = %s\n", var, ret ? ret : "(nil)");
68 #endif
70 return ret;
73 #if defined (KPSE_COMPAT_API)
74 string
75 kpse_var_value (const_string var)
77 return kpathsea_var_value (kpse_def,var);
79 #endif
82 /* We have to keep track of variables being expanded, otherwise
83 constructs like TEXINPUTS = $TEXINPUTS result in an infinite loop.
84 (Or indirectly recursive variables, etc.) Our simple solution is to
85 add to a list each time an expansion is started, and check the list
86 before expanding. */
88 static void
89 expanding (kpathsea kpse, const_string var, boolean xp)
91 unsigned e;
92 for (e = 0; e < kpse->expansion_len; e++) {
93 if (STREQ (kpse->expansions[e].var, var)) {
94 kpse->expansions[e].expanding = xp;
95 return;
99 /* New variable, add it to the list. */
100 kpse->expansion_len++;
101 XRETALLOC (kpse->expansions, kpse->expansion_len, expansion_type);
102 kpse->expansions[kpse->expansion_len - 1].var = xstrdup (var);
103 kpse->expansions[kpse->expansion_len - 1].expanding = xp;
107 /* Return whether VAR is currently being expanding. */
109 static boolean
110 expanding_p (kpathsea kpse, const_string var)
112 unsigned e;
113 for (e = 0; e < kpse->expansion_len; e++) {
114 if (STREQ (kpse->expansions[e].var, var))
115 return kpse->expansions[e].expanding;
118 return false;
121 /* Append the result of value of `var' to EXPANSION, where `var' begins
122 at START and ends at END. If `var' is not set, do not complain.
123 Return 1 if `var' was defined, 0 if not. This is a subroutine for
124 the `kpathsea_var_expand' function. */
126 static boolean
127 expand (kpathsea kpse, fn_type *expansion,
128 const_string start, const_string end)
130 boolean ret = false;
131 const_string value;
132 unsigned len = end - start + 1;
133 string var = (string)xmalloc (len + 1);
134 strncpy (var, start, len);
135 var[len] = 0;
137 if (expanding_p (kpse, var)) {
138 WARNING1 ("kpathsea: variable `%s' references itself (eventually)", var);
139 } else {
140 string vtry = concat3 (var, "_", kpse->program_name);
141 /* Check for an environment variable. */
142 value = getenv (vtry);
143 free (vtry);
145 if (!value || !*value)
146 value = getenv (var);
148 /* If no envvar, check the config files. */
149 if (!value || !*value)
150 value = kpathsea_cnf_get (kpse, var);
152 if (value) {
153 string tmp;
154 ret = true;
155 expanding (kpse, var, true);
156 tmp = kpathsea_expand (kpse, value);
157 expanding (kpse, var, false);
159 fn_grow (expansion, tmp, strlen (tmp));
160 free (tmp);
164 free (var);
165 return ret;
168 /* Can't think of when it would be useful to change these (and the
169 diagnostic messages assume them), but ... */
170 #ifndef IS_VAR_START /* starts all variable references */
171 #define IS_VAR_START(c) ((c) == '$')
172 #endif
173 #ifndef IS_VAR_CHAR /* variable name constituent */
174 #define IS_VAR_CHAR(c) (ISALNUM (c) || (c) == '_')
175 #endif
176 #ifndef IS_VAR_BEGIN_DELIMITER /* start delimited variable name (after $) */
177 #define IS_VAR_BEGIN_DELIMITER(c) ((c) == '{')
178 #endif
179 #ifndef IS_VAR_END_DELIMITER
180 #define IS_VAR_END_DELIMITER(c) ((c) == '}')
181 #endif
184 /* Maybe we should support some or all of the various shell ${...}
185 constructs, especially ${var-value}. We do do ~ expansion. */
187 string
188 kpathsea_var_expand (kpathsea kpse, const_string src)
190 const_string s;
191 string ret;
192 fn_type expansion;
193 expansion = fn_init ();
195 /* Copy everything but variable constructs. */
196 for (s = src; *s; s++) {
197 if (IS_VAR_START (*s)) {
198 s++;
200 /* Three cases: `$VAR', `${VAR}', `$<anything-else>'. */
201 if (IS_VAR_CHAR (*s)) {
202 /* $V: collect name constituents, then expand. */
203 const_string var_end = s;
205 do {
206 var_end++;
207 } while (IS_VAR_CHAR (*var_end));
209 var_end--; /* had to go one past */
210 if (!expand (kpse, &expansion, s, var_end)) {
211 /* If no expansion, include the literal $x construct,
212 so filenames containing dollar signs can be read.
213 The first +1 is to get the full variable name,
214 the other +1 is to get the dollar sign; we've moved past it. */
215 fn_grow (&expansion, s - 1, var_end - s + 1 + 1);
217 s = var_end;
219 } else if (IS_VAR_BEGIN_DELIMITER (*s)) {
220 /* ${: scan ahead for matching delimiter, then expand. */
221 const_string var_end = ++s;
223 while (*var_end && !IS_VAR_END_DELIMITER (*var_end)) {
224 #if defined(WIN32)
225 if (IS_KANJI(var_end))
226 var_end++;
227 #endif
228 var_end++;
231 if (! *var_end) {
232 WARNING1 ("kpathsea: %s: No matching } for ${", src);
233 s = var_end - 1; /* will incr to null at top of loop */
234 } else {
235 expand (kpse, &expansion, s, var_end - 1);
236 s = var_end; /* will incr past } at top of loop*/
239 } else {
240 /* $<something-else>: warn, but preserve characters; again, so
241 filenames containing dollar signs can be read. */
242 WARNING2 ("kpathsea: %s: Unrecognized variable construct `$%c'",
243 src, *s);
244 fn_grow (&expansion, s - 1, 2); /* moved past the $ */
246 } else
247 fn_1grow (&expansion, *s);
249 fn_1grow (&expansion, 0);
251 ret = FN_STRING (expansion);
252 return ret;
255 #if defined (KPSE_COMPAT_API)
256 string
257 kpse_var_expand (const_string src)
259 return kpathsea_var_expand (kpse_def,src);
261 #endif
264 #ifdef TEST
266 static void
267 test_var (string test, string right_answer)
269 string result = kpse_var_expand (test);
271 printf ("expansion of `%s'\t=> %s", test, result);
272 if (!STREQ (result, right_answer))
273 printf (" [should be `%s']", right_answer);
274 putchar ('\n');
279 main (int argc, char **argv)
281 kpse_set_program_name(argv[0], NULL);
282 test_var ("a", "a");
283 test_var ("$foo", "");
284 test_var ("a$foo", "a");
285 test_var ("$foo a", " a");
286 test_var ("a$foo b", "a b");
288 xputenv ("FOO", "foo value");
289 test_var ("a$FOO", "afoo value");
291 xputenv ("Dollar", "$");
292 test_var ("$Dollar a", "$ a");
294 test_var ("a${FOO}b", "afoo valueb");
295 test_var ("a${}b", "ab");
297 test_var ("$$", ""); /* and error */
298 test_var ("a${oops", "a"); /* and error */
300 return 0;
303 #endif /* TEST */
307 Local variables:
308 standalone-compile-command: "gcc -g -I. -I.. -DTEST variable.c kpathsea.a"
309 End: