1 /* kpsewhich -- standalone path lookup and variable expansion for Kpathsea.
2 Ideas from Thomas Esser, Pierre MacKay, and many others.
4 Copyright 1995-2015 Karl Berry & 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>
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>
36 #define fputs win32_fputs
37 #define puts win32_puts
40 /* For variable and path expansion. (-expand-var, -expand-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
;
48 /* Base resolution. (-D, -dpi) */
51 /* The engine name, for '$engine' construct in texmf.cnf. (-engine) */
54 /* Interactively ask for names to look up? (-interactive) */
55 boolean interactive
= false;
57 /* The device name, for $MAKETEX_MODE. (-mode) */
60 /* Search the disk as well as ls-R? (-must-exist, -mktex) */
61 boolean must_exist
= false;
63 /* The program name, for `.PROG' construct in texmf.cnf. (-program) */
64 string progname
= NULL
;
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
;
70 /* Return all matches, not just the first one? (-all) */
71 boolean show_all
= false;
73 /* Only match files in given subdirs. (-subdir) */
74 str_list_type subdir_paths
;
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
;
83 /* Define one-word abbreviations for those format types which
84 can otherwise only be specified by strings containing spaces. */
89 kpse_file_format_type format
;
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
} };
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. */
111 static kpse_file_format_type
112 format_abbr (const_string str
)
114 kpse_file_format_type ret
= kpse_last_format
;
117 while (format_abbrs
[a
].abbr
!= NULL
) {
118 if (STREQ (str
, format_abbrs
[a
].abbr
)) {
119 ret
= format_abbrs
[a
].format
;
130 /* Return the <number> substring in `<name>.<number><stuff>', if S has
131 that form. If it doesn't, return 0. */
136 unsigned dpi_number
= 0;
137 const_string extension
= find_suffix (s
);
139 if (extension
!= NULL
)
140 sscanf (extension
, "%u", &dpi_number
);
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. */
153 try_suffix (boolean is_filename
, string name
, unsigned name_len
,
158 if (!ftry
|| ! *ftry
) {
162 try_len
= strlen (ftry
);
163 if (try_len
> name_len
) {
164 /* Candidate is longer than what we're looking for. */
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'. */
174 if (FILESTRCASEEQ (name
+ name_len
- try_len
, ftry
)) {
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.
189 A few filenames have been hard-coded for format types that
190 differ from what would be inferred from their extensions. */
192 static kpse_file_format_type
193 find_format (kpathsea kpse
, string name
, boolean is_filename
)
195 kpse_file_format_type ret
= kpse_last_format
;
197 if (is_filename
&& user_format
!= kpse_last_format
) {
198 ret
= user_format
; /* just return what we already computed */
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
;
222 /* Look for kpsewhich-specific format abbreviations. */
223 ret
= format_abbr (name
);
226 if (ret
== kpse_last_format
) {
227 int f
= 0; /* kpse_file_format_type */
228 unsigned name_len
= strlen (name
);
230 while (f
!= kpse_last_format
) {
233 boolean found
= false;
235 if (!kpse
->format_info
[f
].type
)
236 kpathsea_init_format (kpse
, (kpse_file_format_type
) f
);
238 /* Just to abbreviate this lengthy call. */
239 #define TRY_SUFFIX(ftry) try_suffix (is_filename, name, name_len, (ftry))
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
);
247 for (ext
= kpse
->format_info
[f
].suffix
; !found
&& ext
&& *ext
; ext
++) {
248 found
= TRY_SUFFIX (*ext
);
250 for (ext
=kpse
->format_info
[f
].alt_suffix
; !found
&& ext
&& *ext
;ext
++){
251 found
= TRY_SUFFIX (*ext
);
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.
272 We don't reallocate the actual strings, just the list elements.
273 Perhaps later we will implement wildcards or // or something. */
276 subdir_match (str_list_type subdirs
, string
*matches
)
278 string
*ret
= XTALLOC1 (string
);
285 for (e
= 0; e
< STR_LIST_LENGTH (subdirs
); e
++) {
286 for (p
= STR_LIST_ELT (subdirs
, e
); *p
; p
++) {
289 else if (IS_KANJI(p
))
295 for (m
= 0; matches
[m
]; m
++) {
297 string s
= xstrdup (matches
[m
]);
298 for (loc
= strlen (s
); loc
> 0 && !IS_DIR_SEP_CH (s
[loc
-1]); loc
--)
300 while (loc
> 0 && IS_DIR_SEP_CH (s
[loc
-1])) {
303 s
[loc
] = 0; /* wipe out basename */
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])) {
310 subdir
[subdir_len
] = 0; /* remove trailing slashes from subdir spec */
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
];
327 /* Look up a single filename NAME. Return 0 if success, 1 if failure. */
330 lookup (kpathsea kpse
, string name
)
334 string
*ret_list
= NULL
;
337 /* Translate ; to : if that's our ENV_SEP. See cnf.c. */
338 if (IS_ENV_SEP (':')) {
340 for (loc
= user_path
; *loc
; loc
++) {
345 user_path
= kpathsea_path_expand (kpse
, user_path
);
347 ret_list
= kpathsea_all_path_search (kpse
, user_path
, name
);
349 ret
= kpathsea_path_search (kpse
, user_path
, name
, must_exist
);
353 /* No user-specified search path, check user format or guess from NAME. */
354 kpse_file_format_type fmt
= find_format (kpse
, name
, true);
359 case kpse_any_glyph_format
:
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
);
367 ret
= kpathsea_find_glyph (kpse
, temp
,
368 local_dpi
, fmt
, &glyph_ret
);
374 case kpse_last_format
:
375 /* If the suffix isn't recognized, assume it's a tex file. */
376 fmt
= kpse_tex_format
;
381 ret_list
= kpathsea_find_file_generic (kpse
, name
, fmt
,
384 ret
= kpathsea_find_file (kpse
, name
, fmt
, must_exist
);
389 /* Turn single return into a null-terminated list for uniform treatment. */
391 ret_list
= XTALLOC (2, string
);
396 /* Filter by subdirectories, if specified. */
397 if (STR_LIST_LENGTH (subdir_paths
) > 0) {
398 string
*new_list
= subdir_match (subdir_paths
, ret_list
);
405 for (i
= 0; ret_list
[i
]; i
++)
407 /* Save whether we found anything */
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\
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\
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 (list shown by -help-formats).\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\n\
445 (list shown by -help-formats).\n\
446 -subdir=STRING only output matches whose directory ends with STRING.\n\
447 -var-value=STRING output the value of variable $STRING.\n\
448 -version display version information number and exit.\n \
452 help_message (kpathsea kpse
, string
*argv
)
454 printf ("Usage: %s [OPTION]... [FILENAME]...\n", argv
[0]);
455 fputs (USAGE
, stdout
);
457 fputs (kpathsea_bug_address
, stdout
);
458 fputs ("Kpathsea home page: http://tug.org/kpathsea/\n", stdout
);
463 help_formats (kpathsea kpse
, string
*argv
)
465 int f
; /* kpse_file_format_type */
467 /* Have to set this for init_format to work. */
468 kpathsea_set_program_name (kpse
, argv
[0], progname
);
470 puts (kpathsea_version_string
);
471 puts ("\nRecognized Kpathsea format names and their (abbreviations) and suffixes:");
472 for (f
= 0; f
< kpse_last_format
; f
++) {
475 const_string envvar_list
=
476 kpathsea_init_format_return_varlist (kpse
, (kpse_file_format_type
) f
);
477 printf ("%s", kpse
->format_info
[f
].type
);
479 /* Show abbreviation if we accept one. We repeatedly go through the
480 abbr list here, but it's so short, it doesn't matter. */
483 while (format_abbrs
[a
].abbr
!= NULL
) {
484 if (f
== format_abbrs
[a
].format
) {
485 printf (" (%s)", format_abbrs
[a
].abbr
);
492 /* Regular suffixes. */
494 for (ext
= kpse
->format_info
[f
].suffix
; ext
&& *ext
; ext
++) {
496 fputs (*ext
, stdout
);
499 if (kpse
->format_info
[f
].alt_suffix
) {
500 /* leave extra space between default and alt suffixes */
503 for (ext
= kpse
->format_info
[f
].alt_suffix
; ext
&& *ext
; ext
++) {
505 fputs (*ext
, stdout
);
508 printf (" [variables: %s]\n", envvar_list
);
510 printf (" [original path (from %s) = %s]\n",
511 kpse
->format_info
[f
].path_source
, kpse
->format_info
[f
].raw_path
);
514 fputs ("\nTo see paths after expansion, use --show-path=FMT.\n\n", stdout
);
515 fputs (kpathsea_bug_address
, stdout
);
520 /* Reading the options. */
522 /* This macro tests whether getopt found an option ``A''.
523 Assumes the option index is in the variable `option_index', and the
524 option table in a variable `long_options'. */
525 #define ARGUMENT_IS(a) STREQ (long_options[option_index].name, a)
527 /* SunOS cc can't initialize automatic structs. */
528 static struct option long_options
[]
529 = { { "D", 1, 0, 0 },
530 { "all", 0, (int *) &show_all
, 1 },
531 { "debug", 1, 0, 0 },
533 { "engine", 1, 0, 0 },
534 { "expand-braces", 1, 0, 0 },
535 { "expand-path", 1, 0, 0 },
536 { "expand-var", 1, 0, 0 },
537 { "format", 1, 0, 0 },
539 { "help-formats", 0, 0, 0 },
540 { "interactive", 0, (int *) &interactive
, 1 },
541 { "mktex", 1, 0, 0 },
543 { "must-exist", 0, (int *) &must_exist
, 1 },
545 { "no-mktex", 1, 0, 0 },
546 { "progname", 1, 0, 0 },
547 { "safe-in-name", 1, 0, 0 },
548 { "safe-out-name", 1, 0, 0 },
549 { "subdir", 1, 0, 0 },
550 { "show-path", 1, 0, 0 },
551 { "var-value", 1, 0, 0 },
552 { "version", 0, 0, 0 },
556 read_command_line (kpathsea kpse
, int argc
, string
*argv
)
558 int g
; /* `getopt' return code. */
562 g
= getopt_long_only (argc
, argv
, "", long_options
, &option_index
);
568 exit (1); /* Unknown option. */
570 assert (g
== 0); /* We have no short option names. */
572 if (ARGUMENT_IS ("debug")) {
573 kpse
->debug
|= atoi (optarg
);
575 } else if (ARGUMENT_IS ("dpi") || ARGUMENT_IS ("D")) {
578 } else if (ARGUMENT_IS ("engine")) {
581 } else if (ARGUMENT_IS ("expand-braces")) {
582 braces_to_expand
= optarg
;
584 } else if (ARGUMENT_IS ("expand-path")) {
585 path_to_expand
= optarg
;
587 } else if (ARGUMENT_IS ("expand-var")) {
588 var_to_expand
= optarg
;
590 } else if (ARGUMENT_IS ("format")) {
591 user_format_string
= optarg
;
593 } else if (ARGUMENT_IS ("help")) {
594 help_message (kpse
, argv
);
596 } else if (ARGUMENT_IS ("help-formats")) {
597 help_formats (kpse
, argv
);
599 } else if (ARGUMENT_IS ("mktex")) {
600 kpathsea_maketex_option (kpse
, optarg
, true);
601 must_exist
= 1; /* otherwise it never gets called */
603 } else if (ARGUMENT_IS ("mode")) {
606 } else if (ARGUMENT_IS ("no-mktex")) {
607 kpathsea_maketex_option (kpse
, optarg
, false);
610 } else if (ARGUMENT_IS ("path")) {
613 } else if (ARGUMENT_IS ("progname")) {
616 } else if (ARGUMENT_IS ("safe-in-name")) {
617 safe_in_name
= optarg
;
619 } else if (ARGUMENT_IS ("safe-out-name")) {
620 safe_out_name
= optarg
;
622 } else if (ARGUMENT_IS ("show-path")) {
623 path_to_show
= optarg
;
624 user_format_string
= optarg
;
626 } else if (ARGUMENT_IS ("subdir")) {
627 str_list_add (&subdir_paths
, optarg
);
629 } else if (ARGUMENT_IS ("var-value")) {
630 var_to_value
= optarg
;
632 } else if (ARGUMENT_IS ("version")) {
633 puts (kpathsea_version_string
);
634 puts ("Copyright 2015 Karl Berry & Olaf Weber.\n\
635 License LGPLv2.1+: GNU Lesser GPL version 2.1 or later <http://gnu.org/licenses/lgpl.html>\n\
636 This is free software: you are free to change and redistribute it.\n\
637 There is NO WARRANTY, to the extent permitted by law.\n");
641 /* Else it was just a flag; getopt has already done the assignment. */
644 if (user_path
&& user_format_string
) {
645 fprintf (stderr
, "-path (%s) and -format (%s) are mutually exclusive.\n",
646 user_path
, user_format_string
);
647 fputs ("Try `kpsewhich --help' for more information.\n", stderr
);
652 && !var_to_expand
&& !braces_to_expand
&& !path_to_expand
653 && !path_to_show
&& !var_to_value
654 && !safe_in_name
&& !safe_out_name
) {
655 fputs ("Missing argument. Try `kpsewhich --help' for more information.\n",
663 /* Initializations that may depend on the options. */
666 init_more (kpathsea kpse
)
669 kpathsea_xputenv (kpse
, "engine", engine
);
671 /* Disable all mktex programs unless they were explicitly enabled on our
673 #define DISABLE_MKTEX(fmt) \
674 kpathsea_set_program_enabled (kpse, fmt, false, kpse_src_cmdline - 1)
675 DISABLE_MKTEX (kpse_pk_format
);
676 DISABLE_MKTEX (kpse_mf_format
);
677 DISABLE_MKTEX (kpse_tex_format
);
678 DISABLE_MKTEX (kpse_tfm_format
);
679 DISABLE_MKTEX (kpse_fmt_format
);
680 DISABLE_MKTEX (kpse_ofm_format
);
681 DISABLE_MKTEX (kpse_ocp_format
);
683 /* NULL for no fallback font. */
684 kpathsea_init_prog (kpse
, uppercasify (kpse
->program_name
), dpi
, mode
, NULL
);
686 /* Have to do this after setting the program name. */
687 if (user_format_string
) {
688 user_format
= find_format (kpse
, user_format_string
, false);
689 if (user_format
== kpse_last_format
) {
690 WARNING1 ("kpsewhich: Ignoring unknown file type `%s'",
699 main (int argc
, string
*argv
)
705 unsigned unfound
= 0;
706 kpathsea kpse
= kpathsea_new();
708 /* Read options, then dependent initializations. */
709 read_command_line (kpse
, argc
, argv
);
711 kpathsea_set_program_name (kpse
, argv
[0], progname
);
713 if(strstr(kpse
->program_name
,"xetex") || strstr(kpse
->program_name
,"xelatex")
714 || strstr(kpse
->program_name
,"uptex") || strstr(kpse
->program_name
,"uplatex")
715 || strstr(kpse
->program_name
,"dvipdfm") || strstr(kpse
->program_name
,"extractbb")
716 || strstr(kpse
->program_name
,"xbb") || strstr(kpse
->program_name
,"ebb")
717 || strstr(kpse
->program_name
,"dvips") || strstr(kpse
->program_name
,"upmendex"))
719 if (strstr(kpse
->program_name
,"upmendex"))
722 enc
= kpathsea_var_value (kpse
, "command_line_encoding");
723 if (get_command_line_args_utf8(enc
, &ac
, &av
)) {
725 read_command_line (kpse
, ac
, av
);
734 /* Perform actions. */
736 /* Variable expansion. */
738 puts (kpathsea_var_expand (kpse
, var_to_expand
));
740 /* Brace expansion. */
741 if (braces_to_expand
)
742 puts (kpathsea_brace_expand (kpse
, braces_to_expand
));
744 /* Path expansion. */
746 puts (kpathsea_path_expand (kpse
, path_to_expand
));
748 /* Show a search path. */
750 if (user_format
!= kpse_last_format
) {
751 if (!kpse
->format_info
[user_format
].type
) /* needed if arg was numeric */
752 kpathsea_init_format (kpse
, user_format
);
753 puts (kpse
->format_info
[user_format
].path
);
755 WARNING ("kpsewhich: Cannot show path for unknown file type");
761 const_string value
= kpathsea_var_value (kpse
, var_to_value
);
770 if (!kpathsea_in_name_ok_silent (kpse
, safe_in_name
))
775 if (!kpathsea_out_name_ok_silent (kpse
, safe_out_name
))
779 /* --subdir must imply --all, since we filter here after doing the
780 search, rather than inside the search itself. */
781 if (STR_LIST_LENGTH (subdir_paths
) > 0) {
785 /* Usual case: look up each given filename. */
786 for (; optind
< argc
; optind
++) {
787 unfound
+= lookup (kpse
, argv
[optind
]);
792 string name
= read_line (stdin
);
793 if (!name
|| STREQ (name
, "q") || STREQ (name
, "quit"))
795 unfound
+= lookup (kpse
, name
);
800 kpathsea_finish (kpse
);
801 return unfound
> 255 ? 1 : unfound
;