Back to index

tetex-bin  3.0
kpsewhich.c
Go to the documentation of this file.
00001 /* kpsewhich -- standalone path lookup and variable expansion for Kpathsea.
00002    Ideas from Thomas Esser and Pierre MacKay.
00003 
00004 Copyright (C) 1995 - 2004 Karl Berry & Olaf Weber.
00005 
00006 This library is free software; you can redistribute it and/or
00007 modify it under the terms of the GNU Library General Public
00008 License as published by the Free Software Foundation; either
00009 version 2 of the License, or (at your option) any later version.
00010 
00011 This library is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 Library General Public License for more details.
00015 
00016 You should have received a copy of the GNU Library General Public
00017 License along with this library; if not, write to the Free Software
00018 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
00019 
00020 #include <kpathsea/config.h>
00021 #include <kpathsea/c-ctype.h>
00022 #include <kpathsea/c-pathch.h>
00023 #include <kpathsea/expand.h>
00024 #include <kpathsea/getopt.h>
00025 #include <kpathsea/line.h>
00026 #include <kpathsea/pathsearch.h>
00027 #include <kpathsea/proginit.h>
00028 #include <kpathsea/tex-file.h>
00029 #include <kpathsea/tex-glyph.h>
00030 #include <kpathsea/variable.h>
00031 #include <kpathsea/progname.h>
00032 
00033 
00034 /* Base resolution. (-D, -dpi) */
00035 unsigned dpi = 600;
00036 
00037 /* For variable and path expansion.  (-expand-var, -expand-path,
00038    -show-path, -separator) */
00039 string var_to_expand = NULL;
00040 string braces_to_expand = NULL;
00041 string path_to_expand = NULL;
00042 string path_to_show = NULL;
00043 string var_to_value = NULL;
00044 
00045 /* The file type and path for lookups.  (-format, -path) */
00046 kpse_file_format_type user_format = kpse_last_format;
00047 string user_format_string;
00048 string user_path;
00049 
00050 /* Interactively ask for names to look up?  (-interactive) */
00051 boolean interactive = false;
00052 
00053 /* Search the disk as well as ls-R?  (-must-exist) */
00054 boolean must_exist = false;
00055 
00056 /* Return all matches, not just the first one?  (-all) */
00057 boolean show_all = false;
00058 
00059 /* The device name, for $MAKETEX_MODE.  (-mode) */
00060 string mode = NULL;
00061 
00062 /* The program name, for `.PROG' construct in texmf.cnf.  (-program) */
00063 string progname = NULL;
00064 
00065 /* The engine name, for '$engine' construct in texmf.cnf.  (-engine) */
00066 string engine = NULL;
00067 
00068 /* Return the <number> substring in `<name>.<number><stuff>', if S has
00069    that form.  If it doesn't, return 0.  */
00070 
00071 static unsigned
00072 find_dpi P1C(string, s)
00073 {
00074   unsigned dpi_number = 0;
00075   string extension = find_suffix (s);
00076   
00077   if (extension != NULL)
00078     sscanf (extension, "%u", &dpi_number);
00079 
00080   return dpi_number;
00081 }
00082 
00083 /* Use the file type from -format if that was specified, else guess
00084    dynamically from NAME.  Return kpse_last_format if undeterminable.
00085    This function is also used to parse the -format string, a case which
00086    we distinguish by setting is_filename to false.
00087 
00088    Note that a few filenames have been hard-coded for format types that
00089    differ from what would be inferred from their extensions. */
00090 
00091 static kpse_file_format_type
00092 find_format P2C(string, name, boolean, is_filename)
00093 {
00094   kpse_file_format_type ret;
00095   
00096   if (is_filename && user_format != kpse_last_format) {
00097     ret = user_format;
00098   } else if (FILESTRCASEEQ (name, "pdftex.cfg")) {
00099     ret = kpse_pdftex_config_format;
00100   } else {
00101     int f;  /* kpse_file_format_type */
00102     unsigned name_len = strlen (name);
00103 
00104 /* Have to rely on `try_len' being declared here, since we can't assume
00105    GNU C and statement expressions.  */
00106 #define TRY_SUFFIX(ftry) (\
00107   try_len = (ftry) ? strlen (ftry) : 0, \
00108   (ftry) && try_len <= name_len \
00109      && FILESTRCASEEQ (ftry, name + name_len - try_len))
00110 
00111     f = 0;
00112     while (f != kpse_last_format) {
00113       unsigned try_len;
00114       const_string *ext;
00115       const_string ftry;
00116       boolean found = false;
00117       
00118       if (!kpse_format_info[f].type)
00119         kpse_init_format ((kpse_file_format_type)f);
00120 
00121       if (!is_filename) {
00122         /* Allow the long name, but only in the -format option.  We don't
00123            want a filename confused with a format name.  */
00124         ftry = kpse_format_info[f].type;
00125         found = TRY_SUFFIX (ftry);
00126       }
00127       for (ext = kpse_format_info[f].suffix; !found && ext && *ext; ext++){
00128         found = TRY_SUFFIX (*ext);
00129       }      
00130       for (ext = kpse_format_info[f].alt_suffix; !found && ext && *ext; ext++){
00131         found = TRY_SUFFIX (*ext);
00132       }
00133 
00134       if (found)
00135         break;
00136 
00137       /* Some trickery here: the extensions for kpse_fmt_format can
00138        * clash with other extensions in use, and we prefer for those
00139        * others to be preferred.  And we don't want to change the
00140        * integer value of kpse_fmt_format.  So skip it when first
00141        * enountered, then use it when we've done everything else,
00142        * and use it as the end-guard.
00143        */
00144       if (f == kpse_fmt_format) {
00145         f = kpse_last_format;
00146       } else if (++f == kpse_fmt_format) {
00147         f++;
00148       } else if (f == kpse_last_format) {
00149         f = kpse_fmt_format;
00150       }
00151     }
00152 
00153     /* If there was a match, f will be one past the correct value.  */
00154     ret = f;
00155   }
00156   
00157   return ret;
00158 }
00159 
00160 /* Look up a single filename NAME.  Return 0 if success, 1 if failure.  */
00161 
00162 static unsigned
00163 lookup P1C(string, name)
00164 {
00165   string ret = NULL;
00166   string *ret_list = NULL;
00167   int i;
00168   unsigned local_dpi;
00169   kpse_glyph_file_type glyph_ret;
00170   
00171   if (user_path) {
00172     if (show_all) {
00173       ret_list = kpse_all_path_search (user_path, name);
00174     } else {
00175        ret = kpse_path_search (user_path, name, must_exist);
00176     }
00177     
00178   } else {
00179     /* No user-specified search path, check user format or guess from NAME.  */
00180     kpse_file_format_type fmt = find_format (name, true);
00181 
00182     switch (fmt) {
00183       case kpse_pk_format:
00184       case kpse_gf_format:
00185       case kpse_any_glyph_format:
00186         /* Try to extract the resolution from the name.  */
00187         local_dpi = find_dpi (name);
00188         if (!local_dpi)
00189           local_dpi = dpi;
00190         ret = kpse_find_glyph (remove_suffix (name), local_dpi, fmt, &glyph_ret);
00191         break;
00192 
00193       case kpse_last_format:
00194         /* If the suffix isn't recognized, assume it's a tex file. */
00195         fmt = kpse_tex_format;
00196         /* fall through */
00197 
00198       default:
00199         ret = kpse_find_file (name, fmt, must_exist);
00200     }
00201   }
00202   
00203   if (ret)
00204     puts (ret);
00205   if (ret_list) {
00206     for (i = 0; ret_list[i]; i++)
00207       puts (ret_list[i]);
00208     /* Save whether we found anything */
00209     ret = ret_list[0];
00210     free (ret_list);
00211   }
00212   
00213   return ret == NULL;
00214 }
00215 
00216 /* Reading the options.  */
00217 
00218 #define USAGE "\
00219   Standalone path lookup and expansion for Kpathsea.\n\
00220 \n\
00221 -debug=NUM             set debugging flags.\n\
00222 -D, -dpi=NUM           use a base resolution of NUM; default 600.\n\
00223 -engine=STRING         set engine name to STRING.\n\
00224 -expand-braces=STRING  output variable and brace expansion of STRING.\n\
00225 -expand-path=STRING    output complete path expansion of STRING.\n\
00226 -expand-var=STRING     output variable expansion of STRING.\n\
00227 -format=NAME           use file type NAME (see list below).\n\
00228 -help                  print this message and exit.\n\
00229 -interactive           ask for additional filenames to look up.\n\
00230 [-no]-mktex=FMT        disable/enable mktexFMT generation (FMT=pk/mf/tex/tfm).\n\
00231 -mode=STRING           set device name for $MAKETEX_MODE to STRING;\n\
00232                        no default.\n\
00233 -must-exist            search the disk as well as ls-R if necessary\n\
00234 -path=STRING           search in the path STRING.\n\
00235 -progname=STRING       set program name to STRING.\n\
00236 -show-path=NAME        output search path for file type NAME (see list below).\n\
00237 -var-value=STRING      output the value of variable $STRING.\n\
00238 -version               print version number and exit.\n \
00239 "
00240 
00241 /* Test whether getopt found an option ``A''.
00242    Assumes the option index is in the variable `option_index', and the
00243    option table in a variable `long_options'.  */
00244 #define ARGUMENT_IS(a) STREQ (long_options[option_index].name, a)
00245 
00246 /* SunOS cc can't initialize automatic structs.  */
00247 static struct option long_options[]
00248   = { { "D",                1, 0, 0 },
00249       { "all",                     0, (int *) &show_all, 1 },
00250       { "debug",            1, 0, 0 },
00251       { "dpi",                     1, 0, 0 },
00252       { "engine",           1, 0, 0 },
00253       { "expand-braces",    1, 0, 0 },
00254       { "expand-path",             1, 0, 0 },
00255       { "expand-var",              1, 0, 0 },
00256       { "format",           1, 0, 0 },
00257       { "help",                 0, 0, 0 },
00258       { "interactive",             0, (int *) &interactive, 1 },
00259       { "mktex",            1, 0, 0 },
00260       { "mode",                    1, 0, 0 },
00261       { "must-exist",              0, (int *) &must_exist, 1 },
00262       { "path",                    1, 0, 0 },
00263       { "no-mktex",         1, 0, 0 },
00264       { "progname",         1, 0, 0 },
00265       { "separator",        1, 0, 0 },
00266       { "show-path",        1, 0, 0 },
00267       { "var-value",        1, 0, 0 },
00268       { "version",              0, 0, 0 },
00269       { 0, 0, 0, 0 } };
00270 
00271 static void
00272 read_command_line P2C(int, argc,  string *, argv)
00273 {
00274   int g;   /* `getopt' return code.  */
00275   int option_index;
00276 
00277   for (;;) {
00278     g = getopt_long_only (argc, argv, "", long_options, &option_index);
00279 
00280     if (g == -1)
00281       break;
00282 
00283     if (g == '?')
00284       exit (1);  /* Unknown option.  */
00285 
00286     assert (g == 0); /* We have no short option names.  */
00287 
00288     if (ARGUMENT_IS ("debug")) {
00289       kpathsea_debug |= atoi (optarg);
00290 
00291     } else if (ARGUMENT_IS ("dpi") || ARGUMENT_IS ("D")) {
00292       dpi = atoi (optarg);
00293 
00294     } else if (ARGUMENT_IS ("engine")) {
00295       engine = optarg;
00296       
00297     } else if (ARGUMENT_IS ("expand-braces")) {
00298       braces_to_expand = optarg;
00299       
00300     } else if (ARGUMENT_IS ("expand-path")) {
00301       path_to_expand = optarg;
00302 
00303     } else if (ARGUMENT_IS ("expand-var")) {
00304       var_to_expand = optarg;
00305 
00306     } else if (ARGUMENT_IS ("format")) {
00307       user_format_string = optarg;
00308 
00309     } else if (ARGUMENT_IS ("help")) {
00310       int f; /* kpse_file_format_type */
00311       extern KPSEDLL char *kpse_bug_address; /* from version.c */
00312       
00313       printf ("Usage: %s [OPTION]... [FILENAME]...\n", argv[0]);
00314       fputs (USAGE, stdout);
00315       putchar ('\n');
00316       fputs (kpse_bug_address, stdout);
00317 
00318       /* Have to set this for init_format to work.  */
00319       kpse_set_program_name (argv[0], progname);
00320 
00321       puts ("\nRecognized format names and their suffixes:");
00322       for (f = 0; f < kpse_last_format; f++) {
00323         const_string *ext;
00324         kpse_init_format ((kpse_file_format_type)f);
00325         printf ("%s:", kpse_format_info[f].type);
00326         for (ext = kpse_format_info[f].suffix; ext && *ext; ext++) {
00327           putchar (' ');
00328           fputs (*ext, stdout);
00329         }
00330         for (ext = kpse_format_info[f].alt_suffix; ext && *ext; ext++) {
00331           putchar (' ');
00332           fputs (*ext, stdout);
00333         }
00334         putchar ('\n');
00335       }
00336 
00337       exit (0);
00338 
00339     } else if (ARGUMENT_IS ("mktex")) {
00340       kpse_maketex_option (optarg, true);
00341 
00342     } else if (ARGUMENT_IS ("mode")) {
00343       mode = optarg;
00344 
00345     } else if (ARGUMENT_IS ("no-mktex")) {
00346       kpse_maketex_option (optarg, false);
00347 
00348     } else if (ARGUMENT_IS ("path")) {
00349       user_path = optarg;
00350 
00351     } else if (ARGUMENT_IS ("progname")) {
00352       progname = optarg;
00353 
00354     } else if (ARGUMENT_IS ("show-path")) {
00355       path_to_show = optarg;
00356       user_format_string = optarg;
00357 
00358     } else if (ARGUMENT_IS ("var-value")) {
00359       var_to_value = optarg;
00360 
00361     } else if (ARGUMENT_IS ("version")) {
00362       extern KPSEDLL char *kpathsea_version_string; /* from version.c */
00363       puts (kpathsea_version_string);
00364       puts ("Copyright (C) 1997 - 2004 K. Berry & O. Weber.\n\
00365 There is NO warranty.  You may redistribute this software\n\
00366 under the terms of the GNU General Public License.\n\
00367 For more information about these matters, see the files named COPYING.");
00368       exit (0);
00369     }
00370 
00371     /* Else it was just a flag; getopt has already done the assignment.  */
00372   }
00373   
00374   if (user_path && user_format_string) {
00375     fprintf (stderr, "-path (%s) and -format (%s) are mutually exclusive.\n",
00376              user_path, user_format_string);
00377     fputs ("Try `kpsewhich --help' for more information.\n", stderr);
00378     exit (1);
00379   }
00380 
00381   if (optind == argc && !var_to_expand && !braces_to_expand && !path_to_expand
00382                      && !path_to_show && !var_to_value) {
00383     fputs ("Missing argument. Try `kpsewhich --help' for more information.\n",
00384            stderr);
00385     exit (1);
00386   }
00387 }
00388 
00389 int
00390 main P2C(int, argc,  string *, argv)
00391 {
00392   unsigned unfound = 0;
00393 
00394   read_command_line (argc, argv);
00395 
00396   kpse_set_program_name (argv[0], progname);
00397 
00398   if (engine)
00399     xputenv("engine", engine);
00400   
00401   /* NULL for no fallback font.  */
00402   kpse_init_prog (uppercasify (kpse_program_name), dpi, mode, NULL);
00403   
00404   /* Have to do this after setting the program name.  */
00405   if (user_format_string)
00406     user_format = find_format (user_format_string, false);
00407   
00408   /* Variable expansion.  */
00409   if (var_to_expand)
00410     puts (kpse_var_expand (var_to_expand));
00411 
00412   /* Brace expansion. */
00413   if (braces_to_expand)
00414     puts (kpse_brace_expand (braces_to_expand));
00415   
00416   /* Path expansion. */
00417   if (path_to_expand)
00418     puts (kpse_path_expand (path_to_expand));
00419 
00420   /* Show a search path. */
00421   if (path_to_show) {
00422     if (user_format != kpse_last_format) {
00423       if (!kpse_format_info[user_format].type) /* needed if arg was numeric */
00424         kpse_init_format (user_format);
00425       puts (kpse_format_info[user_format].path);
00426     } else {
00427       WARNING1 ("kpsewhich: Ignoring unknown file type `%s'", path_to_show);
00428     }
00429   }
00430 
00431   /* Var to value. */
00432   if (var_to_value) {
00433     string value = kpse_var_value (var_to_value);
00434     if (!value) {
00435       unfound++;
00436       value="";
00437     }
00438     puts (value);
00439   }
00440   
00441   for (; optind < argc; optind++) {
00442     unfound += lookup (argv[optind]);
00443   }
00444 
00445   if (interactive) {
00446     for (;;) {
00447       string name = read_line (stdin);
00448       if (!name || STREQ (name, "q") || STREQ (name, "quit")) break;
00449       unfound += lookup (name);
00450       free (name);
00451     }
00452   }
00453   
00454   return unfound > 255 ? 1 : unfound;
00455 }