home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / octave-1.1.1p1-base.tgz / octave-1.1.1p1-base.tar / fsf / octave / kpathsea / tex-make.c < prev    next >
C/C++ Source or Header  |  1994-02-02  |  9KB  |  322 lines

  1. /* tex-make.c: Run external programs to make TeX files.
  2.  
  3. Copyright (C) 1993 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/concatn.h>
  23. #include <kpathsea/fn.h>
  24. #include <kpathsea/readable.h>
  25. #include <kpathsea/tex-make.h>
  26. #include <kpathsea/variable.h>
  27.  
  28.  
  29. /* We never throw away stdout, since that is supposed to be the filename
  30.    found, if all is successful.  This variable controls whether stderr
  31.    is thrown away.  */
  32. boolean kpse_make_tex_discard_errors = false;
  33.  
  34.  
  35. #define MAKE_TEX_PK_SPEC \
  36.   "$KPATHSEA_DPI $MAKETEX_BASE_DPI $MAKETEX_MAG $MAKETEX_MODE"
  37.  
  38. /* We could generalize this to the idea of a ``path spec'', and collect
  39.    the default paths, environment variables, and whatever else in the
  40.    same structure.  `kpse_var_expand' could understand ${PARM-word} to
  41.    go along with it, then the envvar search list itself would be
  42.    overridable.  Is it worth it?  */
  43. kpse_make_spec_type kpse_make_specs[] = {
  44.   /* kpse_gf_format */        { false, NULL, NULL },
  45.   /* kpse_pk_format */        { false, "MakeTeXPK", MAKE_TEX_PK_SPEC },
  46.   /* kpse_any_glyph_format */    { false, "MakeTeXPK", MAKE_TEX_PK_SPEC },
  47.   /* kpse_bib_format */        { false, NULL, NULL }, 
  48.   /* kpse_bst_format */        { false, NULL, NULL }, 
  49.   /* kpse_mf_format */        { false, "MakeTeXMF", NULL },
  50.   /* kpse_tex_format */        { false, "MakeTeXTeX", NULL },
  51.   /* kpse_tfm_format */        { false, "MakeTeXTFM", NULL },
  52.   /* kpse_vf_format */        { false, NULL, NULL },
  53. };
  54.  
  55.  
  56. /* We assume the script will output the filename it creates (and nothing
  57.    else) on standard output, and hence run the script with `popen'.  */
  58.  
  59. string
  60. kpse_make_tex P2C(kpse_file_format_type, format,  const_string, base_file)
  61. {
  62.   string ret;
  63.   kpse_make_spec_type spec;
  64.   spec = kpse_make_specs[format];
  65.   
  66.   if (KPSE_MAKE_SPEC_ENABLED (spec))
  67.     {
  68.       FILE *f;
  69.       const_string prog = KPSE_MAKE_SPEC_PROGRAM (spec);
  70.       string PROG = uppercasify (prog);
  71.       string progenv = getenv (PROG);
  72.       const_string arg_spec = progenv ? progenv : KPSE_MAKE_SPEC_ARGS (spec);
  73.       string args = arg_spec ? kpse_var_expand (arg_spec) : (string) "";
  74.       string cmd = concatn (prog, " ", base_file, " ", args, NULL);
  75.       
  76.       /* Only way to discard errors is redirect stderr inside another
  77.          shell; otherwise, if the MakeTeX... script doesn't exist, we
  78.          will see the `sh: MakeTeX...: not found' error.  */
  79.       if (kpse_make_tex_discard_errors)
  80.         {
  81.           string old_cmd = cmd;
  82.           cmd = concat3 ("sh -c \"", cmd, "\" 2>/dev/null");
  83.           free (old_cmd);
  84.         }
  85.  
  86.       /* Run the script and prepare to read the output.  */
  87.       f = popen (cmd, FOPEN_R_MODE);
  88.       
  89.       free (PROG);
  90.       free (cmd);
  91.       if (strlen (args) > 0)
  92.         free (args);
  93.       
  94.       if (f)
  95.         {
  96.           int c;
  97.           string fn;             /* The final filename.  */
  98.           unsigned len;          /* And its length.  */
  99.           fn_type output;
  100.           output = fn_init ();   /* Collect the script output.  */
  101.           
  102.           /* Read all the output and terminate with a null.  */
  103.           while ((c = getc (f)) != EOF)
  104.             fn_1grow (&output, c);
  105.           fn_1grow (&output, 0);
  106.           
  107.           /* Maybe should check for `EXIT_SUCCESS' status before even
  108.              looking at the output?  */
  109.           if (pclose (f) == -1)
  110.             FATAL_PERROR (cmd);
  111.           
  112.           len = FN_LENGTH (output);
  113.           fn = FN_STRING (output);
  114.           
  115.           /* Remove trailing newlines and returns.  */
  116.           while (len > 1 && (fn[len - 2] == '\n' || fn[len - 2] == '\r'))
  117.             {
  118.               fn[len - 2] = 0;
  119.               len--;
  120.             }
  121.  
  122.           /* If no output from script, return NULL.  Otherwise check
  123.              what it output.  */
  124.           ret = len == 1 ? NULL : kpse_readable_file (fn);
  125.           
  126.           /* Free the name if we're not returning it.  */
  127.           if (fn != ret)
  128.             free (fn);
  129.         }
  130.       else
  131.         /* popen failed.  Maybe should give error (optionally), but for
  132.            now be silent, to avoid annoying people who purposefully
  133.            don't have the script installed. */
  134.         ret = NULL;
  135.     }
  136.   else
  137.     ret = NULL; /* This MakeTeX... program was disabled.  */
  138.   
  139.   return ret;
  140. }
  141.  
  142. /* Return true magstep N for resolution BDPI.  From dvips.  */
  143.  
  144. static int
  145. magstep P2C(int, n,  int, bdpi)
  146. {
  147.    register double t;
  148.    int step;
  149.    int neg = 0;
  150.  
  151.    if (n < 0) {
  152.       neg = 1;
  153.       n = -n;
  154.    }
  155.    if (n & 1) {
  156.       n &= ~1;
  157.       t = 1.095445115;
  158.    } else
  159.       t = 1.0;
  160.    while (n > 8) {
  161.       n -= 8;
  162.       t = t * 2.0736;
  163.    }
  164.    while (n > 0) {
  165.       n -= 2;
  166.       t = t * 1.2;
  167.    }
  168.  
  169.    step = 0.5 + (neg ? bdpi / t : bdpi * t);
  170.    return step;
  171. }
  172.  
  173. /* Tom Rokicki wrote this code for dvips.  It is in kpathsea now so that
  174.    we can be sure xdvik and dvipsk use the same code to compute this.
  175.  
  176.       His comments:
  177.  
  178.       Here we want to return a string.  If we can find some integer
  179.       m such that floor(0.5 + bdpi * 1.2 ^ (m/2)) = dpi, we write out
  180.          magstep(m/2)
  181.       where m/2 is a decimal number; else we write out
  182.          dpi/bdpi
  183.       We do this for the very slight improvement in accuracy that
  184.       magstep() gives us over the rounded dpi/bdpi.
  185.  
  186.    Instead of returning a string, we set the envvar MAKETEX_MAG, which
  187.    is part of the default spec for MakeTeXPK above. (That's why this
  188.    routine is in this source file.)
  189.    
  190.    We allow +-1 when checking if DPI is a given magstep, so that DPI
  191.    values of 328, 329, and 330 will all translate to magstep(.5).
  192.    Floating-point computation with the DVI scale factors leads to 328.  */
  193.  
  194. /* Don't bother trying to use fabs or some other ``standard'' routine
  195.    which can only cause trouble; just roll our own simple-minded
  196.    absolute-value function that is all we need.  */
  197. #define ABS(expr) ((expr) < 0 ? -(expr) : (expr))
  198.  
  199. void
  200. kpse_set_maketex_mag P2C(int, dpi,  int, bdpi)
  201. {
  202.   int m, n;
  203.   char q[1000];
  204.  
  205.   m = 0;
  206.   if (dpi < bdpi) {
  207.      for (;;) {
  208.         m--;
  209.         n = magstep(m, bdpi);
  210.         if (ABS (n - dpi) <= 1)
  211.            break;
  212.         if (n < dpi || m < -40) {
  213.            m = 9999;
  214.            break;
  215.         }
  216.      }
  217.   } else if (dpi > bdpi) {
  218.      for (;;) {
  219.         m++;
  220.         n = magstep(m, bdpi);
  221.         if (ABS (n - dpi) <= 1)
  222.            break;
  223.         if (n > dpi || m > 40) {
  224.            m = 9999;
  225.            break;
  226.         }
  227.      }
  228.   }
  229. #if defined (DOS) || defined (OS2)
  230.   {
  231.     double t;
  232.  
  233.   /* write out magnification as decimal number ... why? --karl */
  234.     if (m == 9999) {
  235.        t = (double)dpi/bdpi;
  236.     } else {
  237.        if (m < 0)
  238.             n = -m;
  239.        else
  240.             n = m;
  241.        if (n & 1) {
  242.             n &= ~1;
  243.             t = 1.095445115;
  244.        } else
  245.             t = 1.0;
  246.        while (n > 0) {
  247.             n -= 2;
  248.             t = t * 1.2;
  249.        }
  250.        if (m < 0)
  251.             t = 1 / t;
  252.     }
  253.     sprintf(q, "%12.9f", t);
  254.   }
  255. #else /* not DOS or OS2 */
  256.   if (m == 9999) {
  257.      sprintf(q, "%d+%d/%d", dpi/bdpi, dpi%bdpi, bdpi);
  258.   } else if (m >= 0) {
  259.      sprintf(q, "magstep\\(%d.%d\\)", m/2, (m&1)*5);
  260.   } else {
  261.      sprintf(q, "magstep\\(-%d.%d\\)", (-m)/2, (m&1)*5);
  262.   }
  263. #endif /* not DOS or OS2 */
  264.  
  265.   xputenv ("MAKETEX_MAG", q);
  266. }
  267.  
  268. /* I don't think it makes much difference whether we check if DPI2 can
  269.    tolerate DPI1 or the reverse.  */
  270.  
  271. boolean
  272. kpse_check_bitmap_tolerance P2C(double, dpi1,  double, dpi2)
  273. {
  274.   unsigned tolerance = KPSE_BITMAP_TOLERANCE (dpi2);
  275.   unsigned lower_bound = (int) (dpi2 - tolerance) < 0 ? 0 : dpi2 - tolerance;
  276.   unsigned upper_bound = dpi2 + tolerance;
  277.  
  278.   return lower_bound <= dpi1 && dpi1 <= upper_bound;
  279. }
  280.  
  281. #ifdef TEST
  282.  
  283. void
  284. test_make_tex (kpse_file_format_type fmt, const_string base_file)
  285. {
  286.   string answer;
  287.   
  288.   printf ("\nAttempting %s in format %d:\n", base_file, fmt);
  289.  
  290.   answer = kpse_make_tex (fmt, base_file);
  291.   puts (answer ? answer : "(null)");
  292. }
  293.  
  294.  
  295. int
  296. main ()
  297. {
  298.   xputenv ("MAKETEX_DPI", "781"); /* call MakeTeXPK */
  299.   xputenv ("MAKETEX_BASE_DPI", "300"); /* call MakeTeXPK */
  300.   xputenv ("MAKETEX_MAG", "781/300"); /* call MakeTeXPK */
  301.   KPSE_MAKE_SPEC_ENABLED (kpse_make_specs[kpse_pk_format]) = true;
  302.   test_make_tex (kpse_pk_format, "cmr10");
  303.  
  304.   /* Fail with MakeTeXTFM.  */
  305.   KPSE_MAKE_SPEC_ENABLED (kpse_make_specs[kpse_tfm_format]) = true;
  306.   test_make_tex (kpse_tfm_format, "foozler99");
  307.   
  308.   /* Call something disabled.  */
  309.   test_make_tex (kpse_bst_format, "no-way");
  310.   
  311.   return 0;
  312. }
  313.  
  314. #endif /* TEST */
  315.  
  316.  
  317. /*
  318. Local variables:
  319. test-compile-command: "gcc -posix -g -I. -I.. -DTEST tex-make.c kpathsea.a"
  320. End:
  321. */
  322.