dvitomp fix from Akira
[mplib] / src / texk / kpathsea / cnf.c
1 /* cnf.c: read config files.
2
3    Copyright 1994, 1995, 1996, 1997, 2008 Karl Berry.
4    Copyright 1997-2005 Olaf Weber.
5
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.
10
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.
15
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/>.  */
18
19 #include <kpathsea/config.h>
20 #include <kpathsea/c-fopen.h>
21 #include <kpathsea/c-ctype.h>
22 #include <kpathsea/c-pathch.h>
23 #include <kpathsea/cnf.h>
24 #include <kpathsea/db.h>
25 #include <kpathsea/hash.h>
26 #include <kpathsea/line.h>
27 #include <kpathsea/paths.h>
28 #include <kpathsea/pathsearch.h>
29 #include <kpathsea/progname.h>
30 #include <kpathsea/recorder.h>
31 #include <kpathsea/tex-file.h>
32 #include <kpathsea/variable.h>
33
34 /* Declared in recorder.h, used in fontmap.c, web2c/lib/texmfmp.c.  */
35 void (*kpse_record_input) (const_string);
36 void (*kpse_record_output) (const_string);
37
38 /* By using our own hash table, instead of the environment, we
39    complicate variable expansion (because we have to look in two
40    places), but we don't bang so much on the system.  DOS and System V
41    have very limited environment space.  Also, this way
42    `kpse_init_format' can distinguish between values originating from
43    the cnf file and ones from environment variables, which can be useful
44    for users trying to figure out what's going on.  */
45 static hash_table_type cnf_hash;
46 #define CNF_HASH_SIZE 751
47 #define CNF_NAME "texmf.cnf"
48 \f
49 /* Do a single line in a cnf file: if it's blank or a comment, skip it.
50    Otherwise, parse <variable>[.<program>] [=] <value>.  Do
51    this even if the <variable> is already set in the environment, since
52    the envvalue might contain a trailing :, in which case we'll be
53    looking for the cnf value.  */
54
55 static void
56 do_line P1C(string, line)
57 {
58   unsigned len;
59   string start;
60   string value, var;
61   string prog = NULL;
62   
63   /* Skip leading whitespace.  */
64   while (ISSPACE (*line))
65     line++;
66   
67   /* More to do only if we have non-comment material left.  */
68   if (*line == 0 || *line == '%' || *line == '#')
69     return;
70   
71   /* The variable name is everything up to the next space or = or `.'.  */
72   start = line;
73   while (!ISSPACE (*line) && *line != '=' && *line != '.')
74     line++;
75
76   /* `line' is now one character past the end of the variable name.  */
77   len = line - start;
78   var = (string)xmalloc (len + 1);
79   strncpy (var, start, len);
80   var[len] = 0;
81   
82   /* If the variable is qualified with a program name, find out which. */
83   while (ISSPACE (*line))
84     line++;
85   if (*line == '.') {
86     /* Skip spaces, then everything up to the next space or =.  */
87     line++;
88     while (ISSPACE (*line))
89       line++;
90     start = line;
91     while (!ISSPACE (*line) && *line != '=')
92       line++;
93
94     /* It's annoying to repeat all this, but making a tokenizing
95        subroutine would be just as long and annoying.  */
96     len = line - start;
97     prog = (string)xmalloc (len + 1);
98     strncpy (prog, start, len);
99     prog[len] = 0;
100   }
101
102   /* Skip whitespace, an optional =, more whitespace.  */
103   while (ISSPACE (*line))
104     line++;
105   if (*line == '=') {
106     line++;
107     while (ISSPACE (*line))
108       line++;
109   }
110   
111   /* The value is whatever remains.  Remove trailing whitespace.  */
112   start = line;
113   len = strlen (start);
114   while (len > 0 && ISSPACE (start[len - 1]))
115     len--;
116   
117   value = (string)xmalloc (len + 1);
118   strncpy (value, start, len);
119   value[len] = 0;
120
121   /* Suppose we want to write a single texmf.cnf that can be used under
122      both NT and Unix.  This is feasible except for the path separators
123      : on Unix, ; on NT.  We can't switch NT to allowing :'s, since :
124      is the drive separator.  So we switch Unix to allowing ;'s.  On the
125      other hand, we don't want to change IS_ENV_SEP and all the rest.
126      
127      So, simply translate all ;'s in the path
128      values to :'s if we are a Unix binary.  (Fortunately we don't use ;
129      in other kinds of texmf.cnf values.)  */
130      
131   if (IS_ENV_SEP(':')) {
132       string loc;
133       for (loc = value; *loc; loc++) {
134           if (*loc == ';')
135               *loc = ':';
136       }
137   }
138
139   /* We want TEXINPUTS.prog to override plain TEXINPUTS.  The simplest
140      way is to put both in the hash table (so we don't have to write
141      hash_delete and hash_replace, and keep track of values' sources),
142      and then look up the .prog version first in `kpse_cnf_get'.  */
143   if (prog) {
144     string lhs = concat3 (var, ".", prog);
145     free (var);
146     free (prog);
147     var = lhs;
148   }
149   hash_insert (&cnf_hash, var, value);
150   
151   /* We could check that anything remaining is preceded by a comment
152      character, but let's not bother.  */
153 }
154 \f
155 /* Read all the configuration files in the path.  */
156
157 static void
158 read_all_cnf P1H(void)
159 {
160   string *cnf_files;
161   string *cnf;
162   const_string cnf_path = kpse_init_format (kpse_cnf_format);
163
164   cnf_hash = hash_create (CNF_HASH_SIZE);
165
166   cnf_files = kpse_all_path_search (cnf_path, CNF_NAME);
167   if (cnf_files && *cnf_files) {
168     for (cnf = cnf_files; *cnf; cnf++) {
169       string line;
170       FILE *cnf_file = xfopen (*cnf, FOPEN_R_MODE);
171       if (kpse_record_input)
172         kpse_record_input (*cnf);
173
174       while ((line = read_line (cnf_file)) != NULL) {
175         unsigned len = strlen (line);
176         /* Strip trailing spaces. */
177         while (len > 0 && ISSPACE(line[len-1])) {
178           line[len - 1] = 0;
179           --len;
180         }
181         /* Concatenate consecutive lines that end with \.  */
182         while (len > 0 && line[len - 1] == '\\') {
183           string next_line = read_line (cnf_file);
184           line[len - 1] = 0;
185           if (!next_line) {
186             WARNING1 ("%s: Last line ends with \\", *cnf);
187           } else {
188             string new_line;
189             new_line = concat (line, next_line);
190             free (line);
191             line = new_line;
192             len = strlen (line);
193           }
194         }
195
196         do_line (line);
197         free (line);
198       }
199
200       xfclose (cnf_file, *cnf);
201       free (*cnf);
202     }
203     free (cnf_files);
204   } else {
205     string warn = getenv ("KPATHSEA_WARNING");
206     if (!(warn && STREQ (warn, "0"))) {
207       WARNING1 ("kpathsea: configuration file texmf.cnf not found in these directories: %s", 
208         cnf_path);
209     }
210   }
211 }
212 \f
213 /* Read the cnf files on the first call.  Return the first value in the
214    returned list -- this will be from the last-read cnf file.  */
215
216 string
217 kpse_cnf_get P1C(const_string, name)
218 {
219   string ret, ctry;
220   string *ret_list;
221   static boolean doing_cnf_init = false;
222
223   /* When we expand the compile-time value for DEFAULT_TEXMFCNF,
224      we end up needing the value for TETEXDIR and other variables,
225      so kpse_var_expand ends up calling us again.  No good.  Except this
226      code is not sufficient, somehow the ls-R path needs to be
227      computed when initializing the cnf path.  Better to ensure that the
228      compile-time path does not contain variable references.  */
229   if (doing_cnf_init)
230     return NULL;
231     
232   if (cnf_hash.size == 0) {
233     /* Read configuration files and initialize databases.  */
234     doing_cnf_init = true;
235     read_all_cnf ();
236     doing_cnf_init = false;
237     
238     /* Since `kpse_init_db' recursively calls us, we must call it from
239        outside a `kpse_path_element' loop (namely, the one in
240        `read_all_cnf' above): `kpse_path_element' is not reentrant.  */
241     kpse_init_db ();
242   }
243   
244   /* First look up NAME.`kpse_program_name', then NAME.  */
245   assert (kpse_program_name);
246   ctry = concat3 (name, ".", kpse_program_name);
247   ret_list = hash_lookup (cnf_hash, ctry);
248   free (ctry);
249   if (ret_list) {
250     ret = *ret_list;
251     free (ret_list);
252   } else {
253     ret_list = hash_lookup (cnf_hash, name);
254     if (ret_list) {
255       ret = *ret_list;
256       free (ret_list);
257     } else {
258       ret = NULL;
259     }
260   }
261   
262   return ret;
263 }