home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / unixtex-6.1b-src.tgz / tar.out / contrib / unixtex / kpathsea / tex-make.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  9KB  |  302 lines

  1. /* tex-make.c: Run external programs to make TeX-related files.
  2.  
  3. Copyright (C) 1993, 94 Karl Berry.
  4.  
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include <kpathsea/config.h>
  20.  
  21. #include <kpathsea/c-fopen.h>
  22. #include <kpathsea/c-pathch.h>
  23. #include <kpathsea/concatn.h>
  24. #include <kpathsea/db.h>
  25. #include <kpathsea/fn.h>
  26. #include <kpathsea/magstep.h>
  27. #include <kpathsea/readable.h>
  28. #include <kpathsea/tex-make.h>
  29. #include <kpathsea/variable.h>
  30.  
  31.  
  32. /* We never throw away stdout, since that is supposed to be the filename
  33.    found, if all is successful.  This variable controls whether stderr
  34.    is thrown away.  */
  35. boolean kpse_make_tex_discard_errors = false;
  36.  
  37. /* We set the envvar MAKETEX_MAG, which is part of the default spec for
  38.    MakeTeXPK above, based on KPATHSEA_DPI and MAKETEX_BASE_DPI.  */
  39.  
  40. static void
  41. set_maketex_mag P1H(void)
  42. {
  43.   char q[MAX_INT_LENGTH * 3 + 3];
  44.   int m;
  45.   string dpi_str = getenv ("KPATHSEA_DPI");
  46.   string bdpi_str = getenv ("MAKETEX_BASE_DPI");
  47.   unsigned dpi = dpi_str ? atoi (dpi_str) : 0;
  48.   unsigned bdpi = bdpi_str ? atoi (bdpi_str) : 0;
  49.  
  50.   /* If the environment variables aren't set, it's a bug.  */
  51.   assert (dpi != 0 && bdpi != 0);
  52.   
  53.   /* Fix up for roundoff error.  Hopefully the driver has already fixed
  54.      up DPI, but may as well be safe, and also get the magstep number.  */
  55.   (void) kpse_magstep_fix (dpi, bdpi, &m);
  56.   
  57.   /* Have to do something different for DOS?  */
  58.   if (m == 0)
  59.     sprintf (q, "%d+%d/%d", dpi / bdpi, dpi % bdpi, bdpi);
  60.   else
  61.     { /* m is encoded with LSB being a ``half'' bit (see magstep.h).  Are
  62.          we making an assumption here about two's complement?  Probably.
  63.          In any case, if m is negative, we have to put in the sign
  64.          explicitly, since m/2==0 if m==-1.  */
  65.       const_string sign = "";
  66.       if (m < 0)
  67.         {
  68.           m *= -1;
  69.           sign = "-";
  70.         }
  71.       sprintf (q, "magstep\\(%s%d.%d\\)", sign, m / 2, (m & 1) * 5);
  72.     }  
  73.   xputenv ("MAKETEX_MAG", q);
  74. }
  75.  
  76. /* This MakeTeX... program was disabled, or the script failed.  If this
  77.    was a font creation (according to FORMAT), append CMD
  78.    to a file missfont.log in the current directory.  */
  79.  
  80. static void
  81. misstex P2C(kpse_file_format_type, format,  const_string, cmd)
  82. {
  83.   static FILE *missfont = NULL;
  84.  
  85.   /* If we weren't trying to make a font, do nothing.  Maybe should
  86.      allow people to specify what they want recorded?  */
  87.   if (format > kpse_any_glyph_format && format != kpse_tfm_format
  88.       && format != kpse_vf_format)
  89.     return;
  90.  
  91.   /* If this is the first time, have to open the log file.  */
  92.   if (!missfont)
  93.     {
  94.       const_string missfont_name = "missfont.log";
  95.       missfont = fopen (missfont_name, FOPEN_A_MODE);
  96.       if (!missfont && getenv ("TEXMFOUTPUT"))
  97.         {
  98.           missfont_name = concat3 (getenv ("TEXMFOUTPUT"), DIR_SEP_STRING,
  99.                                    missfont_name);
  100.           missfont = fopen (missfont_name, FOPEN_A_MODE);
  101.         }
  102.  
  103.       /* Should we really be unconditionally shouting this message?  */
  104.       if (missfont)
  105.         fprintf (stderr, "kpathsea: Appending font creation commands to %s.\n",
  106.                  missfont_name);
  107.     }
  108.   
  109.   /* Write the command if we have a log file.  */
  110.   if (missfont)
  111.     {
  112.       fputs (cmd, missfont);
  113.       putc ('\n', missfont);
  114.     }
  115. }  
  116.  
  117.  
  118. /* Assume the script outputs the filename it creates (and nothing
  119.    else) on standard output; hence, we run the script with `popen'.  */
  120.  
  121. static string
  122. maketex P2C(kpse_file_format_type, format,  const_string, cmd)
  123. {
  124.   string ret;
  125.   FILE *f;
  126.   
  127.   /* Tell the user we are running the script, so they have a clue as to
  128.      what's going on if something messes up.  */
  129.   fprintf (stderr, "kpathsea: Running %s\n", cmd);
  130.   
  131.   /* Run the script.  */
  132.   f = popen (cmd, FOPEN_R_MODE);
  133.  
  134.   if (f)
  135.     {
  136.       int c;
  137.       string fn;             /* The final filename.  */
  138.       unsigned len;          /* And its length.  */
  139.       fn_type output;
  140.       output = fn_init ();   /* Collect the script output.  */
  141.  
  142.       /* Read all the output and terminate with a null.  */
  143.       while ((c = getc (f)) != EOF)
  144.         fn_1grow (&output, c);
  145.       fn_1grow (&output, 0);
  146.  
  147.       /* Maybe should check for `EXIT_SUCCESS' status before even
  148.          looking at the output?  */
  149.       if (pclose (f) == -1)
  150.         FATAL_PERROR (cmd);
  151.  
  152.       len = FN_LENGTH (output);
  153.       fn = FN_STRING (output);
  154.  
  155.       /* Remove trailing newlines and returns.  */
  156.       while (len > 1 && (fn[len - 2] == '\n' || fn[len - 2] == '\r'))
  157.         {
  158.           fn[len - 2] = 0;
  159.           len--;
  160.         }
  161.  
  162.       /* If no output from script, return NULL.  Otherwise check
  163.          what it output.  */
  164.       ret = len == 1 ? NULL : kpse_readable_file (fn);
  165.  
  166.       /* Free the name if we're not returning it.  */
  167.       if (fn != ret)
  168.         free (fn);
  169.     }
  170.   else
  171.     /* popen failed.  Maybe should give error (optionally), but for
  172.        now be silent, to avoid annoying people who purposefully
  173.        don't have the script installed. */
  174.     ret = NULL;
  175.   
  176.   if (ret == NULL)
  177.     misstex (format, cmd);
  178.   else
  179.     db_insert (ret);
  180.     
  181.   return ret;
  182. }
  183.  
  184.  
  185. /* Create BASE in FORMAT and return the generated filename, or
  186.    return NULL.  */
  187.  
  188. string
  189. kpse_make_tex P2C(kpse_file_format_type, format,  const_string, base)
  190. {
  191.   kpse_format_info_type spec; /* some compilers lack struct initialization */
  192.   string ret = NULL;
  193.   
  194.   spec = kpse_format_info[format];
  195.   
  196.   if (spec.program)
  197.     {
  198.       /* See the documentation for the envvars we're dealing with here.  */
  199.       string args, cmd;
  200.       const_string prog = spec.program; /* MakeTeXPK */
  201.       string PROG = uppercasify (prog); /* MAKETEXPK */
  202.       string progenv = getenv (PROG);   /* ENV{"MAKETEXPK"} */
  203.       const_string arg_spec = progenv ? progenv : spec.program_args;
  204.       string mode = getenv ("MAKETEX_MODE");
  205.       boolean unset_mode = false;
  206.       
  207.       set_maketex_mag ();
  208.       
  209.       /* Here's an awful kludge: if the mode is `/', unset it for the
  210.          call and then reset it.  We could ignore a mode of / in
  211.          MakeTeXPK, but then everyone's MakeTeXPK would have to handle
  212.          that special case, which seems too onerous.  `kpse_prog_init'
  213.          sets it to this in the first place when no mode is otherwise
  214.          specified; this is so when the user defines a resolution, they
  215.          don't also have to specify a mode; instead, MakeTeXPK's guesses
  216.          will take over.  They use / for the value because then when it
  217.          is expanded as part of the PKFONTS et al. path values, we'll
  218.          wind up searching all the pk directories.  We put $MAKETEX_MODE
  219.          in the path values in the first place so that sites with two
  220.          different devices with the same resolution can find the right
  221.          fonts; but such sites are uncommon, so they shouldn't make
  222.          things harder for everyone else.  */
  223.       if (mode && STREQ (mode, DIR_SEP_STRING))
  224.         {
  225.           xputenv ("MAKETEX_MODE", "");
  226.           unset_mode = true;
  227.         }
  228.       args = arg_spec ? kpse_var_expand (arg_spec) : (string) "";
  229.       if (unset_mode)
  230.         xputenv ("MAKETEX_MODE", DIR_SEP_STRING);
  231.       
  232.       /* The command is the program name plus the arguments.  */
  233.       cmd = concatn (prog, " ", base, " ", args, NULL);
  234.  
  235.       if (spec.program_enabled_p)
  236.         {
  237.           /* Only way to discard errors is redirect stderr inside another
  238.              shell; otherwise, if the MakeTeX... script doesn't exist, we
  239.              will see the `sh: MakeTeX...: not found' error.  No point in
  240.              doing this if we're not actually going to run anything.  */
  241.           if (kpse_make_tex_discard_errors)
  242.             {
  243.               string old_cmd = cmd;
  244.               cmd = concat3 ("sh -c \"", cmd, "\" 2>/dev/null");
  245.               free (old_cmd);
  246.             }
  247.  
  248.           ret = maketex (format, cmd);
  249.         }
  250.       else
  251.         misstex (format, cmd);
  252.  
  253.       free (PROG);
  254.       free (cmd);
  255.       if (*args)
  256.         free (args);
  257.     }  
  258.  
  259.   return ret;
  260. }
  261.  
  262. #ifdef TEST
  263.  
  264. void
  265. test_make_tex (kpse_file_format_type fmt, const_string base)
  266. {
  267.   string answer;
  268.   
  269.   printf ("\nAttempting %s in format %d:\n", base, fmt);
  270.  
  271.   answer = kpse_make_tex (fmt, base);
  272.   puts (answer ? answer : "(null)");
  273. }
  274.  
  275.  
  276. int
  277. main ()
  278. {
  279.   xputenv ("KPATHSEA_DPI", "781"); /* call MakeTeXPK */
  280.   xputenv ("MAKETEX_BASE_DPI", "300"); /* call MakeTeXPK */
  281.   KPSE_MAKE_SPEC_ENABLED (kpse_make_specs[kpse_pk_format]) = true;
  282.   test_make_tex (kpse_pk_format, "cmr10");
  283.  
  284.   /* Fail with MakeTeXTFM.  */
  285.   KPSE_MAKE_SPEC_ENABLED (kpse_make_specs[kpse_tfm_format]) = true;
  286.   test_make_tex (kpse_tfm_format, "foozler99");
  287.   
  288.   /* Call something disabled.  */
  289.   test_make_tex (kpse_bst_format, "no-way");
  290.   
  291.   return 0;
  292. }
  293.  
  294. #endif /* TEST */
  295.  
  296.  
  297. /*
  298. Local variables:
  299. test-compile-command: "gcc -g -I. -I.. -DTEST tex-make.c kpathsea.a"
  300. End:
  301. */
  302.