1 /* tex-make.c: run external programs to make TeX-related files.
2
3 Copyright 1993, 1994, 1995, 1996, 1997, 2008-2013 Karl Berry.
4 Copyright 1997, 1998, 2001-05 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
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>
29
30 #if !defined (AMIGA) && !(defined (MSDOS) && !defined(__DJGPP__)) && !defined (WIN32)
31 #include <sys/wait.h>
32 #endif
33
34
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. */
37
38 static void
set_maketex_mag(kpathsea kpse)39 set_maketex_mag (kpathsea kpse)
40 {
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;
47
48 /* If the environment variables aren't set, it's a bug. */
49 assert (dpi != 0 && bdpi != 0);
50
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);
54
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;
61
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);
68 }
69 } else {
70 sprintf(q, "%u+%u/(4000+%u)", dpi/bdpi, dpi%bdpi, r);
71 }
72 }
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 = "-";
82 }
83 sprintf(q, "magstep\\(%s%d.%d\\)", sign, m / 2, (m & 1) * 5);
84 }
85 kpathsea_xputenv (kpse, "MAKETEX_MAG", q);
86 }
87
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. */
91
92 static void
misstex(kpathsea kpse,kpse_file_format_type format,string * args)93 misstex (kpathsea kpse, kpse_file_format_type format, string *args)
94 {
95 string *s;
96
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;
105
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 */
116
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);
123 }
124
125 if (kpse->missfont)
126 fprintf (stderr, "kpathsea: Appending font creation commands to %s.\n",
127 missfont_name);
128 }
129
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);
136 }
137 putc ('\n', kpse->missfont);
138 }
139 }
140
141
142 /* Assume the script outputs the filename it creates (and nothing
143 else) on standard output; hence, we run the script with `popen'. */
144
145 static string
maketex(kpathsea kpse,kpse_file_format_type format,string * args)146 maketex (kpathsea kpse, kpse_file_format_type format, string* args)
147 {
148 /* New implementation, use fork/exec pair instead of popen, since
149 * the latter is virtually impossible to make safe.
150 */
151 unsigned len;
152 string *s;
153 string ret = NULL;
154 string fn;
155 #if defined(WIN32)
156 char fullbin[256], *wrp;
157
158 wrp = kpathsea_var_value(kpse, "SELFAUTOLOC");
159 if(wrp == NULL) {
160 fprintf(stderr, "I cannot get SELFAUTOLOC\n");
161 exit(100);
162 }
163
164 strcpy(fullbin, wrp);
165 free(wrp);
166 for(wrp=fullbin; *wrp; wrp++) {
167 if(*wrp == '/') *wrp = '\\';
168 }
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);
177 }
178
179 #if defined (AMIGA)
180 /* Amiga has a different interface. */
181 {
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;
189 }
190 ret = system(cmd) == 0 ? getenv ("LAST_FONT_CREATED"): NULL;
191 free (cmd);
192 }
193 #elif defined (MSDOS) && !defined(__DJGPP__)
194 #error Implement new MSDOS mktex call interface here
195 #else /* WIN32 or Unix */
196 {
197 #if defined (WIN32)
198 /* spawnvp(_P_NOWAIT, ...) and pipe --ak 2002/12/15 */
199
200 unsigned long nexitcode = STILL_ACTIVE;
201 HANDLE hchild;
202 int hstdout, childpipe[2];
203 int hstderr = -1;
204 FILE *Hnul = NULL;
205
206 fn = NULL;
207
208 if(_pipe(childpipe, 1024, O_TEXT | _O_NOINHERIT) == -1) {
209 perror("kpathsea: pipe()");
210 goto labeldone;
211 }
212
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;
219 }
220
221 close(childpipe[1]);
222
223 if(kpse->make_tex_discard_errors) {
224 Hnul = fopen("nul", "w");
225 if(!Hnul) {
226 perror("kpathsea: fopen(\"nul\")");
227 }
228 else {
229 hstderr = _dup(fileno(stderr));
230 _dup2(fileno(Hnul), fileno(stderr));
231 }
232 }
233 fprintf(stderr, "\nThe command name is %s\n", fullbin);
234 hchild = (HANDLE)spawnvp(_P_NOWAIT, fullbin, (const char * const *) args);
235
236 _dup2(hstdout, fileno(stdout));
237 close(hstdout);
238
239 if((int)hchild == -1) {
240 close(childpipe[0]);
241 goto labeldone;
242 }
243
244 if(hchild) {
245 char buf[1024+1];
246 int num;
247
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;
257 }
258 if(!GetExitCodeProcess(hchild, &nexitcode)) {
259 fn = NULL;
260 close(childpipe[0]);
261 goto labeldone;
262 }
263 }
264 close(childpipe[0]);
265 }
266
267 labeldone:
268 if(kpse->make_tex_discard_errors && Hnul) {
269 _dup2(hstderr, fileno(stderr));
270 close(hstderr);
271 fclose(Hnul);
272 }
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;
282
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;
288 }
289 if (pipe(childout) < 0) {
290 perror("kpathsea: pipe()");
291 goto error_childout;
292 }
293 if ((childerr = open("/dev/null", O_WRONLY)) < 0) {
294 perror("kpathsea: open(\"/dev/null\", O_WRONLY)");
295 goto error_childerr;
296 }
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
309 *
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.
313 *
314 * Complete setting up the file descriptors.
315 * We use dup(2) so the order in which we do this matters.
316 */
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);
323 }
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]);
329 }
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);
335 }
336 close(childerr);
337 }
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;
347
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;
359 }
360 } else {
361 string newfn;
362 buf[num] = '\0';
363 newfn = concat(fn, buf);
364 free(fn);
365 fn = newfn;
366 }
367 }
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);
372 }
373 #endif /* !WIN32 */
374
375 if (fn) {
376 len = strlen(fn);
377
378 /* Remove trailing newlines and returns. */
379 while (len && (fn[len - 1] == '\n' || fn[len - 1] == '\r')) {
380 fn[len - 1] = '\0';
381 len--;
382 }
383
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);
388 }
389
390 /* Free the name if we're not returning it. */
391 if (fn != ret)
392 free (fn);
393 }
394 }
395 #endif /* WIN32 or Unix */
396
397 if (ret == NULL)
398 misstex (kpse, format, args);
399 else
400 kpathsea_db_insert (kpse, ret);
401
402 return ret;
403 }
404
405
406
407 /* Create BASE in FORMAT and return the generated filename, or
408 return NULL. */
409
410 string
kpathsea_make_tex(kpathsea kpse,kpse_file_format_type format,const_string base)411 kpathsea_make_tex (kpathsea kpse, kpse_file_format_type format,
412 const_string base)
413 {
414 kpse_format_info_type spec; /* some compilers lack struct initialization */
415 string ret = NULL;
416
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];
421 }
422
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;
430
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.
438 */
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;
443 }
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]))
451 {
452 fprintf(stderr, "kpathsea:make_tex: Invalid fontname `%s', contains '%c'\n",
453 base, base[i]);
454 return NULL;
455 }
456 }
457
458 if (format == kpse_gf_format
459 || format == kpse_pk_format
460 || format == kpse_any_glyph_format)
461 set_maketex_mag (kpse);
462
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]);
477 }
478 args[argnum++] = xstrdup(base);
479 args[argnum] = NULL;
480
481 ret = maketex (kpse, format, args);
482
483 for (argnum = 0; args[argnum] != NULL; argnum++)
484 free (args[argnum]);
485 free (args);
486 }
487
488 return ret;
489 }
490
491 #if defined (KPSE_COMPAT_API)
492 string
kpse_make_tex(kpse_file_format_type format,const_string base)493 kpse_make_tex (kpse_file_format_type format, const_string base)
494 {
495 return kpathsea_make_tex (kpse_def, format, base);
496 }
497 #endif
498
499
500 #ifdef TEST
501
502 void
test_make_tex(kpathsea kpse,kpse_file_format_type fmt,const_string base)503 test_make_tex (kpathsea kpse, kpse_file_format_type fmt, const_string base)
504 {
505 string answer;
506
507 printf ("\nAttempting %s in format %d:\n", base, fmt);
508
509 answer = kpathsea_make_tex (kpse, fmt, base);
510 puts (answer ? answer : "(nil)");
511 }
512
513
514 int
main(int argc,char ** argv)515 main (int argc, char **argv)
516 {
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");
523
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");
527
528 /* Call something disabled. */
529 test_make_tex (kpse, kpse_bst_format, "no-way");
530
531 return 0;
532 }
533
534 #endif /* TEST */
535
536
537 /*
538 Local variables:
539 standalone-compile-command: "gcc -g -I. -I.. -DTEST tex-make.c kpathsea.a"
540 End:
541 */
542