beta-0.89.2
[luatex.git] / source / texk / kpathsea / tex-make.c
blob6671b5474ba294aae0cc7ecca2c8d4bd70825b6f
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)
31 #include <sys/wait.h>
32 #endif
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. */
38 static void
39 set_maketex_mag (kpathsea kpse)
41 char q[MAX_INT_LENGTH * 3 + 3];
42 int m;
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);
55 if (m == 0) {
56 if (bdpi <= 4000) {
57 sprintf(q, "%u+%u/%u", dpi / bdpi, dpi % bdpi, bdpi);
58 } else {
59 unsigned f = bdpi/4000;
60 unsigned r = bdpi%4000;
62 if (f > 1) {
63 if (r > 0) {
64 sprintf(q, "%u+%u/(%u*%u+%u)",
65 dpi/bdpi, dpi%bdpi, f, (bdpi - r)/f, r);
66 } else {
67 sprintf(q, "%u+%u/(%u*%u)", dpi/bdpi, dpi%bdpi, f, bdpi/f);
69 } else {
70 sprintf(q, "%u+%u/(4000+%u)", dpi/bdpi, dpi%bdpi, r);
73 } else {
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 = "";
79 if (m < 0) {
80 m *= -1;
81 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. */
92 static void
93 misstex (kpathsea kpse, kpse_file_format_type format, string *args)
95 string *s;
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)
104 return;
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 */
117 kpse->missfont
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);
125 if (kpse->missfont)
126 fprintf (stderr, "kpathsea: Appending font creation commands to %s.\n",
127 missfont_name);
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'. */
145 static string
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.
151 unsigned len;
152 string *s;
153 string ret = NULL;
154 string fn;
155 #if defined(WIN32)
156 char fullbin[256], *wrp;
158 wrp = kpathsea_var_value(kpse, "SELFAUTOLOC");
159 if(wrp == NULL) {
160 fprintf(stderr, "I cannot get SELFAUTOLOC\n");
161 exit(100);
164 strcpy(fullbin, wrp);
165 free(wrp);
166 for(wrp=fullbin; *wrp; wrp++) {
167 if(*wrp == '/') *wrp = '\\';
169 strcat(fullbin, "\\");
170 strcat(fullbin, args[0]);
171 #endif
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);
176 fputc('\n', stderr);
179 #if defined (AMIGA)
180 /* Amiga has a different interface. */
182 string cmd;
183 string newcmd;
184 cmd = xstrdup(args[0]);
185 for (s = &args[1]; *s != NULL; s++) {
186 newcmd = concat(cmd, *s);
187 free (cmd);
188 cmd = newcmd;
190 ret = system(cmd) == 0 ? getenv ("LAST_FONT_CREATED"): NULL;
191 free (cmd);
193 #elif defined (MSDOS) && !defined(__DJGPP__)
194 #error Implement new MSDOS mktex call interface here
195 #else /* WIN32 or Unix */
197 #if defined (WIN32)
198 /* spawnvp(_P_NOWAIT, ...) and pipe --ak 2002/12/15 */
200 unsigned long nexitcode = STILL_ACTIVE;
201 HANDLE hchild;
202 int hstdout, childpipe[2];
203 int hstderr = -1;
204 FILE *Hnul = NULL;
206 fn = NULL;
208 if(_pipe(childpipe, 1024, O_TEXT | _O_NOINHERIT) == -1) {
209 perror("kpathsea: pipe()");
210 goto labeldone;
213 hstdout = _dup(fileno(stdout));
214 if(_dup2(childpipe[1], fileno(stdout)) != 0) {
215 close(hstdout);
216 close(childpipe[0]);
217 close(childpipe[1]);
218 goto labeldone;
221 close(childpipe[1]);
223 if(kpse->make_tex_discard_errors) {
224 Hnul = fopen("nul", "w");
225 if(!Hnul) {
226 perror("kpathsea: fopen(\"nul\")");
228 else {
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));
237 close(hstdout);
239 if(hchild == (HANDLE)(-1)) {
240 close(childpipe[0]);
241 goto labeldone;
244 if(hchild) {
245 char buf[1024+1];
246 int num;
248 fn = xstrdup("");
249 while(nexitcode == STILL_ACTIVE) {
250 num = read(childpipe[0], buf, sizeof(buf)-1);
251 if(num) {
252 string newfn;
253 buf[num] = '\0';
254 newfn = concat(fn, buf);
255 free(fn);
256 fn = newfn;
258 if(!GetExitCodeProcess(hchild, &nexitcode)) {
259 fn = NULL;
260 close(childpipe[0]);
261 goto labeldone;
264 close(childpipe[0]);
267 labeldone:
268 if(kpse->make_tex_discard_errors && Hnul) {
269 _dup2(hstderr, fileno(stderr));
270 close(hstderr);
271 fclose(Hnul);
273 #else /* !WIN32 */
274 /* Standard input for the child. Set to /dev/null */
275 int childin;
276 /* Standard output for the child, what we're interested in. */
277 int childout[2];
278 /* Standard error for the child, same as parent or /dev/null */
279 int childerr;
280 /* Child pid. */
281 pid_t childpid;
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)");
287 goto error_childin;
289 if (pipe(childout) < 0) {
290 perror("kpathsea: pipe()");
291 goto error_childout;
293 if ((childerr = open("/dev/null", O_WRONLY)) < 0) {
294 perror("kpathsea: open(\"/dev/null\", O_WRONLY)");
295 goto error_childerr;
297 if ((childpid = fork()) < 0) {
298 perror("kpathsea: fork()");
299 close(childerr);
300 error_childerr:
301 close(childout[0]);
302 close(childout[1]);
303 error_childout:
304 close(childin);
305 error_childin:
306 fn = NULL;
307 } else if (childpid == 0) {
308 /* Child
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.
317 close(childout[0]);
318 /* stdin -- the child will not receive input from this */
319 if (childin != 0) {
320 close(0);
321 dup(childin);
322 close(childin);
324 /* stdout -- the output of the child's action */
325 if (childout[1] != 1) {
326 close(1);
327 dup(childout[1]);
328 close(childout[1]);
330 /* stderr -- use /dev/null if we discard errors */
331 if (childerr != 2) {
332 if (kpse->make_tex_discard_errors) {
333 close(2);
334 dup(childerr);
336 close(childerr);
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))
341 perror(args[0]);
342 _exit(1);
343 } else {
344 /* Parent */
345 char buf[1024+1];
346 int num;
348 /* Clean up child file descriptors that we won't use anyway. */
349 close(childin);
350 close(childout[1]);
351 close(childerr);
352 /* Get stdout of child from the pipe. */
353 fn = xstrdup("");
354 while ((num = read(childout[0],buf,sizeof(buf)-1)) != 0) {
355 if (num == -1) {
356 if (errno != EINTR) {
357 perror("kpathsea: read()");
358 break;
360 } else {
361 string newfn;
362 buf[num] = '\0';
363 newfn = concat(fn, buf);
364 free(fn);
365 fn = newfn;
368 /* End of file on pipe, child should have exited at this point. */
369 close(childout[0]);
370 /* We don't really care about the exit status at this point. */
371 wait(NULL);
373 #endif /* !WIN32 */
375 if (fn) {
376 len = strlen(fn);
378 /* Remove trailing newlines and returns. */
379 while (len && (fn[len - 1] == '\n' || fn[len - 1] == '\r')) {
380 fn[len - 1] = '\0';
381 len--;
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",
387 args[0], fn);
390 /* Free the name if we're not returning it. */
391 if (fn != ret)
392 free (fn);
395 #endif /* WIN32 or Unix */
397 if (ret == NULL)
398 misstex (kpse, format, args);
399 else
400 kpathsea_db_insert (kpse, ret);
402 return ret;
407 /* Create BASE in FORMAT and return the generated filename, or
408 return NULL. */
410 string
411 kpathsea_make_tex (kpathsea kpse, kpse_file_format_type format,
412 const_string base)
414 kpse_format_info_type spec; /* some compilers lack struct initialization */
415 string ret = NULL;
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);
427 /* Helpers */
428 int argnum;
429 int i;
431 /* FIXME
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",
441 base, base[0]);
442 return NULL;
444 for (i = 0; base[i]; i++) {
445 if (!ISALNUM(base[i])
446 && base[i] != '-'
447 && base[i] != '+'
448 && base[i] != '_'
449 && base[i] != '.'
450 && !IS_DIR_SEP(base[i]))
452 fprintf(stderr, "kpathsea:make_tex: Invalid fontname `%s', contains '%c'\n",
453 base, base[i]);
454 return NULL;
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);
479 args[argnum] = NULL;
481 ret = maketex (kpse, format, args);
483 for (argnum = 0; args[argnum] != NULL; argnum++)
484 free (args[argnum]);
485 free (args);
488 return ret;
491 #if defined (KPSE_COMPAT_API)
492 string
493 kpse_make_tex (kpse_file_format_type format, const_string base)
495 return kpathsea_make_tex (kpse_def, format, base);
497 #endif
500 #ifdef TEST
502 void
503 test_make_tex (kpathsea kpse, kpse_file_format_type fmt, const_string base)
505 string answer;
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");
531 return 0;
534 #endif /* TEST */
538 Local variables:
539 standalone-compile-command: "gcc -g -I. -I.. -DTEST tex-make.c kpathsea.a"
540 End: