Back to index

tetex-bin  3.0
cnf.c
Go to the documentation of this file.
00001 /* cnf.c: read config files.
00002 
00003 Copyright (C) 1994, 95, 96, 97 Karl Berry.
00004 
00005 This library is free software; you can redistribute it and/or
00006 modify it under the terms of the GNU Library General Public
00007 License as published by the Free Software Foundation; either
00008 version 2 of the License, or (at your option) any later version.
00009 
00010 This library is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 Library General Public License for more details.
00014 
00015 You should have received a copy of the GNU Library General Public
00016 License along with this library; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
00018 
00019 #include <kpathsea/config.h>
00020 #include <kpathsea/c-fopen.h>
00021 #include <kpathsea/c-ctype.h>
00022 #include <kpathsea/c-pathch.h>
00023 #include <kpathsea/cnf.h>
00024 #include <kpathsea/db.h>
00025 #include <kpathsea/hash.h>
00026 #include <kpathsea/line.h>
00027 #include <kpathsea/paths.h>
00028 #include <kpathsea/pathsearch.h>
00029 #include <kpathsea/progname.h>
00030 #include <kpathsea/tex-file.h>
00031 #include <kpathsea/variable.h>
00032 
00033 /* By using our own hash table, instead of the environment, we
00034    complicate variable expansion (because we have to look in two
00035    places), but we don't bang so much on the system.  DOS and System V
00036    have very limited environment space.  Also, this way
00037    `kpse_init_format' can distinguish between values originating from
00038    the cnf file and ones from environment variables, which can be useful
00039    for users trying to figure out what's going on.  */
00040 static hash_table_type cnf_hash;
00041 #define CNF_HASH_SIZE 751
00042 #define CNF_NAME "texmf.cnf"
00043 
00044 /* Do a single line in a cnf file: if it's blank or a comment, skip it.
00045    Otherwise, parse <variable>[.<program>] [=] <value>.  Do
00046    this even if the <variable> is already set in the environment, since
00047    the envvalue might contain a trailing :, in which case we'll be
00048    looking for the cnf value.  */
00049 
00050 static void
00051 do_line P1C(string, line)
00052 {
00053   unsigned len;
00054   string start;
00055   string value, var;
00056   string prog = NULL;
00057   
00058   /* Skip leading whitespace.  */
00059   while (ISSPACE (*line))
00060     line++;
00061   
00062   /* More to do only if we have non-comment material left.  */
00063   if (*line == 0 || *line == '%' || *line == '#')
00064     return;
00065   
00066   /* The variable name is everything up to the next space or = or `.'.  */
00067   start = line;
00068   while (!ISSPACE (*line) && *line != '=' && *line != '.')
00069     line++;
00070 
00071   /* `line' is now one character past the end of the variable name.  */
00072   len = line - start;
00073   var = (string)xmalloc (len + 1);
00074   strncpy (var, start, len);
00075   var[len] = 0;
00076   
00077   /* If the variable is qualified with a program name, find out which. */
00078   while (ISSPACE (*line))
00079     line++;
00080   if (*line == '.') {
00081     /* Skip spaces, then everything up to the next space or =.  */
00082     line++;
00083     while (ISSPACE (*line))
00084       line++;
00085     start = line;
00086     while (!ISSPACE (*line) && *line != '=')
00087       line++;
00088 
00089     /* It's annoying to repeat all this, but making a tokenizing
00090        subroutine would be just as long and annoying.  */
00091     len = line - start;
00092     prog = (string)xmalloc (len + 1);
00093     strncpy (prog, start, len);
00094     prog[len] = 0;
00095   }
00096 
00097   /* Skip whitespace, an optional =, more whitespace.  */
00098   while (ISSPACE (*line))
00099     line++;
00100   if (*line == '=') {
00101     line++;
00102     while (ISSPACE (*line))
00103       line++;
00104   }
00105   
00106   /* The value is whatever remains.  Remove trailing whitespace.  */
00107   start = line;
00108   len = strlen (start);
00109   while (len > 0 && ISSPACE (start[len - 1]))
00110     len--;
00111   
00112   value = (string)xmalloc (len + 1);
00113   strncpy (value, start, len);
00114   value[len] = 0;
00115 
00116   /* Suppose we want to write a single texmf.cnf that can be used under
00117      both NT and Unix.  This is feasible except for the path separators
00118      : on Unix, ; on NT.  We can't switch NT to allowing :'s, since :
00119      is the drive separator.  So we switch Unix to allowing ;'s.  On the
00120      other hand, we don't want to change IS_ENV_SEP and all the rest.
00121      
00122      So, simply translate all ;'s in the path
00123      values to :'s if we are a Unix binary.  (Fortunately we don't use ;
00124      in other kinds of texmf.cnf values.)
00125      
00126      If you really want to put ; in your filenames, add
00127      -DALLOW_SEMICOLON_IN_FILENAMES.  (And there's no way to get :'s in
00128      your filenames, sorry.)  */
00129      
00130 #if IS_ENV_SEP(':') && !defined (ALLOW_SEMICOLON_IN_FILENAMES)
00131   {
00132     string loc;
00133     for (loc = value; *loc; loc++) {
00134       if (*loc == ';')
00135         *loc = ':';
00136     }
00137   }
00138 #endif
00139 
00140   /* We want TEXINPUTS.prog to override plain TEXINPUTS.  The simplest
00141      way is to put both in the hash table (so we don't have to write
00142      hash_delete and hash_replace, and keep track of values' sources),
00143      and then look up the .prog version first in `kpse_cnf_get'.  */
00144   if (prog) {
00145     string lhs = concat3 (var, ".", prog);
00146     free (var);
00147     free (prog);
00148     var = lhs;
00149   }
00150   hash_insert (&cnf_hash, var, value);
00151   
00152   /* We could check that anything remaining is preceded by a comment
00153      character, but let's not bother.  */
00154 }
00155 
00156 /* Read all the configuration files in the path.  */
00157 
00158 static void
00159 read_all_cnf P1H(void)
00160 {
00161   string *cnf_files;
00162   string *cnf;
00163   const_string cnf_path = kpse_init_format (kpse_cnf_format);
00164 
00165   cnf_hash = hash_create (CNF_HASH_SIZE);
00166 
00167   cnf_files = kpse_all_path_search (cnf_path, CNF_NAME);
00168   if (cnf_files) {
00169     for (cnf = cnf_files; *cnf; cnf++) {
00170       string line;
00171       FILE *cnf_file = xfopen (*cnf, FOPEN_R_MODE);
00172 
00173       while ((line = read_line (cnf_file)) != NULL) {
00174         unsigned len = strlen (line);
00175         /* Strip trailing spaces. */
00176         while (len > 0 && ISSPACE(line[len-1])) {
00177           line[len - 1] = 0;
00178           --len;
00179         }
00180         /* Concatenate consecutive lines that end with \.  */
00181         while (len > 0 && line[len - 1] == '\\') {
00182           string next_line = read_line (cnf_file);
00183           line[len - 1] = 0;
00184           if (!next_line) {
00185             WARNING1 ("%s: Last line ends with \\", *cnf);
00186           } else {
00187             string new_line;
00188             new_line = concat (line, next_line);
00189             free (line);
00190             line = new_line;
00191             len = strlen (line);
00192           }
00193         }
00194 
00195         do_line (line);
00196         free (line);
00197       }
00198 
00199       xfclose (cnf_file, *cnf);
00200       free (*cnf);
00201     }
00202     free (cnf_files);
00203   }
00204 }
00205 
00206 /* Read the cnf files on the first call.  Return the first value in the
00207    returned list -- this will be from the last-read cnf file.  */
00208 
00209 string
00210 kpse_cnf_get P1C(const_string, name)
00211 {
00212   string ret, ctry;
00213   string *ret_list;
00214   static boolean doing_cnf_init = false;
00215 
00216   /* When we expand the compile-time value for DEFAULT_TEXMFCNF,
00217      we end up needing the value for TETEXDIR and other variables,
00218      so kpse_var_expand ends up calling us again.  No good.  */
00219   if (doing_cnf_init)
00220     return NULL;
00221     
00222   if (cnf_hash.size == 0) {
00223     doing_cnf_init = true;
00224     read_all_cnf ();
00225     doing_cnf_init = false;
00226     
00227     /* Here's a pleasant kludge: Since `kpse_init_dbs' recursively calls
00228        us, we must call it from outside a `kpse_path_element' loop
00229        (namely, the one in `read_all_cnf' above): `kpse_path_element' is
00230        not reentrant.  */
00231     kpse_init_db ();
00232   }
00233   
00234   /* First look up NAME.`kpse_program_name', then NAME.  */
00235   assert (kpse_program_name);
00236   ctry = concat3 (name, ".", kpse_program_name);
00237   ret_list = hash_lookup (cnf_hash, ctry);
00238   free (ctry);
00239   if (ret_list) {
00240     ret = *ret_list;
00241     free (ret_list);
00242   } else {
00243     ret_list = hash_lookup (cnf_hash, name);
00244     if (ret_list) {
00245       ret = *ret_list;
00246       free (ret_list);
00247     } else {
00248       ret = NULL;
00249     }
00250   }
00251   
00252   return ret;
00253 
00254 }