home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 9 / FreshFishVol9-CD2.bin / bbs / gnu / unixtex-6.1b-src.lha / unixtex-6.1b / web2c / lib / texmf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-04  |  20.8 KB  |  804 lines

  1. /* Hand-coded routines for TeX or Metafont in C.  Originally
  2.    written by Tim Morgan, drawing from other Unix ports of TeX.  */
  3.  
  4. /* Either `texd.h' or `mfd.h' will include `../common/texmf.h'.  */
  5.  
  6. /* Instantiate data in `texd.h' or `mfd.h' here.  */
  7. #define    EXTERN
  8.  
  9. #ifdef TeX
  10. #include "texd.h"
  11. #define dump_default_var TEXformatdefault
  12. #define dump_default " plain.fmt"
  13. #define dump_format " %s.fmt"
  14. #define dump_ext_length 4
  15. #define dump_default_length formatdefaultlength
  16. #define virgin_program "virtex"
  17. #define main_program texbody
  18. #define edit_value tex_edit_value
  19. #define edit_var "TEXEDIT"
  20. #else /* not TeX */
  21. #include "mfd.h"
  22. #define dump_default_var MFbasedefault
  23. #define dump_default " plain.base"
  24. #define dump_format " %s.base"
  25. #define dump_ext_length 5
  26. #define dump_default_length basedefaultlength
  27. #define virgin_program "virmf"
  28. #define main_program main_body
  29. #define edit_value mf_edit_value
  30. #define edit_var "MFEDIT"
  31. #endif /* not TeX */
  32.  
  33. #include <kpathsea/c-ctype.h>
  34. #include <kpathsea/c-pathch.h>
  35. #include <kpathsea/tex-file.h>
  36.  
  37. /* For `struct tm'.  */
  38. #include <time.h>
  39. extern struct tm *localtime ();
  40.  
  41. /* Catch interrupts.  */
  42. #include <signal.h>
  43.  
  44. #ifdef FUNNY_CORE_DUMP
  45. void funny_core_dump ();
  46. #endif
  47.  
  48. /* ridderbusch.pad@nixdorf.com says this is necessary.  */
  49. #ifdef ATARI_ST
  50. int _stksize = -1L;
  51. #endif
  52.  
  53. /* The main program, etc.  */
  54.  
  55. /* What we were invoked as and with.  */
  56. static char *program_name = NULL;
  57. static int gargc;
  58. char **gargv;
  59. int argc;
  60.  
  61.  
  62. /* The entry point: set up for reading the command line, which will
  63.    happen in `topenin', then call the main body.  */
  64.  
  65. int
  66. main (ac, av)
  67.     int ac;
  68.     char *av[];
  69. {
  70.   gargc = ac;
  71.   gargv = av;
  72.  
  73.   dump_default_var = dump_default;
  74.   dump_default_length = strlen (dump_default + 1);
  75.  
  76.   kpse_set_progname(av[0]);
  77.  
  78. #ifndef INI
  79.   if (readyalready != 314159)
  80.     {
  81.       program_name = strrchr (av[0], DIR_SEP);
  82.       if (program_name == NULL)
  83.     program_name = av[0];
  84.       else
  85.     program_name++;
  86.       if (strcmp (program_name, virgin_program) != 0)
  87.         {
  88.           char custom_default[PATH_MAX];
  89.  
  90.           /* TeX/Metafont adds the space at the end of the name.  */
  91.           sprintf (custom_default, dump_format, program_name);
  92.           dump_default_var = custom_default;
  93.           dump_default_length = strlen (program_name) + dump_ext_length;
  94.         }
  95.     }
  96. #endif /* not INI */
  97.  
  98. #ifdef MF
  99.   {
  100.     boolean use_maketexmf = MAKE_TEX_MF_BY_DEFAULT
  101.                             || getenv ("USE_MAKETEXMF")
  102.                             || getenv ("MAKETEXMF");
  103.     kpse_format_info[kpse_mf_format].program_enabled_p = use_maketexmf;
  104.   }
  105. #endif /* MF */
  106. #ifdef TeX
  107.   {
  108.     boolean use_maketextex = MAKE_TEX_TEX_BY_DEFAULT
  109.                              || getenv ("USE_MAKETEXTEX")
  110.                              || getenv ("MAKETEXTEX");
  111.     boolean use_maketextfm = MAKE_TEX_TFM_BY_DEFAULT
  112.                              || getenv ("USE_MAKETEXTFM")
  113.                              || getenv ("MAKETEXTFM");
  114.     kpse_format_info[kpse_tex_format].program_enabled_p = use_maketextex;
  115.     kpse_format_info[kpse_tfm_format].program_enabled_p = use_maketextfm;
  116.   }
  117. #endif /* TeX */
  118.  
  119.   main_program ();
  120.  
  121.  
  122. /* This is supposed to ``open the terminal for input'', but what we
  123.    really do is copy command line arguments into TeX's or Metafont's
  124.    buffer, so they can handle them.  If nothing is available, or we've
  125.    been called already (and hence, gargc==0), we return with
  126.    `last=first'.  */
  127.  
  128. void
  129. topenin ()
  130. {
  131.   register int i;
  132.  
  133.   buffer[first] = 0;    /* So the first `strcat' will work.  */
  134.  
  135.   if (gargc > 1)
  136.     { /* We have command line arguments.  */
  137.       for (i = 1; i < gargc; i++)
  138.         {
  139.       (void) strcat ((char *) &buffer[first], gargv[i]);
  140.           (void) strcat ((char *) &buffer[first], " ");
  141.     }
  142.       gargc = 0;    /* Don't do this again.  */
  143.     }
  144.  
  145.   /* Find the end of the buffer.  */
  146.   for (last = first; buffer[last]; ++last)
  147.     ;
  148.  
  149.   /* Make `last' be one past the last non-blank non-formfeed character
  150.      in `buffer'.  */
  151.   for (--last; last >= first
  152.        && ISSPACE (buffer[last]) && buffer[last] != '\f'; --last) 
  153.     ;
  154.   last++;
  155.  
  156.   /* One more time, this time converting to TeX's internal character
  157.      representation.  */
  158. #ifdef NONASCII
  159.   for (i = first; i < last; i++)
  160.     buffer[i] = xord[buffer[i]];
  161. #endif
  162. }
  163.  
  164. /* All our interrupt handler has to do is set TeX's or Metafont's global
  165.    variable `interrupt'; then they will do everything needed.  */
  166.  
  167. static RETSIGTYPE
  168. catch_interrupt (arg)
  169.     int arg;
  170. {
  171.   interrupt = 1;
  172.   (void) signal (SIGINT, catch_interrupt);
  173. }
  174.  
  175.  
  176. /* Besides getting the date and time here, we also set up the interrupt
  177.    handler, for no particularly good reason.  It's just that since the
  178.    `fix_date_and_time' routine is called early on (section 1337 in TeX,
  179.    ``Get the first line of input and prepare to start''), this is as
  180.    good a place as any.  */
  181.  
  182. void
  183. get_date_and_time (minutes, day, month, year)
  184.     integer *minutes, *day, *month, *year;
  185. {
  186.   time_t clock = time ((time_t *) 0);
  187.   struct tm *tmptr = localtime (&clock);
  188.  
  189.   *minutes = tmptr->tm_hour * 60 + tmptr->tm_min;
  190.   *day = tmptr->tm_mday;
  191.   *month = tmptr->tm_mon + 1;
  192.   *year = tmptr->tm_year + 1900;
  193.  
  194.   {
  195. #ifdef SA_INTERRUPT
  196.     /* Under SunOS 4.1.x, the default action after return from the
  197.        signal handler is to restart the I/O if nothing has been
  198.        transferred.  The effect on TeX is that interrupts are ignored if
  199.        we are waiting for input.  The following tells the system to
  200.        return EINTR from read() in this case.  From ken@cs.toronto.edu.  */
  201.  
  202.     struct sigaction a, oa;
  203.  
  204.     a.sa_handler = catch_interrupt;
  205.     sigemptyset (&a.sa_mask);
  206.     sigaddset (&a.sa_mask, SIGINT);
  207.     a.sa_flags = SA_INTERRUPT;
  208.     sigaction (SIGINT, &a, &oa);
  209.     if (oa.sa_handler != SIG_DFL)
  210.       sigaction (SIGINT, &oa, (struct sigaction *) 0);
  211.  
  212. #else /* no SA_INTERRUPT */
  213.     RETSIGTYPE (*old_handler) ();
  214.     
  215.     old_handler = signal (SIGINT, catch_interrupt);
  216.     if (old_handler != SIG_DFL)
  217.       signal (SIGINT, old_handler);
  218. #endif /* no SA_INTERRUPT */
  219.   }
  220. }
  221.  
  222. /* I/O for TeX and Metafont.  */
  223.  
  224. /* Read a line of input as efficiently as possible while still looking
  225.    like Pascal.  We set `last' to `first' and return `false' if we get
  226.    to eof.  Otherwise, we return `true' and set last = first +
  227.    length(line except trailing whitespace).  */
  228.  
  229. boolean
  230. input_line (f)
  231.     FILE *f;
  232. {
  233.   register int i;
  234.  
  235.   last = first;
  236.  
  237.   while (last < bufsize && (i = getc (f)) != EOF && i != '\n')
  238.     buffer[last++] = i;
  239.  
  240.   if (i == EOF && last == first)
  241.       return false;
  242.  
  243.   /* We didn't get the whole line because our buffer was too small.  */
  244.   if (i != EOF && i != '\n')
  245.     {
  246.       (void) fprintf (stderr,
  247.                      "! Unable to read an entire line---bufsize=%d.\n",
  248.                      bufsize);
  249.       (void) fprintf (stderr, "Please ask a wizard to enlarge me.\n");
  250.       uexit (1);
  251.     }
  252.  
  253.   buffer[last] = ' ';
  254.   if (last >= maxbufstack)
  255.     maxbufstack = last;
  256.  
  257.   /* Trim trailing whitespace.  */
  258.   while (last > first
  259.          && (isblank (buffer[last - 1]) || buffer[last - 1] == '\r'))
  260.     --last;
  261.  
  262.   /* Don't bother using xord if we don't need to.  */
  263. #ifdef NONASCII
  264.   for (i = first; i <= last; i++)
  265.      buffer[i] = xord[buffer[i]];
  266. #endif
  267.  
  268.     return true;
  269. }
  270.  
  271. /* This string specifies what the `e' option does in response to an
  272.    error message.  */ 
  273. static char *edit_value = EDITOR;
  274.  
  275. /* This procedure is due to sjc@s1-c.  TeX (or Metafont) calls it when
  276.    the user types `e' in response to an error, invoking a text editor on
  277.    the erroneous source file.  FNSTART is how far into FILENAME the
  278.    actual filename starts; FNLENGTH is how long the filename is.
  279.    
  280.    See ../site.h for how to set the default, and how to override it.  */
  281.  
  282. void
  283. calledit (filename, fnstart, fnlength, linenumber)
  284.     ASCIIcode *filename;
  285.     poolpointer fnstart;
  286.     integer fnlength, linenumber;
  287. {
  288.   char *temp, *command;
  289.   char c;
  290.   int sdone, ddone, i;
  291.  
  292.   sdone = ddone = 0;
  293.   filename += fnstart;
  294.  
  295.   /* Close any open input files, since we're going to kill the job.  */
  296.   for (i = 1; i <= inopen; i++)
  297.     (void) fclose (inputfile[i]);
  298.  
  299.   /* Replace the default with the value of the appropriate environment
  300.      variable, if it's set.  */
  301.   temp = getenv (edit_var);
  302.   if (temp != NULL)
  303.     edit_value = temp;
  304.  
  305.   /* Construct the command string.  The `11' is the maximum length an
  306.      integer might be.  */
  307.   command = (string) xmalloc (strlen (edit_value) + fnlength + 11);
  308.  
  309.   /* So we can construct it as we go.  */
  310.   temp = command;
  311.  
  312.   while ((c = *edit_value++) != 0)
  313.     {
  314.       if (c == '%')
  315.         {
  316.           switch (c = *edit_value++)
  317.             {
  318.         case 'd':
  319.           if (ddone)
  320.                 {
  321.           (void) fprintf (stderr,
  322.                            "! `%%d' cannot appear twice in editor command.\n");
  323.               uexit (1);
  324.         }
  325.               (void) sprintf (temp, "%d", linenumber);
  326.               while (*temp != '\0')
  327.                 temp++;
  328.               ddone = 1;
  329.               break;
  330.  
  331.         case 's':
  332.               if (sdone)
  333.                 {
  334.               (void) fprintf(stderr,
  335.                            "! `%%s' cannot appear twice in editor command.\n");
  336.           uexit (1);
  337.         }
  338.               for (i =0; i < fnlength; i++)
  339.         *temp++ = Xchr (filename[i]);
  340.               sdone = 1;
  341.               break;
  342.  
  343.         case '\0':
  344.               *temp++ = '%';
  345.               /* Back up to the null to force termination.  */
  346.           edit_value--;
  347.           break;
  348.  
  349.         default:
  350.           *temp++ = '%';
  351.           *temp++ = c;
  352.           break;
  353.         }
  354.     }
  355.       else
  356.     *temp++ = c;
  357.     }
  358.  
  359.   *temp = 0;
  360.  
  361.   /* Execute the command.  */
  362.   if (system (command) != 0)
  363.     fprintf (stderr, "! Trouble executing `%s'.\n", command);
  364.  
  365.   /* Quit, since we found an error.  */
  366.   uexit (1);
  367. }
  368.  
  369. /* Read and write format (for TeX) or base (for Metafont) files.  In
  370.    tex.web, these files are architecture dependent; specifically,
  371.    BigEndian and LittleEndian architectures produce different files.
  372.    These routines always output BigEndian files.  This still does not
  373.    make the dump files architecture-independent, because it is possible
  374.    to make a format file that dumps a glue ratio, i.e., a floating-point
  375.    number.  Fortunately, none of the standard formats do that.  */
  376.  
  377. #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP) /* this fn */
  378.  
  379. /* This macro is always invoked as a statement.  It assumes a variable
  380.    `temp'.  */
  381.    
  382. #define SWAP(x, y) temp = (x); (x) = (y); (y) = temp;
  383.  
  384.  
  385. /* Make the NITEMS items pointed at by P, each of size SIZE, be the
  386.    opposite-endianness of whatever they are now.  */
  387.  
  388. static void
  389. swap_items (p, nitems, size)
  390.   char *p;
  391.   int nitems;
  392.   int size;
  393. {
  394.   char temp;
  395.  
  396.   /* Since `size' does not change, we can write a while loop for each
  397.      case, and avoid testing `size' for each time.  */
  398.   switch (size)
  399.     {
  400.     /* 16-byte items happen on the DEC Alpha machine when we are not
  401.        doing sharable memory dumps.  */
  402.     case 16:
  403.       while (nitems--)
  404.         {
  405.           SWAP (p[0], p[15]);
  406.           SWAP (p[1], p[14]);
  407.           SWAP (p[2], p[13]);
  408.           SWAP (p[3], p[12]);
  409.           SWAP (p[4], p[11]);
  410.           SWAP (p[5], p[10]);
  411.           SWAP (p[6], p[9]);
  412.           SWAP (p[7], p[8]);
  413.           p += size;
  414.         }
  415.       break;
  416.  
  417.     case 8:
  418.       while (nitems--)
  419.         {
  420.           SWAP (p[0], p[7]);
  421.           SWAP (p[1], p[6]);
  422.           SWAP (p[2], p[5]);
  423.           SWAP (p[3], p[4]);
  424.           p += size;
  425.         }
  426.       break;
  427.  
  428.     case 4:
  429.       while (nitems--)
  430.         {
  431.           SWAP (p[0], p[3]);
  432.           SWAP (p[1], p[2]);
  433.           p += size;
  434.         }
  435.       break;
  436.  
  437.     case 2:
  438.       while (nitems--)
  439.         {
  440.           SWAP (p[0], p[1]);
  441.           p += size;
  442.         }
  443.       break;
  444.  
  445.     case 1:
  446.       /* Nothing to do.  */
  447.       break;
  448.  
  449.     default:
  450.       fprintf (stderr, "! I can't (un)dump a %d byte item.\n", size);
  451.       uexit (1);
  452.   }
  453. }
  454. #endif /* not WORDS_BIGENDIAN and not NO_FMTBASE_SWAP */
  455.  
  456.  
  457. /* Here we write NITEMS items, each item being ITEM_SIZE bytes long.
  458.    The pointer to the stuff to write is P, and we write to the file
  459.    OUT_FILE.  */
  460.  
  461. void
  462. do_dump (p, item_size, nitems, out_file)
  463.     char *p;
  464.     int item_size, nitems;
  465.     FILE *out_file;
  466. {
  467. #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
  468.   swap_items (p, nitems, item_size);
  469. #endif
  470.  
  471.   if (fwrite (p, item_size, nitems, out_file) != nitems)
  472.     {
  473.       fprintf (stderr, "! Could not write %d %d-byte item(s).\n",
  474.                nitems, item_size);
  475.       uexit (1);
  476.     }
  477.  
  478.   /* Have to restore the old contents of memory, since some of it might
  479.      get used again.  */
  480. #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
  481.   swap_items (p, nitems, item_size);
  482. #endif
  483. }
  484.  
  485.  
  486. /* Here is the dual of the writing routine.  */
  487.  
  488. void
  489. do_undump (p, item_size, nitems, in_file)
  490.     char *p;
  491.     int item_size, nitems;
  492.     FILE *in_file;
  493. {
  494.   if (fread (p, item_size, nitems, in_file) != nitems)
  495.     {
  496.       fprintf (stderr, "! Could not read %d %d-byte item(s).\n",
  497.                nitems, item_size);
  498.       uexit (1);
  499.     }
  500.  
  501. #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
  502.   swap_items (p, nitems, item_size);
  503. #endif
  504. }
  505.  
  506. #ifdef FUNNY_CORE_DUMP
  507. /* This procedure is due to chris@mimsy.umd.edu.  It makes a core dump
  508.    without any sort of error status (abort(2) does return an error status,
  509.    so we don't want to use that).  It is used only when making a preloaded
  510.    TeX from virtex, and is triggered by a magic file name requested as
  511.    input (see `open_input', above).  */
  512.  
  513. void
  514. funny_core_dump ()
  515. {
  516.   int pid, w;
  517.   union wait status;
  518.  
  519.   switch (pid = vfork ())
  520.     {
  521.     case -1:        /* failed */
  522.       perror ("vfork");
  523.       exit (-1);
  524.       /*NOTREACHED*/
  525.  
  526.     case 0:             /* child */
  527.        (void) signal (SIGQUIT, SIG_DFL);
  528.        (void) kill (getpid (), SIGQUIT);
  529.        (void) write (2, "how did we get here?\n", 21);
  530.        _exit (1);
  531.        /*NOTREACHED*/
  532.  
  533.     default:        /* parent */
  534.       while ((w = wait (&status)) != pid && w != -1)
  535.     ;
  536.       if (status.w_coredump)
  537.     exit (0);
  538.       (void) write (2, "attempt to dump core failed\n", 28);
  539.       exit (1);
  540.     }
  541. }
  542. #endif /* FUNNY_CORE_DUMP */
  543.  
  544. #ifdef MF
  545. /* On-line display routines for Metafont.  Here we use a dispatch table
  546.    indexed by the MFTERM or TERM environment variable to select the
  547.    graphics routines appropriate to the user's terminal.  stdout must be
  548.    connected to a terminal for us to do any graphics.  */
  549.  
  550. /* We don't want any other window routines screwing us up if we're
  551.    trying to do the trap test.  We could have written another device for
  552.    the trap test, but the terminal type conditionals in initscreen argue
  553.    against that.  */
  554.  
  555. #if defined (TRAP) || defined (INI)
  556. #undef HP2627WIN
  557. #undef NEXTWIN
  558. #undef REGISWIN
  559. #undef SUNWIN
  560. #undef XVIEWWIN
  561. #undef TEKTRONIXWIN
  562. #undef UNITERMWIN
  563. #undef X10WIN
  564. #undef X11WIN
  565. #endif /* TRAP or INI */
  566.  
  567.  
  568. #ifdef HP2627WIN
  569. extern mf_hp2627_initscreen (), mf_hp2627_updatescreen ();
  570. extern mf_hp2627_blankrectangle (), mf_hp2627_paintrow ();
  571. #endif
  572.  
  573. #ifdef NEXTWIN
  574. extern mf_next_initscreen (), mf_next_updatescreen ();
  575. extern mf_next_blankrectangle (), mf_next_paintrow ();
  576. #endif
  577.  
  578. #ifdef REGISWIN
  579. extern mf_regis_initscreen (), mf_regis_updatescreen ();
  580. extern mf_regis_blankrectangle (), mf_regis_paintrow ();
  581. #endif
  582.  
  583. #ifdef SUNWIN
  584. extern mf_sun_initscreen (), mf_sun_updatescreen ();
  585. extern mf_sun_blankrectangle (), mf_sun_paintrow ();
  586. #endif
  587.  
  588. #ifdef TEKTRONIXWIN
  589. extern mf_tektronix_initscreen (), mf_tektronix_updatescreen ();
  590. extern mf_tektronix_blankrectangle (), mf_tektronix_paintrow ();
  591. #endif
  592.  
  593. #ifdef UNITERMWIN
  594. extern mf_uniterm_initscreen (), mf_uniterm_updatescreen();
  595. extern mf_uniterm_blankrectangle(), mf_uniterm_paintrow();
  596. #endif
  597.  
  598. #ifdef X10WIN
  599. extern mf_x10_initscreen (), mf_x10_updatescreen ();
  600. extern mf_x10_blankrectangle (), mf_x10_paintrow ();
  601. #endif
  602.  
  603. #ifdef X11WIN
  604. extern mf_x11_initscreen (), mf_x11_updatescreen ();
  605. extern mf_x11_blankrectangle (), mf_x11_paintrow ();
  606. #endif
  607.  
  608.  
  609. /* This variable, `mfwsw', contains the dispatch tables for each
  610.    terminal.  We map the Pascal calls to the routines `init_screen',
  611.    `update_screen', `blank_rectangle', and `paint_row' into the
  612.    appropriate entry point for the specific terminal that MF is being
  613.    run on.  */
  614.  
  615. struct mfwin_sw
  616. {
  617.   char *mfwsw_type;        /* Name of terminal a la TERMCAP.  */
  618.   int (*mfwsw_initscreen) ();
  619.   int (*mfwsw_updatescrn) ();
  620.   int (*mfwsw_blankrect) ();
  621.   int (*mfwsw_paintrow) ();
  622. } mfwsw[] =
  623. {
  624. #ifdef HP2627WIN
  625.   { "hp2627", mf_hp2627_initscreen, mf_hp2627_updatescreen,
  626.     mf_hp2627_blankrectangle, mf_hp2627_paintrow },
  627. #endif
  628.  
  629. #ifdef NEXTWIN
  630.   { "next", mf_next_initscreen, mf_next_updatescreen,
  631.     mf_next_blankrectangle, mf_next_paintrow },
  632. #endif
  633.  
  634. #ifdef REGISWIN
  635.   { "regis", mf_regis_initscreen, mf_regis_updatescreen,
  636.     mf_regis_blankrectangle, mf_regis_paintrow },
  637. #endif
  638.  
  639. #ifdef SUNWIN
  640.   { "sun", mf_sun_initscreen, mf_sun_updatescreen,
  641.     mf_sun_blankrectangle, mf_sun_paintrow },
  642. #endif
  643.  
  644. #ifdef TEKTRONIXWIN
  645.   { "tek", mf_tektronix_initscreen, mf_tektronix_updatescreen,
  646.     mf_tektronix_blankrectangle, mf_tektronix_paintrow },
  647. #endif
  648.  
  649. #ifdef UNITERMWIN
  650.    { "uniterm", mf_uniterm_initscreen, mf_uniterm_updatescreen,
  651.      mf_uniterm_blankrectangle, mf_uniterm_paintrow },
  652. #endif
  653.  
  654. #ifdef X10WIN
  655.   { "xterm", mf_x10_initscreen, mf_x10_updatescreen,
  656.     mf_x10_blankrectangle, mf_x10_paintrow },
  657. #endif
  658.  
  659. #ifdef X11WIN
  660.   { "xterm", mf_x11_initscreen, mf_x11_updatescreen, 
  661.     mf_x11_blankrectangle, mf_x11_paintrow },
  662. #endif
  663.  
  664. /* Finally, we must have an entry with a terminal type of NULL.  */
  665.   { NULL, NULL, NULL, NULL, NULL }
  666.  
  667. }; /* End of the array initialization.  */
  668.  
  669.  
  670. /* This is a pointer to the mfwsw[] entry that we find.  */
  671. static struct mfwin_sw *mfwp;
  672.  
  673. /* The following are routines that just jump to the correct
  674.    terminal-specific graphics code. If none of the routines in the
  675.    dispatch table exist, or they fail, we produce trap-compatible
  676.    output, i.e., the same words and punctuation that the unchanged
  677.    mf.web would produce.  */
  678.  
  679.  
  680. /* This returns true if we can do window operations, else false.  */
  681.  
  682. boolean
  683. initscreen ()
  684. {
  685. #ifndef TRAP
  686.   /* If MFTERM is set, use it.  */
  687.   char *ttytype = getenv ("MFTERM");
  688.   
  689.   if (ttytype == NULL)
  690.     { /* If DISPLAY is set, we are X11; otherwise, who knows.  */
  691.       boolean have_display = getenv ("DISPLAY") != NULL;
  692.       ttytype = have_display ? "xterm" : getenv ("TERM");
  693.     }
  694.  
  695.   /* If we don't know kind of terminal this is, or if Metafont isn't
  696.       being run interactively, don't do any online output.  */
  697.   if (ttytype == NULL || !isatty (fileno (stdout)))
  698.     return 0;
  699.  
  700.   /* Test each of the terminals given in `mfwsw' against the terminal
  701.      type, and take the first one that matches, or if the user is running
  702.      under Emacs, the first one.  */
  703.   for (mfwp = mfwsw; mfwp->mfwsw_type != NULL; mfwp++)
  704.     if (!strncmp (mfwp->mfwsw_type, ttytype, strlen (mfwp->mfwsw_type))
  705.     || !strcmp (ttytype, "emacs"))
  706.       if (mfwp->mfwsw_initscreen)
  707.     return ((*mfwp->mfwsw_initscreen) ());
  708.       else
  709.     {
  710.       fprintf (stderr,
  711.                    "! Couldn't initialize the online display for a `%s'.\n",
  712.                    ttytype);
  713.       return 1;
  714.     }
  715.   
  716.   /* The current terminal type wasn't found in any of the entries, so
  717.      silently give up, assuming that the user isn't on a terminal that
  718.      supports graphic output.  */
  719.   return 0;
  720. #else /* TRAP */
  721.   return 1;
  722. #endif /* TRAP */
  723. }
  724.  
  725.  
  726. /* Make sure everything is visible.  */
  727.  
  728. void
  729. updatescreen ()
  730. {
  731. #ifndef TRAP
  732.   if (mfwp->mfwsw_updatescrn)
  733.     ((*mfwp->mfwsw_updatescrn) ());
  734.   else
  735.     {
  736.       printf ("Updatescreen called\n");
  737.     }
  738. #else /* TRAP */
  739.   fprintf (logfile, "Calling UPDATESCREEN\n");
  740. #endif /* TRAP */
  741. }
  742.  
  743.  
  744. /* This sets the rectangle bounded by ([left,right], [top,bottom]) to
  745.    the background color.  */
  746.  
  747. void
  748. blankrectangle (left, right, top, bottom)
  749.      screencol left, right;
  750.      screenrow top, bottom;
  751. {
  752. #ifndef TRAP
  753.   if (mfwp->mfwsw_blankrect)
  754.     ((*mfwp->mfwsw_blankrect) (left, right, top, bottom));
  755.   else
  756.     {
  757.       printf ("Blankrectangle l=%d  r=%d  t=%d  b=%d\n",
  758.           left, right, top, bottom);
  759.     }
  760. #else /* TRAP */
  761.   fprintf (logfile, "\nCalling BLANKRECTANGLE(%d,%d,%d,%d)\n", left,
  762.        right, top, bottom);
  763. #endif /* TRAP */
  764. }
  765.  
  766.  
  767. /* This paints ROW, starting with the color INIT_COLOR. 
  768.    TRANSITION_VECTOR then specifies the length of the run; then we
  769.    switch colors.  This goes on for VECTOR_SIZE transitions.  */
  770.  
  771. void
  772. paintrow (row, init_color, transition_vector, vector_size)
  773.      screenrow row;
  774.      pixelcolor init_color;
  775.      transspec transition_vector;
  776.      screencol vector_size;
  777. {
  778. #ifndef TRAP
  779.   if (mfwp->mfwsw_paintrow)
  780.     ((*mfwp->mfwsw_paintrow) (row, init_color,
  781.                   transition_vector, vector_size));
  782.   else
  783.     {
  784.       printf ("Paintrow r=%d  c=%d  v=", row, init_color);
  785.       while (vector_size-- > 0)
  786.     printf ("%d  ", transition_vector++);
  787.       printf ("\n");
  788.     }
  789. #else /* TRAP */
  790.   unsigned k;
  791.  
  792.   fprintf (logfile, "Calling PAINTROW(%d,%d;", row, init_color);
  793.   for (k = 0; k <= vector_size; k++)
  794.     {
  795.       fprintf (logfile, "%d", transition_vector[k]);
  796.       if (k != vector_size)
  797.     fprintf (logfile, ",");
  798.     }
  799.   fprintf (logfile, ")\n");
  800. #endif /* TRAP */
  801. }
  802. #endif /* MF */
  803.