1 /* tex-make.c: run external programs to make TeX-related files.
3 Copyright 1993, 1994, 1995, 1996, 1997, 2008 Karl Berry.
4 Copyright 1997, 1998, 2001-05 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>
21 #include <kpathsea/c-fopen.h>
22 #include <kpathsea/c-pathch.h>
23 #include <kpathsea/db.h>
24 #include <kpathsea/fn.h>
25 #include <kpathsea/magstep.h>
26 #include <kpathsea/readable.h>
27 #include <kpathsea/tex-make.h>
28 #include <kpathsea/variable.h>
31 /* We never throw away stdout, since that is supposed to be the filename
32 found, if all is successful. This variable controls whether stderr
34 boolean kpse_make_tex_discard_errors = false;
36 /* We set the envvar MAKETEX_MAG, which is part of the default spec for
37 MakeTeXPK above, based on KPATHSEA_DPI and MAKETEX_BASE_DPI. */
40 set_maketex_mag P1H(void)
42 char q[MAX_INT_LENGTH * 3 + 3];
44 string dpi_str = getenv ("KPATHSEA_DPI");
45 string bdpi_str = getenv ("MAKETEX_BASE_DPI");
46 unsigned dpi = dpi_str ? atoi (dpi_str) : 0;
47 unsigned bdpi = bdpi_str ? atoi (bdpi_str) : 0;
49 /* If the environment variables aren't set, it's a bug. */
50 assert (dpi != 0 && bdpi != 0);
52 /* Fix up for roundoff error. Hopefully the driver has already fixed
53 up DPI, but may as well be safe, and also get the magstep number. */
54 (void) kpse_magstep_fix (dpi, bdpi, &m);
58 sprintf(q, "%u+%u/%u", dpi / bdpi, dpi % bdpi, bdpi);
60 unsigned f = bdpi/4000;
61 unsigned r = bdpi%4000;
65 sprintf(q, "%u+%u/(%u*%u+%u)",
66 dpi/bdpi, dpi%bdpi, f, (bdpi - r)/f, r);
68 sprintf(q, "%u+%u/(%u*%u)", dpi/bdpi, dpi%bdpi, f, bdpi/f);
71 sprintf(q, "%u+%u/(4000+%u)", dpi/bdpi, dpi%bdpi, r);
75 /* m is encoded with LSB being a ``half'' bit (see magstep.h). Are
76 we making an assumption here about two's complement? Probably.
77 In any case, if m is negative, we have to put in the sign
78 explicitly, since m/2==0 if m==-1. */
79 const_string sign = "";
84 sprintf(q, "magstep\\(%s%d.%d\\)", sign, m / 2, (m & 1) * 5);
86 xputenv ("MAKETEX_MAG", q);
89 /* This mktex... program was disabled, or the script failed. If this
90 was a font creation (according to FORMAT), append CMD
91 to a file missfont.log in the current directory. */
94 misstex P2C(kpse_file_format_type, format, string *, args)
96 static FILE *missfont = NULL;
99 /* If we weren't trying to make a font, do nothing. Maybe should
100 allow people to specify what they want recorded? */
101 if (format != kpse_gf_format
102 && format != kpse_pk_format
103 && format != kpse_any_glyph_format
104 && format != kpse_tfm_format
105 && format != kpse_vf_format)
108 /* If this is the first time, have to open the log file. But don't
109 bother logging anything if they were discarding errors. */
110 if (!missfont && !kpse_make_tex_discard_errors) {
111 const_string missfont_name = kpse_var_value ("MISSFONT_LOG");
112 if (!missfont_name || *missfont_name == '1') {
113 missfont_name = "missfont.log"; /* take default name */
114 } else if (missfont_name
115 && (*missfont_name == 0 || *missfont_name == '0')) {
116 missfont_name = NULL; /* user requested no missfont.log */
117 } /* else use user's name */
119 missfont = missfont_name ? fopen (missfont_name, FOPEN_A_MODE) : NULL;
120 if (!missfont && kpse_var_value ("TEXMFOUTPUT")) {
121 missfont_name = concat3 (kpse_var_value ("TEXMFOUTPUT"), DIR_SEP_STRING,
123 missfont = fopen (missfont_name, FOPEN_A_MODE);
127 fprintf (stderr, "kpathsea: Appending font creation commands to %s.\n",
131 /* Write the command if we have a log file. */
133 fputs (args[0], missfont);
134 for (s = &args[1]; *s != NULL; s++) {
136 fputs (*s, missfont);
138 putc ('\n', missfont);
143 /* Assume the script outputs the filename it creates (and nothing
144 else) on standard output; hence, we run the script with `popen'. */
147 maketex P2C(kpse_file_format_type, format, string*, args)
149 /* New implementation, use fork/exec pair instead of popen, since
150 * the latter is virtually impossible to make safe.
157 if (!kpse_make_tex_discard_errors) {
158 fprintf (stderr, "\nkpathsea: Running");
159 for (s = &args[0]; *s != NULL; s++)
160 fprintf (stderr, " %s", *s);
165 /* Amiga has a different interface. */
169 cmd = xstrdup(args[0]);
170 for (s = &args[1]; *s != NULL; s++) {
171 newcmd = concat(cmd, *s);
175 ret = system(cmd) == 0 ? getenv ("LAST_FONT_CREATED"): NULL;
178 #elif defined (MSDOS) && !defined(DJGPP)
179 #error Implement new MSDOS mktex call interface here
180 #elif defined (WIN32)
181 /* We would vastly prefer to link directly with mktex.c here.
182 Unfortunately, it is not quite possible because kpathsea
183 is not reentrant. The progname is expected to be set in mktex.c
184 and various initialisations occur. So to be safe, we implement
185 a call sequence equivalent to the Unix one. */
188 PROCESS_INFORMATION pi;
190 HANDLE child_in, child_out, child_err;
191 HANDLE father_in, father_out_dup;
193 SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
194 string new_cmd = NULL, app_name = NULL;
198 extern char *quote_args(char **argv);
200 if (look_for_cmd(args[0], &app_name) == FALSE) {
205 /* Compute the command line */
206 new_cmd = quote_args(args);
208 /* We need this handle to duplicate other handles */
209 current_pid = GetCurrentProcess();
211 ZeroMemory( &si, sizeof(STARTUPINFO) );
212 si.cb = sizeof(STARTUPINFO);
213 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW ;
214 si.wShowWindow = /* 0 */ SW_HIDE ;
217 child_in = CreateFile("nul",
219 FILE_SHARE_READ | FILE_SHARE_WRITE,
220 &sa, /* non inheritable */
222 FILE_ATTRIBUTE_NORMAL,
224 si.hStdInput = child_in;
226 if (CreatePipe(&father_in, &child_out, NULL, 0) == FALSE) {
227 fprintf(stderr, "popen: error CreatePipe\n");
230 if (DuplicateHandle(current_pid, child_out,
231 current_pid, &father_out_dup,
232 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) {
233 fprintf(stderr, "popen: error DuplicateHandle father_in\n");
234 CloseHandle(father_in);
235 CloseHandle(child_out);
238 CloseHandle(child_out);
239 si.hStdOutput = father_out_dup;
242 if (kpse_make_tex_discard_errors) {
243 child_err = CreateFile("nul",
245 FILE_SHARE_READ | FILE_SHARE_WRITE,
246 &sa, /* non inheritable */
248 FILE_ATTRIBUTE_NORMAL,
252 DuplicateHandle(current_pid, GetStdHandle(STD_ERROR_HANDLE),
253 current_pid, &child_err,
255 DUPLICATE_SAME_ACCESS);
257 si.hStdError = child_err;
259 /* creating child process */
260 if (CreateProcess(app_name, /* pointer to name of executable module */
261 new_cmd, /* pointer to command line string */
262 NULL, /* pointer to process security attributes */
263 NULL, /* pointer to thread security attributes */
264 TRUE, /* handle inheritance flag */
265 0, /* creation flags */
266 NULL, /* pointer to environment */
267 NULL, /* pointer to current directory */
268 &si, /* pointer to STARTUPINFO */
269 &pi /* pointer to PROCESS_INFORMATION */
271 FATAL2("kpathsea: CreateProcess() failed for `%s' (Error %x)\n", new_cmd, GetLastError());
274 CloseHandle(child_in);
275 CloseHandle(father_out_dup);
276 CloseHandle(child_err);
278 /* Only the process handle is needed */
279 CloseHandle(pi.hThread);
281 /* Get stdout of child from the pipe. */
283 while (ReadFile(father_in,buf,sizeof(buf)-1, &num, NULL) != 0
286 if (GetLastError() != ERROR_BROKEN_PIPE) {
287 FATAL2("kpathsea: read() error code for `%s' (Error %d)", new_cmd, GetLastError());
293 newfn = concat(fn, buf);
298 /* End of file on pipe, child should have exited at this point. */
299 CloseHandle(father_in);
301 if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_OBJECT_0) {
302 WARNING2("kpathsea: failed to wait for process termination: %s (Error %d)\n",
303 new_cmd, GetLastError());
306 CloseHandle(pi.hProcess);
308 if (new_cmd) free(new_cmd);
309 if (app_name) free(app_name);
314 /* Remove trailing newlines and returns. */
315 while (len && (fn[len - 1] == '\n' || fn[len - 1] == '\r')) {
320 ret = len == 0 ? NULL : kpse_readable_file (fn);
321 if (!ret && len > 1) {
322 WARNING2 ("kpathsea: %s output `%s' instead of a filename",
326 /* Free the name if we're not returning it. */
335 /* Standard input for the child. Set to /dev/null */
337 /* Standard output for the child, what we're interested in. */
339 /* Standard error for the child, same as parent or /dev/null */
344 /* Open the channels that the child will use. */
345 /* A fairly horrible uses of gotos for here for the error case. */
346 if ((childin = open("/dev/null", O_RDONLY)) < 0) {
347 perror("kpathsea: open(\"/dev/null\", O_RDONLY)");
350 if (pipe(childout) < 0) {
351 perror("kpathsea: pipe()");
354 if ((childerr = open("/dev/null", O_WRONLY)) < 0) {
355 perror("kpathsea: open(\"/dev/null\", O_WRONLY)");
358 if ((childpid = fork()) < 0) {
359 perror("kpathsea: fork()");
368 } else if (childpid == 0) {
371 * We can use vfork, provided we're careful about what we
372 * do here: do not return from this function, do not modify
373 * variables, call _exit if there is a problem.
375 * Complete setting up the file descriptors.
376 * We use dup(2) so the order in which we do this matters.
379 /* stdin -- the child will not receive input from this */
385 /* stdout -- the output of the child's action */
386 if (childout[1] != 1) {
391 /* stderr -- use /dev/null if we discard errors */
393 if (kpse_make_tex_discard_errors) {
399 /* FIXME: We could/should close all other file descriptors as well. */
400 /* exec -- on failure a call of _exit(2) it is the only option */
401 if (execvp(args[0], args))
409 /* Clean up child file descriptors that we won't use anyway. */
413 /* Get stdout of child from the pipe. */
415 while ((num = read(childout[0],buf,sizeof(buf)-1)) != 0) {
417 if (errno != EINTR) {
418 perror("kpathsea: read()");
424 newfn = concat(fn, buf);
429 /* End of file on pipe, child should have exited at this point. */
431 /* We don't really care about the exit status at this point. */
438 /* Remove trailing newlines and returns. */
439 while (len && (fn[len - 1] == '\n' || fn[len - 1] == '\r')) {
444 ret = len == 0 ? NULL : kpse_readable_file (fn);
445 if (!ret && len > 1) {
446 WARNING2("kpathsea: %s output `%s' instead of a filename",
450 /* Free the name if we're not returning it. */
460 misstex (format, args);
462 kpse_db_insert (ret);
468 /* Create BASE in FORMAT and return the generated filename, or
472 kpse_make_tex P2C(kpse_file_format_type, format, const_string, base)
474 kpse_format_info_type spec; /* some compilers lack struct initialization */
477 spec = kpse_format_info[format];
478 if (!spec.type) { /* Not initialized yet? */
479 kpse_init_format (format);
480 spec = kpse_format_info[format];
483 if (spec.program && spec.program_enabled_p) {
484 /* See the documentation for the envvars we're dealing with here. */
485 /* Number of arguments is spec.argc + 1, plus the trailing NULL. */
486 string *args = XTALLOC (spec.argc + 2, string);
492 * Check whether the name we were given is likely to be a problem.
493 * Right now we err on the side of strictness:
494 * - may not start with a hyphen (fixable in the scripts).
495 * - allowed are: alphanumeric, underscore, hyphen, period, plus
496 * ? also allowed DIRSEP, as we can be fed that when creating pk fonts
497 * No doubt some possibilities were overlooked.
499 if (base[0] == '-' /* || IS_DIR_SEP(base[0]) */) {
500 fprintf(stderr, "kpathsea: Invalid fontname `%s', starts with '%c'\n",
504 for (i = 0; base[i]; i++) {
505 if (!ISALNUM(base[i])
510 && !IS_DIR_SEP(base[i]))
512 fprintf(stderr, "kpathsea: Invalid fontname `%s', contains '%c'\n",
518 if (format == kpse_gf_format
519 || format == kpse_pk_format
520 || format == kpse_any_glyph_format)
523 /* Here's an awful kludge: if the mode is `/', mktexpk recognizes
524 it as a special case. `kpse_prog_init' sets it to this in the
525 first place when no mode is otherwise specified; this is so
526 when the user defines a resolution, they don't also have to
527 specify a mode; instead, mktexpk's guesses will take over.
528 They use / for the value because then when it is expanded as
529 part of the PKFONTS et al. path values, we'll wind up searching
530 all the pk directories. We put $MAKETEX_MODE in the path
531 values in the first place so that sites with two different
532 devices with the same resolution can find the right fonts; but
533 such sites are uncommon, so they shouldn't make things harder
534 for everyone else. */
535 for (argnum = 0; argnum < spec.argc; argnum++) {
536 args[argnum] = kpse_var_expand (spec.argv[argnum]);
538 args[argnum++] = xstrdup(base);
541 ret = maketex (format, args);
543 for (argnum = 0; args[argnum] != NULL; argnum++)
554 test_make_tex (kpse_file_format_type fmt, const_string base)
558 printf ("\nAttempting %s in format %d:\n", base, fmt);
560 answer = kpse_make_tex (fmt, base);
561 puts (answer ? answer : "(nil)");
568 xputenv ("KPATHSEA_DPI", "781"); /* call mktexpk */
569 xputenv ("MAKETEX_BASE_DPI", "300"); /* call mktexpk */
570 KPSE_MAKE_SPEC_ENABLED (kpse_make_specs[kpse_pk_format]) = true;
571 test_make_tex (kpse_pk_format, "cmr10");
573 /* Fail with mktextfm. */
574 KPSE_MAKE_SPEC_ENABLED (kpse_make_specs[kpse_tfm_format]) = true;
575 test_make_tex (kpse_tfm_format, "foozler99");
577 /* Call something disabled. */
578 test_make_tex (kpse_bst_format, "no-way");
588 test-compile-command: "gcc -g -I. -I.. -DTEST tex-make.c kpathsea.a"