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