1 /* kpsewhich -- standalone path lookup and variable expansion for Kpathsea.
2    Ideas from Thomas Esser, Pierre MacKay, and many others.
3 
4    Copyright 1995-2015 Karl Berry & 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-ctype.h>
21 #include <kpathsea/c-pathch.h>
22 #include <kpathsea/expand.h>
23 #include <kpathsea/getopt.h>
24 #include <kpathsea/line.h>
25 #include <kpathsea/pathsearch.h>
26 #include <kpathsea/proginit.h>
27 #include <kpathsea/str-list.h>
28 #include <kpathsea/tex-file.h>
29 #include <kpathsea/tex-glyph.h>
30 #include <kpathsea/variable.h>
31 #include <kpathsea/version.h>
32 
33 #ifdef WIN32
34 #undef fputs
35 #undef puts
36 #define fputs win32_fputs
37 #define puts  win32_puts
38 #endif
39 
40 /* For variable and path expansion.  (-expand-var, -expand-path,
41    -show-path) */
42 string var_to_expand = NULL;
43 string braces_to_expand = NULL;
44 string path_to_expand = NULL;
45 string path_to_show = NULL;
46 string var_to_value = NULL;
47 
48 /* Base resolution. (-D, -dpi) */
49 unsigned dpi = 600;
50 
51 /* The engine name, for '$engine' construct in texmf.cnf.  (-engine) */
52 string engine = NULL;
53 
54 /* Interactively ask for names to look up?  (-interactive) */
55 boolean interactive = false;
56 
57 /* The device name, for $MAKETEX_MODE.  (-mode) */
58 string mode = NULL;
59 
60 /* Search the disk as well as ls-R?  (-must-exist, -mktex) */
61 boolean must_exist = false;
62 
63 /* The program name, for `.PROG' construct in texmf.cnf.  (-program) */
64 string progname = NULL;
65 
66 /* Safe input and output names to check.  (-safe-in-name and -safe-out-name) */
67 string safe_in_name = NULL;
68 string safe_out_name = NULL;
69 
70 /* Return all matches, not just the first one?  (-all) */
71 boolean show_all = false;
72 
73 /* Only match files in given subdirs.  (-subdir) */
74 str_list_type subdir_paths;
75 
76 /* The file type and path for lookups.  (-format, -path) */
77 kpse_file_format_type user_format = kpse_last_format;
78 string user_format_string;
79 string user_path;
80 
81 
82 
83 /* Define one-word abbreviations for those format types which
84    can otherwise only be specified by strings containing spaces.  */
85 
86 typedef struct
87 {
88   const_string abbr;
89   kpse_file_format_type format;
90 } format_abbr_type;
91 
92 static format_abbr_type format_abbrs[]
93   = { { "bitmapfont", kpse_any_glyph_format },
94       { "mpsupport", kpse_mpsupport_format },
95       { "doc", kpse_texdoc_format },
96       { "source", kpse_texsource_format },
97       { "trofffont", kpse_troff_font_format },
98       { "dvipsconfig", kpse_dvips_config_format },
99       { "web2c", kpse_web2c_format },
100       { "othertext", kpse_program_text_format },
101       { "otherbin", kpse_program_binary_format },
102       { "miscfont", kpse_miscfonts_format },
103       { "cmap", kpse_cmap_format },
104       { "pdftexconfig", kpse_pdftex_config_format },
105       { NULL, kpse_last_format } };
106 
107 /* The function to look up STR in the abbr table above.
108    This is called only on a user-specified format string.
109    Return `kpse_last_format' if no match.  */
110 
111 static kpse_file_format_type
format_abbr(const_string str)112 format_abbr (const_string str)
113 {
114   kpse_file_format_type ret = kpse_last_format;
115   unsigned a = 0;
116 
117   while (format_abbrs[a].abbr != NULL) {
118     if (STREQ (str, format_abbrs[a].abbr)) {
119       ret = format_abbrs[a].format;
120       break;
121     }
122     a++;
123   }
124 
125   return ret;
126 }
127 
128 
129 
130 /* Return the <number> substring in `<name>.<number><stuff>', if S has
131    that form.  If it doesn't, return 0.  */
132 
133 static unsigned
find_dpi(string s)134 find_dpi (string s)
135 {
136   unsigned dpi_number = 0;
137   const_string extension = find_suffix (s);
138 
139   if (extension != NULL)
140     sscanf (extension, "%u", &dpi_number);
141 
142   return dpi_number;
143 }
144 
145 
146 
147 /* Return true if FTRY (the candidate suffix) matches NAME.  If
148    IS_FILENAME is true, the check is simply that FTRY is a suffix of
149    NAME.  If false (that is, NAME is a format), then FTRY and NAME must
150    be entirely equal.  */
151 
152 static boolean
try_suffix(boolean is_filename,string name,unsigned name_len,const_string ftry)153 try_suffix (boolean is_filename, string name, unsigned name_len,
154             const_string ftry)
155 {
156   unsigned try_len;
157 
158   if (!ftry || ! *ftry) {
159     return false;
160   }
161 
162   try_len = strlen (ftry);
163   if (try_len > name_len) {
164     /* Candidate is longer than what we're looking for.  */
165     return false;
166   }
167   if (!is_filename && try_len < name_len) {
168     /* We're doing format names, not file names, and candidate is
169        shorter than what we're looking for.  E.g., do not find `lua'
170        when looking for `clua'.  */
171     return false;
172   }
173 
174   if (FILESTRCASEEQ (name + name_len - try_len, ftry)) {
175     return true;
176   }
177 
178   return false;
179 }
180 
181 
182 
183 /* Use the file type from -format if that was previously determined
184    (i.e., the user_format global variable), else guess dynamically from
185    NAME.  Return kpse_last_format if undeterminable.  This function is
186    also used to parse the -format string, a case we distinguish via
187    is_filename being false.
188 
189    A few filenames have been hard-coded for format types that
190    differ from what would be inferred from their extensions. */
191 
192 static kpse_file_format_type
find_format(kpathsea kpse,string name,boolean is_filename)193 find_format (kpathsea kpse, string name, boolean is_filename)
194 {
195   kpse_file_format_type ret = kpse_last_format;
196 
197   if (is_filename && user_format != kpse_last_format) {
198     ret = user_format; /* just return what we already computed */
199 
200   } else if (FILESTRCASEEQ (name, "config.ps")) {
201     ret = kpse_dvips_config_format;
202   } else if (FILESTRCASEEQ (name, "fmtutil.cnf")) {
203     ret = kpse_web2c_format;
204   } else if (FILESTRCASEEQ (name, "glyphlist.txt")) {
205     ret = kpse_fontmap_format;
206   } else if (FILESTRCASEEQ (name, "mktex.cnf")) {
207     ret = kpse_web2c_format;
208   } else if (FILESTRCASEEQ (name, "pdfglyphlist.txt")) {
209     ret = kpse_fontmap_format;
210   } else if (FILESTRCASEEQ (name, "pdftex.cfg")) {
211     ret = kpse_pdftex_config_format;
212   } else if (FILESTRCASEEQ (name, "texglyphlist.txt")) {
213     ret = kpse_fontmap_format;
214   } else if (FILESTRCASEEQ (name, "texmf.cnf")) {
215     ret = kpse_cnf_format;
216   } else if (FILESTRCASEEQ (name, "updmap.cfg")) {
217     ret = kpse_web2c_format;
218   } else if (FILESTRCASEEQ (name, "XDvi")) {
219     ret = kpse_program_text_format;
220   } else {
221     if (!is_filename) {
222       /* Look for kpsewhich-specific format abbreviations.  */
223       ret = format_abbr (name);
224     }
225 
226     if (ret == kpse_last_format) {
227       int f = 0;  /* kpse_file_format_type */
228       unsigned name_len = strlen (name);
229 
230       while (f != kpse_last_format) {
231         const_string *ext;
232         const_string ftry;
233         boolean found = false;
234 
235         if (!kpse->format_info[f].type)
236           kpathsea_init_format (kpse, (kpse_file_format_type) f);
237 
238 /* Just to abbreviate this lengthy call.  */
239 #define TRY_SUFFIX(ftry) try_suffix (is_filename, name, name_len, (ftry))
240 
241         if (!is_filename) {
242           /* Allow the long name, but only in the format options.  We don't
243              want a filename confused with a format name.  */
244           ftry = kpse->format_info[f].type;
245           found = TRY_SUFFIX (ftry);
246         }
247         for (ext = kpse->format_info[f].suffix; !found && ext && *ext; ext++) {
248           found = TRY_SUFFIX (*ext);
249         }
250         for (ext=kpse->format_info[f].alt_suffix; !found && ext && *ext;ext++){
251           found = TRY_SUFFIX (*ext);
252         }
253 
254         if (found)
255           break;
256         f++;
257       }
258       ret = f;
259     }
260   }
261   return ret;
262 }
263 
264 
265 
266 /* Return newly-allocated NULL-terminated list of strings from MATCHES
267    that are prefixed with any of the subdirectories in SUBDIRS.  That
268    is, for a string S in MATCHES, its dirname must end with one of the
269    elements in SUBDIRS.  For instance, if subdir=foo/bar, that will
270    match a string foo/bar/baz or /some/texmf/foo/bar/baz.
271 
272    We don't reallocate the actual strings, just the list elements.
273    Perhaps later we will implement wildcards or // or something.  */
274 
275 static string *
subdir_match(str_list_type subdirs,string * matches)276 subdir_match (str_list_type subdirs,  string *matches)
277 {
278   string *ret = XTALLOC1 (string);
279   unsigned len = 1;
280   unsigned e;
281   unsigned m;
282 #if defined(WIN32)
283   string p;
284 
285   for (e = 0; e < STR_LIST_LENGTH (subdirs); e++) {
286     for (p = STR_LIST_ELT (subdirs, e); *p; p++) {
287       if (*p == '\\')
288         *p = '/';
289       else if (IS_KANJI(p))
290         p++;
291     }
292   }
293 #endif
294 
295   for (m = 0; matches[m]; m++) {
296     unsigned loc;
297     string s = xstrdup (matches[m]);
298     for (loc = strlen (s); loc > 0 && !IS_DIR_SEP_CH (s[loc-1]); loc--)
299       ;
300     while (loc > 0 && IS_DIR_SEP_CH (s[loc-1])) {
301       loc--;
302     }
303     s[loc] = 0;  /* wipe out basename */
304 
305     for (e = 0; e < STR_LIST_LENGTH (subdirs); e++) {
306       string subdir = STR_LIST_ELT (subdirs, e);
307       unsigned subdir_len = strlen (subdir);
308       while (subdir_len > 0 && IS_DIR_SEP_CH (subdir[subdir_len-1])) {
309         subdir_len--;
310         subdir[subdir_len] = 0; /* remove trailing slashes from subdir spec */
311       }
312       if (FILESTRCASEEQ (subdir, s + loc - subdir_len)) {
313         /* matched, save this one.  */
314         XRETALLOC (ret, len + 1, string);
315         ret[len-1] = matches[m];
316         len++;
317       }
318     }
319     free (s);
320   }
321   ret[len-1] = NULL;
322   return ret;
323 }
324 
325 
326 
327 /* Look up a single filename NAME.  Return 0 if success, 1 if failure.  */
328 
329 static unsigned
lookup(kpathsea kpse,string name)330 lookup (kpathsea kpse, string name)
331 {
332   int i;
333   string ret = NULL;
334   string *ret_list = NULL;
335 
336   if (user_path) {
337     /* Translate ; to : if that's our ENV_SEP.  See cnf.c.  */
338     if (IS_ENV_SEP (':')) {
339       string loc;
340       for (loc = user_path; *loc; loc++) {
341         if (*loc == ';')
342           *loc = ':';
343       }
344     }
345     user_path = kpathsea_path_expand (kpse, user_path);
346     if (show_all) {
347       ret_list = kpathsea_all_path_search (kpse, user_path, name);
348     } else {
349       ret = kpathsea_path_search (kpse, user_path, name, must_exist);
350     }
351 
352   } else {
353     /* No user-specified search path, check user format or guess from NAME.  */
354     kpse_file_format_type fmt = find_format (kpse, name, true);
355 
356     switch (fmt) {
357       case kpse_pk_format:
358       case kpse_gf_format:
359       case kpse_any_glyph_format:
360         {
361           kpse_glyph_file_type glyph_ret;
362           string temp = remove_suffix (name);
363           /* Try to extract the resolution from the name.  */
364           unsigned local_dpi = find_dpi (name);
365           if (!local_dpi)
366             local_dpi = dpi;
367           ret = kpathsea_find_glyph (kpse, temp,
368                                      local_dpi, fmt, &glyph_ret);
369           if (temp != name)
370             free (temp);
371         }
372         break;
373 
374       case kpse_last_format:
375         /* If the suffix isn't recognized, assume it's a tex file. */
376         fmt = kpse_tex_format;
377         /* fall through */
378 
379       default:
380         if (show_all) {
381           ret_list = kpathsea_find_file_generic (kpse, name, fmt,
382                                                  must_exist, true);
383         } else {
384           ret = kpathsea_find_file (kpse, name, fmt, must_exist);
385         }
386     }
387   }
388 
389   /* Turn single return into a null-terminated list for uniform treatment.  */
390   if (ret) {
391     ret_list = XTALLOC (2, string);
392     ret_list[0] = ret;
393     ret_list[1] = NULL;
394   }
395 
396   /* Filter by subdirectories, if specified.  */
397   if (STR_LIST_LENGTH (subdir_paths) > 0) {
398     string *new_list = subdir_match (subdir_paths, ret_list);
399     free (ret_list);
400     ret_list = new_list;
401   }
402 
403   /* Print output.  */
404   if (ret_list) {
405     for (i = 0; ret_list[i]; i++)
406       puts (ret_list[i]);
407     /* Save whether we found anything */
408     ret = ret_list[0];
409     free (ret_list);
410   }
411 
412   return ret == NULL;
413 }
414 
415 /* Help message.  */
416 
417 #define USAGE "\n\
418 Standalone path lookup and expansion for the Kpathsea library.\n\
419 The default is to look up each FILENAME in turn and report its\n\
420 first match (if any) to standard output.\n\
421 \n\
422 When looking up format (.fmt/.base/.mem) files, it is usually necessary\n\
423 to also use -engine, or nothing will be returned; in particular,\n\
424 -engine=/ will return matching format files for any engine.\n\
425 \n\
426 -all                   output all matches, one per line.\n\
427 -debug=NUM             set debugging flags.\n\
428 -D, -dpi=NUM           use a base resolution of NUM; default 600.\n\
429 -engine=STRING         set engine name to STRING.\n\
430 -expand-braces=STRING  output variable and brace expansion of STRING.\n\
431 -expand-path=STRING    output complete path expansion of STRING.\n\
432 -expand-var=STRING     output variable expansion of STRING.\n\
433 -format=NAME           use file type NAME (see list below).\n\
434 -help                  display this message and exit.\n\
435 -help-formats          display information about all supported file formats.\n\
436 -interactive           ask for additional filenames to look up.\n\
437 [-no]-mktex=FMT        disable/enable mktexFMT generation (FMT=pk/mf/tex/tfm).\n\
438 -mode=STRING           set device name for $MAKETEX_MODE to STRING; no default.\n\
439 -must-exist            search the disk as well as ls-R if necessary.\n\
440 -path=STRING           search in the path STRING.\n\
441 -progname=STRING       set program name to STRING.\n\
442 -safe-in-name=STRING   check if STRING is ok to open for input.\n\
443 -safe-out-name=STRING  check if STRING is ok to open for output.\n\
444 -show-path=NAME        output search path for file type NAME (list below).\n\
445 -subdir=STRING         only output matches whose directory ends with STRING.\n\
446 -var-value=STRING      output the value of variable $STRING.\n\
447 -version               display version information number and exit.\n \
448 "
449 
450 static void
help_message(kpathsea kpse,string * argv)451 help_message (kpathsea kpse, string *argv)
452 {
453   printf ("Usage: %s [OPTION]... [FILENAME]...\n", argv[0]);
454   fputs (USAGE, stdout);
455   putchar ('\n');
456   fputs (kpathsea_bug_address, stdout);
457   fputs ("Kpathsea home page: http://tug.org/kpathsea/\n", stdout);
458   exit (0);
459 }
460 
461 static void
help_formats(kpathsea kpse,string * argv)462 help_formats (kpathsea kpse, string *argv)
463 {
464   int f; /* kpse_file_format_type */
465 
466   /* Have to set this for init_format to work.  */
467   kpathsea_set_program_name (kpse, argv[0], progname);
468 
469   puts (kpathsea_version_string);
470   puts ("\nRecognized Kpathsea format names and their (abbreviations) and suffixes:");
471   for (f = 0; f < kpse_last_format; f++) {
472     const_string *ext;
473 
474     const_string envvar_list =
475       kpathsea_init_format_return_varlist (kpse, (kpse_file_format_type) f);
476     printf ("%s", kpse->format_info[f].type);
477 
478     /* Show abbreviation if we accept one.  We repeatedly go through the
479        abbr list here, but it's so short, it doesn't matter.  */
480     {
481        unsigned a = 0;
482        while (format_abbrs[a].abbr != NULL) {
483          if (f == format_abbrs[a].format) {
484            printf (" (%s)", format_abbrs[a].abbr);
485            break;
486          }
487          a++;
488        }
489     }
490 
491     /* Regular suffixes.  */
492     putchar (':');
493     for (ext = kpse->format_info[f].suffix; ext && *ext; ext++) {
494       putchar (' ');
495       fputs (*ext, stdout);
496     }
497 
498     if (kpse->format_info[f].alt_suffix) {
499       /* leave extra space between default and alt suffixes */
500       putchar (' ');
501     }
502     for (ext = kpse->format_info[f].alt_suffix; ext && *ext; ext++) {
503       putchar (' ');
504       fputs (*ext, stdout);
505     }
506 
507     printf ("  [variables: %s]\n", envvar_list);
508 
509     printf ("  [original path (from %s) = %s]\n",
510             kpse->format_info[f].path_source, kpse->format_info[f].raw_path);
511   }
512 
513   fputs ("\nTo see paths after expansion, use --show-path=FMT.\n\n", stdout);
514   fputs (kpathsea_bug_address, stdout);
515   exit (0);
516 }
517 
518 
519 /* Reading the options.  */
520 
521 /* This macro tests whether getopt found an option ``A''.
522    Assumes the option index is in the variable `option_index', and the
523    option table in a variable `long_options'.  */
524 #define ARGUMENT_IS(a) STREQ (long_options[option_index].name, a)
525 
526 /* SunOS cc can't initialize automatic structs.  */
527 static struct option long_options[]
528   = { { "D",                    1, 0, 0 },
529       { "all",                  0, (int *) &show_all, 1 },
530       { "debug",                1, 0, 0 },
531       { "dpi",                  1, 0, 0 },
532       { "engine",               1, 0, 0 },
533       { "expand-braces",        1, 0, 0 },
534       { "expand-path",          1, 0, 0 },
535       { "expand-var",           1, 0, 0 },
536       { "format",               1, 0, 0 },
537       { "help",                 0, 0, 0 },
538       { "help-formats",         0, 0, 0 },
539       { "interactive",          0, (int *) &interactive, 1 },
540       { "mktex",                1, 0, 0 },
541       { "mode",                 1, 0, 0 },
542       { "must-exist",           0, (int *) &must_exist, 1 },
543       { "path",                 1, 0, 0 },
544       { "no-mktex",             1, 0, 0 },
545       { "progname",             1, 0, 0 },
546       { "safe-in-name",         1, 0, 0 },
547       { "safe-out-name",        1, 0, 0 },
548       { "subdir",               1, 0, 0 },
549       { "show-path",            1, 0, 0 },
550       { "var-value",            1, 0, 0 },
551       { "version",              0, 0, 0 },
552       { 0, 0, 0, 0 } };
553 
554 static void
read_command_line(kpathsea kpse,int argc,string * argv)555 read_command_line (kpathsea kpse, int argc, string *argv)
556 {
557   int g;   /* `getopt' return code.  */
558   int option_index;
559 
560   for (;;) {
561     g = getopt_long_only (argc, argv, "", long_options, &option_index);
562 
563     if (g == -1)
564       break;
565 
566     if (g == '?')
567       exit (1);  /* Unknown option.  */
568 
569     assert (g == 0); /* We have no short option names.  */
570 
571     if (ARGUMENT_IS ("debug")) {
572       kpse->debug |= atoi (optarg);
573 
574     } else if (ARGUMENT_IS ("dpi") || ARGUMENT_IS ("D")) {
575       dpi = atoi (optarg);
576 
577     } else if (ARGUMENT_IS ("engine")) {
578       engine = optarg;
579 
580     } else if (ARGUMENT_IS ("expand-braces")) {
581       braces_to_expand = optarg;
582 
583     } else if (ARGUMENT_IS ("expand-path")) {
584       path_to_expand = optarg;
585 
586     } else if (ARGUMENT_IS ("expand-var")) {
587       var_to_expand = optarg;
588 
589     } else if (ARGUMENT_IS ("format")) {
590       user_format_string = optarg;
591 
592     } else if (ARGUMENT_IS ("help")) {
593       help_message (kpse, argv);
594 
595     } else if (ARGUMENT_IS ("help-formats")) {
596       help_formats (kpse, argv);
597 
598     } else if (ARGUMENT_IS ("mktex")) {
599       kpathsea_maketex_option (kpse, optarg, true);
600       must_exist = 1;  /* otherwise it never gets called */
601 
602     } else if (ARGUMENT_IS ("mode")) {
603       mode = optarg;
604 
605     } else if (ARGUMENT_IS ("no-mktex")) {
606       kpathsea_maketex_option (kpse, optarg, false);
607       must_exist = 0;
608 
609     } else if (ARGUMENT_IS ("path")) {
610       user_path = optarg;
611 
612     } else if (ARGUMENT_IS ("progname")) {
613       progname = optarg;
614 
615     } else if (ARGUMENT_IS ("safe-in-name")) {
616       safe_in_name = optarg;
617 
618     } else if (ARGUMENT_IS ("safe-out-name")) {
619       safe_out_name = optarg;
620 
621     } else if (ARGUMENT_IS ("show-path")) {
622       path_to_show = optarg;
623       user_format_string = optarg;
624 
625     } else if (ARGUMENT_IS ("subdir")) {
626       str_list_add (&subdir_paths, optarg);
627 
628     } else if (ARGUMENT_IS ("var-value")) {
629       var_to_value = optarg;
630 
631     } else if (ARGUMENT_IS ("version")) {
632       puts (kpathsea_version_string);
633       puts ("Copyright 2015 Karl Berry & Olaf Weber.\n\
634 License LGPLv2.1+: GNU Lesser GPL version 2.1 or later <http://gnu.org/licenses/lgpl.html>\n\
635 This is free software: you are free to change and redistribute it.\n\
636 There is NO WARRANTY, to the extent permitted by law.\n");
637       exit (0);
638     }
639 
640     /* Else it was just a flag; getopt has already done the assignment.  */
641   }
642 
643   if (user_path && user_format_string) {
644     fprintf (stderr, "-path (%s) and -format (%s) are mutually exclusive.\n",
645              user_path, user_format_string);
646     fputs ("Try `kpsewhich --help' for more information.\n", stderr);
647     exit (1);
648   }
649 
650   if (optind == argc
651       && !var_to_expand && !braces_to_expand && !path_to_expand
652       && !path_to_show && !var_to_value
653       && !safe_in_name && !safe_out_name) {
654     fputs ("Missing argument. Try `kpsewhich --help' for more information.\n",
655            stderr);
656     exit (1);
657   }
658 }
659 
660 
661 
662 /* Initializations that may depend on the options.  */
663 
664 static void
init_more(kpathsea kpse)665 init_more (kpathsea kpse)
666 {
667   if (engine)
668     kpathsea_xputenv (kpse, "engine", engine);
669 
670   /* Disable all mktex programs unless they were explicitly enabled on our
671      command line.  */
672 #define DISABLE_MKTEX(fmt) \
673 kpathsea_set_program_enabled (kpse, fmt, false, kpse_src_cmdline - 1)
674   DISABLE_MKTEX (kpse_pk_format);
675   DISABLE_MKTEX (kpse_mf_format);
676   DISABLE_MKTEX (kpse_tex_format);
677   DISABLE_MKTEX (kpse_tfm_format);
678   DISABLE_MKTEX (kpse_fmt_format);
679   DISABLE_MKTEX (kpse_ofm_format);
680   DISABLE_MKTEX (kpse_ocp_format);
681 
682   /* NULL for no fallback font.  */
683   kpathsea_init_prog (kpse, uppercasify (kpse->program_name), dpi, mode, NULL);
684 
685   /* Have to do this after setting the program name.  */
686   if (user_format_string) {
687     user_format = find_format (kpse, user_format_string, false);
688     if (user_format == kpse_last_format) {
689       WARNING1 ("kpsewhich: Ignoring unknown file type `%s'",
690                 user_format_string);
691     }
692   }
693 }
694 
695 
696 
697 int
main(int argc,string * argv)698 main (int argc,  string *argv)
699 {
700 #ifdef WIN32
701   string *av, enc;
702   int ac;
703 #endif
704   unsigned unfound = 0;
705   kpathsea kpse = kpathsea_new();
706 
707   /* Read options, then dependent initializations.  */
708   read_command_line (kpse, argc, argv);
709 
710   kpathsea_set_program_name (kpse, argv[0], progname);
711 #ifdef WIN32
712   if(strstr(kpse->program_name,"xetex") || strstr(kpse->program_name,"xelatex")
713      || strstr(kpse->program_name,"uptex") || strstr(kpse->program_name,"uplatex")
714      || strstr(kpse->program_name,"dvipdfm") || strstr(kpse->program_name,"extractbb")
715      || strstr(kpse->program_name,"xbb") || strstr(kpse->program_name,"ebb")
716      || strstr(kpse->program_name,"dvips"))
717   {
718     enc = kpathsea_var_value (kpse, "command_line_encoding");
719     if (get_command_line_args_utf8(enc, &ac, &av)) {
720       optind = 0;
721       read_command_line (kpse, ac, av);
722       argv = av;
723       argc = ac;
724     }
725   }
726 #endif
727   init_more (kpse);
728 
729 
730   /* Perform actions.  */
731 
732   /* Variable expansion.  */
733   if (var_to_expand)
734     puts (kpathsea_var_expand (kpse, var_to_expand));
735 
736   /* Brace expansion. */
737   if (braces_to_expand)
738     puts (kpathsea_brace_expand (kpse, braces_to_expand));
739 
740   /* Path expansion. */
741   if (path_to_expand)
742     puts (kpathsea_path_expand (kpse, path_to_expand));
743 
744   /* Show a search path. */
745   if (path_to_show) {
746     if (user_format != kpse_last_format) {
747       if (!kpse->format_info[user_format].type) /* needed if arg was numeric */
748         kpathsea_init_format (kpse, user_format);
749       puts (kpse->format_info[user_format].path);
750     } else {
751       WARNING ("kpsewhich: Cannot show path for unknown file type");
752     }
753   }
754 
755   /* Var to value. */
756   if (var_to_value) {
757     const_string value = kpathsea_var_value (kpse, var_to_value);
758     if (!value) {
759       unfound++;
760       value = "";
761     }
762     puts (value);
763   }
764 
765   if (safe_in_name) {
766     if (!kpathsea_in_name_ok_silent (kpse, safe_in_name))
767       unfound++;
768   }
769 
770   if (safe_out_name) {
771     if (!kpathsea_out_name_ok_silent (kpse, safe_out_name))
772       unfound++;
773   }
774 
775   /* --subdir must imply --all, since we filter here after doing the
776      search, rather than inside the search itself.  */
777   if (STR_LIST_LENGTH (subdir_paths) > 0) {
778     show_all = 1;
779   }
780 
781   /* Usual case: look up each given filename.  */
782   for (; optind < argc; optind++) {
783     unfound += lookup (kpse, argv[optind]);
784   }
785 
786   if (interactive) {
787     for (;;) {
788       string name = read_line (stdin);
789       if (!name || STREQ (name, "q") || STREQ (name, "quit"))
790         break;
791       unfound += lookup (kpse, name);
792       free (name);
793     }
794   }
795 
796   kpathsea_finish (kpse);
797   return unfound > 255 ? 1 : unfound;
798 }
799