1 /* tex-make.c: run external programs to make TeX-related files.
3 Copyright 1993, 1994, 1995, 1996, 1997, 2008-2013 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>
30 #if !defined (AMIGA) && !(defined (MSDOS) && !defined(__DJGPP__)) && !defined (WIN32)
35 /* We set the envvar MAKETEX_MAG, which is part of the default spec for
36 MakeTeXPK above, based on KPATHSEA_DPI and MAKETEX_BASE_DPI. */
39 set_maketex_mag (kpathsea kpse
)
41 char q
[MAX_INT_LENGTH
* 3 + 3];
43 string dpi_str
= getenv ("KPATHSEA_DPI");
44 string bdpi_str
= getenv ("MAKETEX_BASE_DPI");
45 unsigned dpi
= dpi_str
? atoi (dpi_str
) : 0;
46 unsigned bdpi
= bdpi_str
? atoi (bdpi_str
) : 0;
48 /* If the environment variables aren't set, it's a bug. */
49 assert (dpi
!= 0 && bdpi
!= 0);
51 /* Fix up for roundoff error. Hopefully the driver has already fixed
52 up DPI, but may as well be safe, and also get the magstep number. */
53 (void) kpathsea_magstep_fix (kpse
, dpi
, bdpi
, &m
);
57 sprintf(q
, "%u+%u/%u", dpi
/ bdpi
, dpi
% bdpi
, bdpi
);
59 unsigned f
= bdpi
/4000;
60 unsigned r
= bdpi
%4000;
64 sprintf(q
, "%u+%u/(%u*%u+%u)",
65 dpi
/bdpi
, dpi
%bdpi
, f
, (bdpi
- r
)/f
, r
);
67 sprintf(q
, "%u+%u/(%u*%u)", dpi
/bdpi
, dpi
%bdpi
, f
, bdpi
/f
);
70 sprintf(q
, "%u+%u/(4000+%u)", dpi
/bdpi
, dpi
%bdpi
, r
);
74 /* m is encoded with LSB being a ``half'' bit (see magstep.h). Are
75 we making an assumption here about two's complement? Probably.
76 In any case, if m is negative, we have to put in the sign
77 explicitly, since m/2==0 if m==-1. */
78 const_string sign
= "";
83 sprintf(q
, "magstep\\(%s%d.%d\\)", sign
, m
/ 2, (m
& 1) * 5);
85 kpathsea_xputenv (kpse
, "MAKETEX_MAG", q
);
88 /* This mktex... program was disabled, or the script failed. If this
89 was a font creation (according to FORMAT), append CMD
90 to a file missfont.log in the current directory. */
93 misstex (kpathsea kpse
, kpse_file_format_type format
, string
*args
)
97 /* If we weren't trying to make a font, do nothing. Maybe should
98 allow people to specify what they want recorded? */
99 if (format
!= kpse_gf_format
100 && format
!= kpse_pk_format
101 && format
!= kpse_any_glyph_format
102 && format
!= kpse_tfm_format
103 && format
!= kpse_vf_format
)
106 /* If this is the first time, have to open the log file. But don't
107 bother logging anything if they were discarding errors. */
108 if (!kpse
->missfont
&& !kpse
->make_tex_discard_errors
) {
109 const_string missfont_name
= kpathsea_var_value (kpse
, "MISSFONT_LOG");
110 if (!missfont_name
|| *missfont_name
== '1') {
111 missfont_name
= "missfont.log"; /* take default name */
112 } else if (missfont_name
113 && (*missfont_name
== 0 || *missfont_name
== '0')) {
114 missfont_name
= NULL
; /* user requested no missfont.log */
115 } /* else use user's name */
118 = missfont_name
? fopen (missfont_name
, FOPEN_A_MODE
) : NULL
;
119 if (!kpse
->missfont
&& kpathsea_var_value (kpse
, "TEXMFOUTPUT")) {
120 missfont_name
= concat3 (kpathsea_var_value (kpse
, "TEXMFOUTPUT"),
121 DIR_SEP_STRING
, missfont_name
);
122 kpse
->missfont
= fopen (missfont_name
, FOPEN_A_MODE
);
126 fprintf (stderr
, "kpathsea: Appending font creation commands to %s.\n",
130 /* Write the command if we have a log file. */
131 if (kpse
->missfont
) {
132 fputs (args
[0], kpse
->missfont
);
133 for (s
= &args
[1]; *s
!= NULL
; s
++) {
134 putc(' ', kpse
->missfont
);
135 fputs (*s
, kpse
->missfont
);
137 putc ('\n', kpse
->missfont
);
142 /* Assume the script outputs the filename it creates (and nothing
143 else) on standard output; hence, we run the script with `popen'. */
146 maketex (kpathsea kpse
, kpse_file_format_type format
, string
* args
)
148 /* New implementation, use fork/exec pair instead of popen, since
149 * the latter is virtually impossible to make safe.
156 char fullbin
[256], *wrp
;
158 wrp
= kpathsea_var_value(kpse
, "SELFAUTOLOC");
160 fprintf(stderr
, "I cannot get SELFAUTOLOC\n");
164 strcpy(fullbin
, wrp
);
166 for(wrp
=fullbin
; *wrp
; wrp
++) {
167 if(*wrp
== '/') *wrp
= '\\';
169 strcat(fullbin
, "\\");
170 strcat(fullbin
, args
[0]);
172 if (!kpse
->make_tex_discard_errors
) {
173 fprintf (stderr
, "\nkpathsea: Running");
174 for (s
= &args
[0]; *s
!= NULL
; s
++)
175 fprintf (stderr
, " %s", *s
);
180 /* Amiga has a different interface. */
184 cmd
= xstrdup(args
[0]);
185 for (s
= &args
[1]; *s
!= NULL
; s
++) {
186 newcmd
= concat(cmd
, *s
);
190 ret
= system(cmd
) == 0 ? getenv ("LAST_FONT_CREATED"): NULL
;
193 #elif defined (MSDOS) && !defined(__DJGPP__)
194 #error Implement new MSDOS mktex call interface here
195 #else /* WIN32 or Unix */
198 /* spawnvp(_P_NOWAIT, ...) and pipe --ak 2002/12/15 */
200 unsigned long nexitcode
= STILL_ACTIVE
;
202 int hstdout
, childpipe
[2];
208 if(_pipe(childpipe
, 1024, O_TEXT
| _O_NOINHERIT
) == -1) {
209 perror("kpathsea: pipe()");
213 hstdout
= _dup(fileno(stdout
));
214 if(_dup2(childpipe
[1], fileno(stdout
)) != 0) {
223 if(kpse
->make_tex_discard_errors
) {
224 Hnul
= fopen("nul", "w");
226 perror("kpathsea: fopen(\"nul\")");
229 hstderr
= _dup(fileno(stderr
));
230 _dup2(fileno(Hnul
), fileno(stderr
));
233 fprintf(stderr
, "\nThe command name is %s\n", fullbin
);
234 hchild
= (HANDLE
)_spawnvp(_P_NOWAIT
, fullbin
, (const char * const *) args
);
236 _dup2(hstdout
, fileno(stdout
));
239 if(hchild
== (HANDLE
)(-1)) {
249 while(nexitcode
== STILL_ACTIVE
) {
250 num
= read(childpipe
[0], buf
, sizeof(buf
)-1);
254 newfn
= concat(fn
, buf
);
258 if(!GetExitCodeProcess(hchild
, &nexitcode
)) {
268 if(kpse
->make_tex_discard_errors
&& Hnul
) {
269 _dup2(hstderr
, fileno(stderr
));
274 /* Standard input for the child. Set to /dev/null */
276 /* Standard output for the child, what we're interested in. */
278 /* Standard error for the child, same as parent or /dev/null */
283 /* Open the channels that the child will use. */
284 /* A fairly horrible uses of gotos for here for the error case. */
285 if ((childin
= open("/dev/null", O_RDONLY
)) < 0) {
286 perror("kpathsea: open(\"/dev/null\", O_RDONLY)");
289 if (pipe(childout
) < 0) {
290 perror("kpathsea: pipe()");
293 if ((childerr
= open("/dev/null", O_WRONLY
)) < 0) {
294 perror("kpathsea: open(\"/dev/null\", O_WRONLY)");
297 if ((childpid
= fork()) < 0) {
298 perror("kpathsea: fork()");
307 } else if (childpid
== 0) {
310 * We can use vfork, provided we're careful about what we
311 * do here: do not return from this function, do not modify
312 * variables, call _exit if there is a problem.
314 * Complete setting up the file descriptors.
315 * We use dup(2) so the order in which we do this matters.
318 /* stdin -- the child will not receive input from this */
324 /* stdout -- the output of the child's action */
325 if (childout
[1] != 1) {
330 /* stderr -- use /dev/null if we discard errors */
332 if (kpse
->make_tex_discard_errors
) {
338 /* FIXME: We could/should close all other file descriptors as well. */
339 /* exec -- on failure a call of _exit(2) it is the only option */
340 if (execvp(args
[0], args
))
348 /* Clean up child file descriptors that we won't use anyway. */
352 /* Get stdout of child from the pipe. */
354 while ((num
= read(childout
[0],buf
,sizeof(buf
)-1)) != 0) {
356 if (errno
!= EINTR
) {
357 perror("kpathsea: read()");
363 newfn
= concat(fn
, buf
);
368 /* End of file on pipe, child should have exited at this point. */
370 /* We don't really care about the exit status at this point. */
378 /* Remove trailing newlines and returns. */
379 while (len
&& (fn
[len
- 1] == '\n' || fn
[len
- 1] == '\r')) {
384 ret
= len
== 0 ? NULL
: kpathsea_readable_file (kpse
, fn
);
385 if (!ret
&& len
> 1) {
386 WARNING2 ("kpathsea: %s output `%s' instead of a filename",
390 /* Free the name if we're not returning it. */
395 #endif /* WIN32 or Unix */
398 misstex (kpse
, format
, args
);
400 kpathsea_db_insert (kpse
, ret
);
407 /* Create BASE in FORMAT and return the generated filename, or
411 kpathsea_make_tex (kpathsea kpse
, kpse_file_format_type format
,
414 kpse_format_info_type spec
; /* some compilers lack struct initialization */
417 spec
= kpse
->format_info
[format
];
418 if (!spec
.type
) { /* Not initialized yet? */
419 kpathsea_init_format (kpse
, format
);
420 spec
= kpse
->format_info
[format
];
423 if (spec
.program
&& spec
.program_enabled_p
) {
424 /* See the documentation for the envvars we're dealing with here. */
425 /* Number of arguments is spec.argc + 1, plus the trailing NULL. */
426 string
*args
= XTALLOC (spec
.argc
+ 2, string
);
432 * Check whether the name we were given is likely to be a problem.
433 * Right now we err on the side of strictness:
434 * - may not start with a hyphen (fixable in the scripts).
435 * - allowed are: alphanumeric, underscore, hyphen, period, plus
436 * ? also allowed DIRSEP, as we can be fed that when creating pk fonts
437 * No doubt some possibilities were overlooked.
439 if (base
[0] == '-' /* || IS_DIR_SEP(base[0]) */) {
440 fprintf(stderr
, "kpathsea:make_tex: Invalid fontname `%s', starts with '%c'\n",
444 for (i
= 0; base
[i
]; i
++) {
445 if (!ISALNUM(base
[i
])
450 && !IS_DIR_SEP(base
[i
]))
452 fprintf(stderr
, "kpathsea:make_tex: Invalid fontname `%s', contains '%c'\n",
458 if (format
== kpse_gf_format
459 || format
== kpse_pk_format
460 || format
== kpse_any_glyph_format
)
461 set_maketex_mag (kpse
);
463 /* Here's an awful kludge: if the mode is `/', mktexpk recognizes
464 it as a special case. `kpse_prog_init' sets it to this in the
465 first place when no mode is otherwise specified; this is so
466 when the user defines a resolution, they don't also have to
467 specify a mode; instead, mktexpk's guesses will take over.
468 They use / for the value because then when it is expanded as
469 part of the PKFONTS et al. path values, we'll wind up searching
470 all the pk directories. We put $MAKETEX_MODE in the path
471 values in the first place so that sites with two different
472 devices with the same resolution can find the right fonts; but
473 such sites are uncommon, so they shouldn't make things harder
474 for everyone else. */
475 for (argnum
= 0; argnum
< spec
.argc
; argnum
++) {
476 args
[argnum
] = kpathsea_var_expand (kpse
, spec
.argv
[argnum
]);
478 args
[argnum
++] = xstrdup(base
);
481 ret
= maketex (kpse
, format
, args
);
483 for (argnum
= 0; args
[argnum
] != NULL
; argnum
++)
491 #if defined (KPSE_COMPAT_API)
493 kpse_make_tex (kpse_file_format_type format
, const_string base
)
495 return kpathsea_make_tex (kpse_def
, format
, base
);
503 test_make_tex (kpathsea kpse
, kpse_file_format_type fmt
, const_string base
)
507 printf ("\nAttempting %s in format %d:\n", base
, fmt
);
509 answer
= kpathsea_make_tex (kpse
, fmt
, base
);
510 puts (answer
? answer
: "(nil)");
515 main (int argc
, char **argv
)
517 kpathsea kpse
= xcalloc(1, sizeof(kpathsea_instance
));
518 kpathsea_set_program_name(kpse
, argv
[0], NULL
);
519 kpathsea_xputenv (kpse
, "KPATHSEA_DPI", "781"); /* call mktexpk */
520 kpathsea_xputenv (kpse
,"MAKETEX_BASE_DPI", "300"); /* call mktexpk */
521 kpathsea_set_program_enabled(kpse
, kpse_pk_format
, 1, kpse_src_env
);
522 test_make_tex (kpse
, kpse_pk_format
, "cmr10");
524 /* Fail with mktextfm. */
525 kpathsea_set_program_enabled(kpse
, kpse_tfm_format
, 1, kpse_src_env
);
526 test_make_tex (kpse
, kpse_tfm_format
, "foozler99");
528 /* Call something disabled. */
529 test_make_tex (kpse
, kpse_bst_format
, "no-way");
539 standalone-compile-command: "gcc -g -I. -I.. -DTEST tex-make.c kpathsea.a"