home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / tex / texsrc1 / Src / lib / c / texmf < prev    next >
Encoding:
Text File  |  1993-05-09  |  21.1 KB  |  808 lines

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