dvitomp fix from Akira
[mplib] / src / texk / kpathsea / tex-make.c
1 /* tex-make.c: run external programs to make TeX-related files.
2
3    Copyright 1993, 1994, 1995, 1996, 1997, 2008 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
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
33    is thrown away.  */
34 boolean kpse_make_tex_discard_errors = false;
35 \f
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.  */
38
39 static void
40 set_maketex_mag P1H(void)
41 {
42   char q[MAX_INT_LENGTH * 3 + 3];
43   int m;
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;
48
49   /* If the environment variables aren't set, it's a bug.  */
50   assert (dpi != 0 && bdpi != 0);
51   
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);
55   
56   if (m == 0) {
57       if (bdpi <= 4000) {
58           sprintf(q, "%u+%u/%u", dpi / bdpi, dpi % bdpi, bdpi);
59       } else {
60           unsigned f = bdpi/4000;
61           unsigned r = bdpi%4000;
62
63           if (f > 1) {
64               if (r > 0) {
65                   sprintf(q, "%u+%u/(%u*%u+%u)",
66                           dpi/bdpi, dpi%bdpi, f, (bdpi - r)/f, r);
67               } else {
68                   sprintf(q, "%u+%u/(%u*%u)", dpi/bdpi, dpi%bdpi, f, bdpi/f);
69               }
70           } else {
71               sprintf(q, "%u+%u/(4000+%u)", dpi/bdpi, dpi%bdpi, r);
72           }
73       }
74   } else {
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 = "";
80       if (m < 0) {
81           m *= -1;
82           sign = "-";
83       }
84       sprintf(q, "magstep\\(%s%d.%d\\)", sign, m / 2, (m & 1) * 5);
85   }
86   xputenv ("MAKETEX_MAG", q);
87 }
88 \f
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.  */
92
93 static void
94 misstex P2C(kpse_file_format_type, format,  string *, args)
95 {
96   static FILE *missfont = NULL;
97   string *s;
98   
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)
106     return;
107
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 */
118
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,
122                                missfont_name);
123       missfont = fopen (missfont_name, FOPEN_A_MODE);
124     }
125
126     if (missfont)
127       fprintf (stderr, "kpathsea: Appending font creation commands to %s.\n",
128                missfont_name);
129   }
130   
131   /* Write the command if we have a log file.  */
132   if (missfont) {
133     fputs (args[0], missfont);
134     for (s = &args[1]; *s != NULL; s++) {
135       putc(' ', missfont);
136       fputs (*s, missfont);
137     }
138     putc ('\n', missfont);
139   }
140 }  
141
142
143 /* Assume the script outputs the filename it creates (and nothing
144    else) on standard output; hence, we run the script with `popen'.  */
145
146 static string
147 maketex P2C(kpse_file_format_type, format, string*, args)
148 {
149   /* New implementation, use fork/exec pair instead of popen, since
150    * the latter is virtually impossible to make safe.
151    */
152   unsigned len;
153   string *s;
154   string ret;
155   string fn;
156   
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);
161     fputc('\n', stderr);
162   }
163
164 #if defined (AMIGA)
165   /* Amiga has a different interface. */
166   {
167     string cmd;
168     string newcmd;
169     cmd = xstrdup(args[0]);
170     for (s = &args[1];  *s != NULL; s++) {
171       newcmd = concat(cmd, *s);
172       free (cmd);
173       cmd = newcmd;
174     }
175     ret = system(cmd) == 0 ? getenv ("LAST_FONT_CREATED"): NULL;
176     free (cmd);
177   }
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. */
186   {
187     STARTUPINFO si;
188     PROCESS_INFORMATION pi;
189
190     HANDLE child_in, child_out, child_err;
191     HANDLE father_in, father_out_dup;
192     HANDLE current_pid;
193     SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
194     string new_cmd = NULL, app_name = NULL;
195
196     char buf[1024+1];
197     int num;
198     extern char *quote_args(char **argv);
199
200     if (look_for_cmd(args[0], &app_name) == FALSE) {
201       ret = NULL;
202       goto error_exit;
203     }
204
205     /* Compute the command line */
206     new_cmd = quote_args(args);
207
208     /* We need this handle to duplicate other handles */
209     current_pid = GetCurrentProcess();
210
211     ZeroMemory( &si, sizeof(STARTUPINFO) );
212     si.cb = sizeof(STARTUPINFO);
213     si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW ;
214     si.wShowWindow = /* 0 */ SW_HIDE ;
215
216     /* Child stdin */
217     child_in = CreateFile("nul",
218                           GENERIC_READ,
219                           FILE_SHARE_READ | FILE_SHARE_WRITE,
220                           &sa,  /* non inheritable */
221                           OPEN_EXISTING,
222                           FILE_ATTRIBUTE_NORMAL,
223                           NULL);
224     si.hStdInput = child_in;
225
226     if (CreatePipe(&father_in, &child_out, NULL, 0) == FALSE) {
227       fprintf(stderr, "popen: error CreatePipe\n");
228       goto error_exit;
229     }
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);
236       goto error_exit;
237     }
238     CloseHandle(child_out);
239     si.hStdOutput = father_out_dup;
240
241     /* Child stderr */
242     if (kpse_make_tex_discard_errors) {
243       child_err = CreateFile("nul",
244                              GENERIC_WRITE,
245                              FILE_SHARE_READ | FILE_SHARE_WRITE,
246                              &sa,       /* non inheritable */
247                              OPEN_EXISTING,
248                              FILE_ATTRIBUTE_NORMAL,
249                              NULL);
250     }
251     else {
252       DuplicateHandle(current_pid, GetStdHandle(STD_ERROR_HANDLE),
253                       current_pid, &child_err,
254                       0, TRUE,
255                       DUPLICATE_SAME_ACCESS);
256     }
257     si.hStdError = child_err;
258
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 */
270                       ) == 0) {
271       FATAL2("kpathsea: CreateProcess() failed for `%s' (Error %x)\n", new_cmd, GetLastError());
272     }
273
274     CloseHandle(child_in);
275     CloseHandle(father_out_dup);
276     CloseHandle(child_err);
277
278     /* Only the process handle is needed */
279     CloseHandle(pi.hThread);
280
281     /* Get stdout of child from the pipe. */
282     fn = xstrdup("");
283     while (ReadFile(father_in,buf,sizeof(buf)-1, &num, NULL) != 0
284            && num > 0) {
285       if (num <= 0) {
286         if (GetLastError() != ERROR_BROKEN_PIPE) {
287           FATAL2("kpathsea: read() error code for `%s' (Error %d)", new_cmd, GetLastError());
288           break;
289         }
290       } else {
291         string newfn;
292         buf[num] = '\0';
293         newfn = concat(fn, buf);
294         free(fn);
295         fn = newfn;
296       }
297     }
298     /* End of file on pipe, child should have exited at this point. */
299     CloseHandle(father_in);
300
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());
304     }
305
306     CloseHandle(pi.hProcess);
307
308     if (new_cmd) free(new_cmd);
309     if (app_name) free(app_name);
310
311     if (fn) {
312       len = strlen(fn);
313
314       /* Remove trailing newlines and returns.  */
315       while (len && (fn[len - 1] == '\n' || fn[len - 1] == '\r')) {
316         fn[len - 1] = '\0';
317         len--;
318       }
319
320       ret = len == 0 ? NULL : kpse_readable_file (fn);
321       if (!ret && len > 1) {
322         WARNING2 ("kpathsea: %s output `%s' instead of a filename",
323                   new_cmd, fn);
324       }
325
326       /* Free the name if we're not returning it.  */
327       if (fn != ret)
328         free (fn);
329     }
330   error_exit:
331     ;
332   }
333 #else
334   {
335     /* Standard input for the child.  Set to /dev/null */
336     int childin;
337     /* Standard output for the child, what we're interested in. */
338     int childout[2];
339     /* Standard error for the child, same as parent or /dev/null */
340     int childerr;
341     /* Child pid. */
342     pid_t childpid;
343
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)");
348       goto error_childin;
349     }
350     if (pipe(childout) < 0) {
351       perror("kpathsea: pipe()");
352       goto error_childout;
353     }
354     if ((childerr = open("/dev/null", O_WRONLY)) < 0) {
355       perror("kpathsea: open(\"/dev/null\", O_WRONLY)");
356       goto error_childerr;
357     }
358     if ((childpid = fork()) < 0) {
359       perror("kpathsea: fork()");
360       close(childerr);
361      error_childerr:
362       close(childout[0]);
363       close(childout[1]);
364      error_childout:
365       close(childin);
366      error_childin:
367       fn = NULL;
368     } else if (childpid == 0) {
369       /* Child
370        *
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.
374        *
375        * Complete setting up the file descriptors.
376        * We use dup(2) so the order in which we do this matters.
377        */
378       close(childout[0]);
379       /* stdin -- the child will not receive input from this */
380       if (childin != 0) {
381         close(0);
382         dup(childin);
383         close(childin);
384       }
385       /* stdout -- the output of the child's action */
386       if (childout[1] != 1) {
387         close(1);
388         dup(childout[1]);
389         close(childout[1]);
390       }
391       /* stderr -- use /dev/null if we discard errors */
392       if (childerr != 2) {
393         if (kpse_make_tex_discard_errors) {
394           close(2);
395           dup(childerr);
396         }
397         close(childerr);
398       }
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))
402         perror(args[0]);
403       _exit(1);
404     } else {
405       /* Parent */
406       char buf[1024+1];
407       int num;
408
409       /* Clean up child file descriptors that we won't use anyway. */
410       close(childin);
411       close(childout[1]);
412       close(childerr);
413       /* Get stdout of child from the pipe. */
414       fn = xstrdup("");
415       while ((num = read(childout[0],buf,sizeof(buf)-1)) != 0) {
416         if (num == -1) {
417           if (errno != EINTR) {
418             perror("kpathsea: read()");
419             break;
420           }
421         } else {
422           string newfn;
423           buf[num] = '\0';
424           newfn = concat(fn, buf);
425           free(fn);
426           fn = newfn;
427         }
428       }
429       /* End of file on pipe, child should have exited at this point. */
430       close(childout[0]);
431       /* We don't really care about the exit status at this point. */
432       wait(NULL);
433     }
434
435     if (fn) {
436       len = strlen(fn);
437
438       /* Remove trailing newlines and returns.  */
439       while (len && (fn[len - 1] == '\n' || fn[len - 1] == '\r')) {
440         fn[len - 1] = '\0';
441         len--;
442       }
443
444       ret = len == 0 ? NULL : kpse_readable_file (fn);
445       if (!ret && len > 1) {
446         WARNING2("kpathsea: %s output `%s' instead of a filename",
447                  args[0], fn);
448       }
449
450       /* Free the name if we're not returning it.  */
451       if (fn != ret)
452         free (fn);
453     } else {
454       ret = NULL;
455     }
456   }
457 #endif
458
459   if (ret == NULL)
460     misstex (format, args);
461   else
462     kpse_db_insert (ret);
463   
464   return ret;
465 }
466
467
468 /* Create BASE in FORMAT and return the generated filename, or
469    return NULL.  */
470
471 string
472 kpse_make_tex P2C(kpse_file_format_type, format,  const_string, base)
473 {
474   kpse_format_info_type spec; /* some compilers lack struct initialization */
475   string ret = NULL;
476   
477   spec = kpse_format_info[format];
478   if (!spec.type) { /* Not initialized yet? */
479     kpse_init_format (format);
480     spec = kpse_format_info[format];
481   }
482
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);
487     /* Helpers */
488     int argnum;
489     int i;
490     
491     /* FIXME
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.
498      */
499     if (base[0] == '-' /* || IS_DIR_SEP(base[0])  */) {
500       fprintf(stderr, "kpathsea: Invalid fontname `%s', starts with '%c'\n",
501               base, base[0]);
502       return NULL;
503     }
504     for (i = 0; base[i]; i++) {
505       if (!ISALNUM(base[i])
506           && base[i] != '-'
507           && base[i] != '+'
508           && base[i] != '_'
509           && base[i] != '.'
510           && !IS_DIR_SEP(base[i]))
511       {
512         fprintf(stderr, "kpathsea: Invalid fontname `%s', contains '%c'\n",
513                 base, base[i]);
514         return NULL;
515       }
516     }
517
518     if (format == kpse_gf_format
519         || format == kpse_pk_format
520         || format == kpse_any_glyph_format)
521       set_maketex_mag ();
522
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]);
537     }
538     args[argnum++] = xstrdup(base);
539     args[argnum] = NULL;
540
541     ret = maketex (format, args);
542
543     for (argnum = 0; args[argnum] != NULL; argnum++)
544       free (args[argnum]);
545     free (args);
546   }
547
548   return ret;
549 }
550 \f
551 #ifdef TEST
552
553 void
554 test_make_tex (kpse_file_format_type fmt, const_string base)
555 {
556   string answer;
557   
558   printf ("\nAttempting %s in format %d:\n", base, fmt);
559
560   answer = kpse_make_tex (fmt, base);
561   puts (answer ? answer : "(nil)");
562 }
563
564
565 int
566 main ()
567 {
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");
572
573   /* Fail with mktextfm.  */
574   KPSE_MAKE_SPEC_ENABLED (kpse_make_specs[kpse_tfm_format]) = true;
575   test_make_tex (kpse_tfm_format, "foozler99");
576   
577   /* Call something disabled.  */
578   test_make_tex (kpse_bst_format, "no-way");
579   
580   return 0;
581 }
582
583 #endif /* TEST */
584
585
586 /*
587 Local variables:
588 test-compile-command: "gcc -g -I. -I.. -DTEST tex-make.c kpathsea.a"
589 End:
590 */