home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / tex / tex31 / texsrc.lzh / COMMON.LZH / TEXMF.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-01-13  |  15.6 KB  |  647 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.  The
  3.    file-opening routines are also used by BibTeX.  */
  4.  
  5. /* Either `texd.h' or `mfd.h' will include `../common/texmf.h'.  */
  6.  
  7. /* Instantiate data in `texd.h' or `mfd.h' here.  */
  8. #define    EXTERN
  9.  
  10. #ifdef TeX
  11. #include "texd.h"
  12. #define dump_default_var TEXformatdefault
  13. #define dump_default " plain.fmt"
  14. #define dump_format " %s.fmt"
  15. #define dump_ext_length 4
  16. #define dump_default_length formatdefaultlength
  17. #define virgin_program "virtex"
  18. #define main_program texbody
  19. #define edit_value tex_edit_value
  20. #define edit_var "TEXEDIT"
  21. #else /* not TeX */
  22. #include "mfd.h"
  23. #define dump_default_var MFbasedefault
  24. #define dump_default " plain.base"
  25. #define dump_format " %s.base"
  26. #define dump_ext_length 5
  27. #define dump_default_length basedefaultlength
  28. #define virgin_program "virmf"
  29. #define main_program main_body
  30. #define edit_value mf_edit_value
  31. #define edit_var "MFEDIT"
  32. #endif /* not TeX */
  33.  
  34. /* Catch interrupts.  */
  35. #define    HANDLE_INTERRUPTS
  36.  
  37. #ifdef HANDLE_INTERRUPTS
  38. #ifdef _POSIX_SOURCE
  39. #include <sys/types.h>
  40. #endif
  41. #include <signal.h>
  42. #endif
  43.  
  44. #ifdef BSD
  45. void funny_core_dump ();
  46. #include <sys/time.h>
  47. #include <sys/wait.h>
  48. #include <sys/file.h>
  49. #include <fcntl.h>
  50. #else
  51. #include <time.h>
  52. #endif
  53.  
  54. #if defined (BSD) || defined (SYSV)
  55. #include <sgtty.h>
  56. #endif
  57.  
  58. extern long time ();
  59. extern struct tm *localtime ();
  60.  
  61.  
  62.  
  63. #ifdef atarist
  64. int _stksize = -1L;
  65. #endif
  66.  
  67. /* The main program, etc.  */
  68.  
  69. /* What we were invoked as and with.  */
  70. static char *program_name = NULL;
  71. static int gargc;
  72. static char **gargv;
  73.  
  74.  
  75. /* The entry point: set up for reading the command line, which will
  76.    happen in `topenin', then call the main body.  */
  77.  
  78. void
  79. main (ac, av)
  80.   int ac;
  81.   char *av[];
  82. {
  83.   char custom_default[FILENAMESIZE];
  84.  
  85.   gargc = ac;
  86.   gargv = av;
  87.  
  88. #ifdef atarist
  89.   if (!getenv ("UNIXMODE"))
  90.     _set_unixmode ("dr/");
  91.   _binmode (1);            /* Make sure to open all files in */
  92.                 /* binary mode */
  93. #endif
  94.  
  95.   dump_default_var = dump_default;
  96.   dump_default_length = strlen (dump_default + 1);
  97.  
  98. #ifndef INI
  99.   if (readyalready != 314159)
  100.     {
  101.       program_name = rindex (av[0], '/');
  102.       if (program_name == NULL)
  103.     program_name = av[0];
  104.       else
  105.     program_name++;
  106.       if (strcmp (program_name, virgin_program) != 0)
  107.         {
  108.           /* TeX or Metafont adds the space at the end of the name.  */
  109.           (void) sprintf (custom_default, dump_format, program_name);
  110.           dump_default_var = custom_default;
  111.           dump_default_length = strlen (program_name) + dump_ext_length;
  112.         }
  113.     }
  114. #endif /* not INI */
  115.  
  116.   main_program ();
  117.   /*NOTREACHED*/
  118.  
  119.  
  120. /* This is supposed to ``open the terminal for input'', but what we
  121.    really do is copy command line arguments into TeX's or Metafont's
  122.    buffer, so they can handle them.  If nothing is available, or we've
  123.    been called already (and hence, gargc==0), we return with
  124.    `last=first'.  */
  125.  
  126. void
  127. topenin ()
  128. {
  129.   register int i;
  130.  
  131.   buffer[first] = 0;    /* So the first `strcat' will work.  */
  132.  
  133.   if (gargc > 1)
  134.     { /* We have command line arguments.  */
  135.       for (i = 1; i < gargc; i++)
  136.         {
  137.       (void) strcat ((char *) &buffer[first], gargv[i]);
  138.           (void) strcat ((char *) &buffer[first], " ");
  139.     }
  140.       gargc = 0;    /* Don't do this again.  */
  141.     }
  142.  
  143.   /* Make `last' be one past the last non-blank character in `buffer'.  */
  144.   for (last = first; buffer[last]; ++last)
  145.     ;
  146.   for (--last; last >= first && buffer[last] == ' '; --last)
  147.     ;
  148.   last++;
  149. }
  150.  
  151.  
  152.  
  153. #ifdef HANDLE_INTERRUPTS
  154. /* All our interrupt handler has to do is set TeX's or Metafont's global
  155.    variable `interrupt'; then they will do everything needed.  */
  156.  
  157. static void
  158. interrupt_handler ()
  159. {
  160.   interrupt = 1;
  161.   (void) signal (SIGINT, interrupt_handler);
  162. }
  163. #endif /* HANDLE_INTERRUPTS */
  164.  
  165.  
  166. /* Besides getting the date and time here, we also set up the interrupt
  167.    handler, for no particularly good reason.  It's just that since the
  168.    `fix_date_and_time' routine is called early on (section 1337 in TeX,
  169.    ``Get the first line of input and prepare to start''), this is as
  170.    good a place as any.  */
  171.  
  172. void
  173. get_date_and_time (minutes, day, month, year)
  174.   integer *minutes, *day, *month, *year;
  175. {
  176.   long clock;
  177.   struct tm *tmptr;
  178.  
  179.   clock = time ((long *) 0);
  180.   tmptr = localtime (&clock);
  181.  
  182.   *minutes = tmptr->tm_hour * 60 + tmptr->tm_min;
  183.   *day = tmptr->tm_mday;
  184.   *month = tmptr->tm_mon + 1;
  185.   *year = tmptr->tm_year + 1900;
  186.  
  187. #ifdef HANDLE_INTERRUPTS
  188.   {
  189.     SIGNAL_HANDLER_RETURN_TYPE (*old_handler) ();
  190.  
  191.     if ((old_handler = signal (SIGINT, interrupt_handler)) != SIG_DFL)
  192.       (void) signal (SIGINT, old_handler);
  193.   }
  194. #endif
  195. }
  196.  
  197.  
  198.  
  199. /* I/O for TeX and Metafont.  */
  200.  
  201. /* Read a line of input as efficiently as possible while still looking
  202.    like Pascal.  We set `last' to `first' and return `false' if we get
  203.    to eof.  Otherwise, we return `true' and either `last==first' or
  204.    `buffer[last-1]!=' ''; that is, last == first + length(line except
  205.    trailing whitespace).  */
  206.  
  207. boolean
  208. input_line (f)
  209.   FILE *f;
  210. {
  211.   register int i;
  212.  
  213.   last = first;
  214.  
  215. #ifdef BSD
  216.   if (f == stdin) clearerr (stdin);
  217. #endif
  218.  
  219.   while (last < bufsize && (i = getc (f)) != EOF && i != '\n') 
  220.     buffer[last++] = i;
  221.  
  222.   if (i == '\n' && buffer[last-1] == '\r')
  223.     last--;
  224.   if (i == EOF && last == first)
  225.       return false;
  226.  
  227.   /* We didn't get the whole line because our buffer was too small.  */
  228.   if (i != EOF && i != '\n')
  229.     {
  230.       (void) fprintf (stderr, "! Unable to read an entire line---bufsize=%d.\n", bufsize);
  231.       (void) fprintf (stderr, "Please ask a wizard to enlarge me.\n");
  232.       exit (1);
  233.     }
  234.  
  235.   buffer[last] = ' ';
  236.   if (last >= maxbufstack)
  237.     maxbufstack = last;
  238.  
  239.   /* Trim trailing whitespace.  */
  240.   while (last > first && (buffer[last-1] == ' ' || buffer[last-1] == '\t'))
  241.     --last;
  242.  
  243.   /* Now, either `last==first' or `buffer[last-1] != ' '' (or \t). */
  244.  
  245.   /* Don't bother using xord if we don't need to.  */
  246. #ifdef NONASCII
  247.   for (i = first; i <= last; i++)
  248.      buffer[i] = xord[buffer[i]];
  249. #endif
  250.  
  251.     return true;
  252. }
  253.  
  254.  
  255. #ifdef BSD
  256. /* Clear any pending terminal input.  The usual way to do this in Unix
  257.   is to switch the terminal to get the current tty flags, set RAW mode,
  258.   then switch back to the original setting.  If the user isn't in COOKED
  259.   mode, though, this won't work.  At least, it leaves his terminal in
  260.   its original mode.  */
  261.  
  262. void
  263. bsd_clear_terminal ()
  264. {
  265.   int arg = FREAD;
  266.   (void) ioctl (fileno (stdout), TIOCFLUSH, &arg);
  267. }
  268.  
  269.  
  270. /* Cancel any output cancellation (^O) by the user.  */
  271.  
  272. void
  273. bsd_wake_up_terminal ()
  274. {
  275.   int i = LFLUSHO;
  276.   (void) ioctl (fileno (stdout), TIOCLBIC, (struct sgttyb *) &i);
  277. }
  278.  
  279. #endif /* BSD */
  280.  
  281.  
  282.  
  283. /* This string specifies what the `e' option does in response to an
  284.    error message.  */ 
  285. static char *edit_value = EDITOR;
  286.  
  287. /* This procedure is due to sjc@s1-c.  TeX (or Metafont) calls it when
  288.    the user types `e' in response to an error, invoking a text editor on
  289.    the erroneous source file.  FNSTART is how far into FILENAME the
  290.    actual filename starts; FNLENGTH is how long the filename is.
  291.    
  292.    See ../site.h for how to set the default, and how to override it.  */
  293.  
  294. void
  295. calledit (filename, fnstart, fnlength, linenumber)
  296.   ASCIIcode *filename;
  297.   poolpointer fnstart;
  298.   integer fnlength, linenumber;
  299. {
  300.   char *temp, *command;
  301.   char c;
  302.   int sdone, ddone, i;
  303.  
  304.   sdone = ddone = 0;
  305.   filename += fnstart;
  306.  
  307.   /* Close any open input files, since we're going to kill the job.  */
  308.   for (i = 1; i <= inopen; i++)
  309.     (void) fclose (inputfile[i]);
  310.  
  311.   /* Replace the default with the value of the appropriate environment
  312.      variable, if it's set.  */
  313.   temp = getenv (edit_var);
  314.   if (temp != NULL)
  315.     edit_value = temp;
  316.  
  317.   /* Construct the command string.  The `11' is the maximum length an
  318.      integer might be.  */
  319.   command = xmalloc ((unsigned) (strlen (edit_value) + fnlength + 11));
  320.  
  321.   /* So we can construct it as we go.  */
  322.   temp = command;
  323.  
  324.   while ((c = *edit_value++) != 0)
  325.     {
  326.       if (c == '%')
  327.         {
  328.           switch (c = *edit_value++)
  329.             {
  330.         case 'd':
  331.           if (ddone)
  332.                 {
  333.           (void) fprintf (stderr, "! `%%d' cannot appear twice in editor command.\n");
  334.               exit (1);
  335.         }
  336.               (void) sprintf (temp, "%d", linenumber);
  337.               while (*temp != '\0')
  338.                 temp++;
  339.               ddone = 1;
  340.               break;
  341.  
  342.         case 's':
  343.               if (sdone)
  344.                 {
  345.               (void) fprintf(stderr, "! `%%s' cannot appear twice in editor command.\n");
  346.           exit (1);
  347.         }
  348.               for (i =0; i < fnlength; i++)
  349.         *temp++ = Xchr (filename[i]);
  350.               sdone = 1;
  351.               break;
  352.  
  353.         case '\0':
  354.               *temp++ = '%';
  355.               /* Back up to the null to force termination.  */
  356.           edit_value--;
  357.           break;
  358.  
  359.         default:
  360.           *temp++ = '%';
  361.           *temp++ = c;
  362.           break;
  363.         }
  364.     }
  365.       else
  366.     *temp++ = c;
  367.     }
  368.  
  369.   *temp = 0;
  370.  
  371.   /* Execute the command.  */
  372.   if (system (command) != 0)
  373.     (void) fprintf(stderr, "! Trouble executing `%s'.\n", command);
  374.  
  375.   /* Quit, since we found an error.  */
  376.   exit (1);
  377. }
  378.  
  379.  
  380.  
  381. #ifdef BSD
  382. /* This procedure is due to chris@mimsy.umd.edu.  It makes a core dump
  383.    without any sort of error status (abort(2) does give an error status,
  384.    so we don't want to use that).  It is used only when making a preloaded
  385.    TeX from virtex, and is triggered by a magic file name requested as
  386.    input (see `open_input', above).
  387.  
  388.    This is what is known in computing circles as a hack.  */
  389.  
  390. void
  391. funny_core_dump ()
  392. {
  393.   int pid, w;
  394.   union wait status;
  395.  
  396.   switch (pid = vfork ())
  397.     {
  398.     case -1:        /* failed */
  399.       perror ("vfork");
  400.       exit (-1);
  401.       /*NOTREACHED*/
  402.  
  403.     case 0:             /* child */
  404.        (void) signal (SIGQUIT, SIG_DFL);
  405.        (void) kill (getpid (), SIGQUIT);
  406.        (void) write (2, "how did we get here?\n", 21);
  407.        _exit(1);
  408.        /*NOTREACHED*/
  409.  
  410.     default:        /* parent */
  411.       while ((w = wait (&status)) != pid && w != -1)
  412.     ;
  413.       if (status.w_coredump)
  414.     exit (0);
  415.       (void) write (2, "attempt to dump core failed\n", 28);
  416.       exit (1);
  417.     }
  418. }
  419. #endif /* BSD */
  420.  
  421.  
  422.  
  423. #ifndef TeX
  424. /* On-line display routines for Metafont.  Here we use a dispatch table
  425.    indexed by the TERM environment variable to select the graphics
  426.    routines appropriate to the user's terminal.  stdout must be
  427.    connected to a terminal for us to do any graphics.  */
  428.  
  429. /* We don't want any other window routines screwing us up if we're
  430.    trying to do the trap test.  We could have written another device for
  431.    the trap test, but the terminal type conditionals in initscreen argue
  432.    against that.  */
  433.  
  434. #ifdef TRAP
  435. #undef SUNWIN
  436. #undef HP2627WIN
  437. #undef X10WIN
  438. #undef X11WIN
  439. #undef TEKTRONIXWIN
  440. #endif
  441.  
  442.  
  443. #ifdef HP2627WIN
  444. extern mf_hp2627_initscreen (), mf_hp2627_updatescreen ();
  445. extern mf_hp2627_blankrectangle (), mf_hp2627_paintrow ();
  446. #endif
  447.  
  448. #ifdef SUNWIN
  449. extern mf_sun_initscreen (), mf_sun_updatescreen ();
  450. extern mf_sun_blankrectangle (), mf_sun_paintrow ();
  451. #endif
  452.  
  453. #ifdef TEKTRONIXWIN
  454. extern mf_tektronix_initscreen (), mf_tektronix_updatescreen ();
  455. extern mf_tektronix_blankrectangle (), mf_tektronix_paintrow ();
  456. #endif
  457.  
  458. #ifdef UNITERMWIN
  459. extern mf_uniterm_initscreen (), mf_uniterm_updatescreen();
  460. extern mf_uniterm_blankrectangle(), mf_uniterm_paintrow();
  461. #endif
  462.  
  463. #ifdef X10WIN
  464. extern mf_x10_initscreen (), mf_x10_updatescreen ();
  465. extern mf_x10_blankrectangle (), mf_x10_paintrow ();
  466. #endif
  467.  
  468. #ifdef X11WIN
  469. extern mf_x11_initscreen (), mf_x11_updatescreen ();
  470. extern mf_x11_blankrectangle (), mf_x11_paintrow ();
  471. #endif
  472.  
  473.  
  474. /* `mfwsw' contains the dispatch tables for each terminal.  We map the
  475.    Pascal calls to the routines `init_screen', `update_screen',
  476.    `blank_rectangle', and `paint_row' into the appropriate entry point
  477.    for the specific terminal that MF is being run on.  */
  478.  
  479. struct mfwin_sw
  480. {
  481.   char *mfwsw_type;        /* Name of terminal a la TERMCAP.  */
  482.   int (*mfwsw_initscreen) ();
  483.   int (*mfwsw_updatescrn) ();
  484.   int (*mfwsw_blankrect) ();
  485.   int (*mfwsw_paintrow) ();
  486. } mfwsw[] =
  487.  
  488. /* Now we have a long structure which initializes this array of
  489.    ``Metafont window switches''.  */
  490.  
  491. {
  492.  
  493. #ifdef HP2627WIN
  494.   { "hp2627", mf_hp2627_initscreen, mf_hp2627_updatescreen,
  495.     mf_hp2627_blankrectangle, mf_hp2627_paintrow },
  496. #endif
  497.  
  498. #ifdef SUNWIN
  499.   { "sun", mf_sun_initscreen, mf_sun_updatescreen,
  500.     mf_sun_blankrectangle, mf_sun_paintrow },
  501. #endif
  502.  
  503. #ifdef TEKTRONIXWIN
  504.   { "tek", mf_tektronix_initscreen, mf_tektronix_updatescreen,
  505.     mf_tektronix_blankrectangle, mf_tektronix_paintrow },
  506. #endif
  507.  
  508. #ifdef UNITERMWIN
  509.    { "uniterm", mf_uniterm_initscreen, mf_uniterm_updatescreen,
  510.      mf_uniterm_blankrectangle, mf_uniterm_paintrow },
  511. #endif
  512.  
  513. #ifdef X10WIN
  514.   { "xterm", mf_x10_initscreen, mf_x10_updatescreen,
  515.     mf_x10_blankrectangle, mf_x10_paintrow },
  516. #endif
  517.  
  518. #ifdef X11WIN
  519.   { "xterm", mf_x11_initscreen, mf_x11_updatescreen, 
  520.     mf_x11_blankrectangle, mf_x11_paintrow },
  521. #endif
  522.  
  523.   { "Irrelevant", NULL, NULL, NULL, NULL },
  524.  
  525. /* Finally, we must have an entry with a terminal type of NULL.  */
  526.   { NULL, NULL, NULL, NULL, NULL }
  527.  
  528. }; /* End of the array initialization.  */
  529.  
  530.  
  531. /* This is a pointer to current mfwsw[] entry.  */
  532. static struct mfwin_sw *mfwp;
  533.  
  534. /* The following are routines that just jump to the correct
  535.    terminal-specific graphics code. If none of the routines in the
  536.    dispatch table exist, or they fail, we produce trap-compatible
  537.    output, i.e., the same words and punctuation that the unchanged
  538.    mf.web would produce.  */
  539.  
  540.  
  541. /* This returns true if window operations legal, else false.  */
  542.  
  543. boolean
  544. initscreen ()
  545. {
  546. #ifndef TRAP
  547.   register char *ttytype;
  548.  
  549.   if ((ttytype = getenv ("TERM")) == NULL || !(isatty (fileno (stdout))))
  550.     return (0);
  551.   for (mfwp = mfwsw; mfwp->mfwsw_type != NULL; mfwp++)
  552.     if (!strncmp (mfwp->mfwsw_type, ttytype, strlen (mfwp->mfwsw_type))
  553.     || !strcmp (ttytype, "emacs"))
  554.       if (mfwp->mfwsw_initscreen)
  555.     return ((*mfwp->mfwsw_initscreen) ());
  556.       else
  557.     {            /* Test terminal type */
  558.       printf ("Could not init_screen for `%s'.\n", ttytype);
  559.       return 1;
  560.     }
  561.   return 0;
  562.  
  563. #else /* TRAP */
  564.   return 1;
  565. #endif
  566. }
  567.  
  568.  
  569. /* Make sure everything is visible.  */
  570.  
  571. void
  572. updatescreen ()
  573. {
  574. #ifndef TRAP
  575.   if (mfwp->mfwsw_updatescrn)
  576.     ((*mfwp->mfwsw_updatescrn) ());
  577.   else
  578.     {
  579.       printf ("Updatescreen called\n");
  580.     }
  581. #else /* TRAP */
  582.   fprintf (logfile, "Calling UPDATESCREEN\n");
  583. #endif
  584. }
  585.  
  586.  
  587. /* This sets the rectangle bounded by ([left,right], [top,bottom]) to
  588.    the background color.  */
  589.  
  590. void
  591. blankrectangle (left, right, top, bottom)
  592.      screencol left, right;
  593.      screenrow top, bottom;
  594. {
  595. #ifndef TRAP
  596.   if (mfwp->mfwsw_blankrect)
  597.     ((*mfwp->mfwsw_blankrect) (left, right, top, bottom));
  598.   else
  599.     {
  600.       printf ("Blankrectangle l=%d  r=%d  t=%d  b=%d\n",
  601.           left, right, top, bottom);
  602.     }
  603. #else /* TRAP */
  604.   fprintf (logfile, "\nCalling BLANKRECTANGLE(%d,%d,%d,%d)\n", left,
  605.        right, top, bottom);
  606. #endif
  607. }
  608.  
  609.  
  610. /* This paints ROW, starting with the color INIT_COLOR. 
  611.    TRANSITION_VECTOR then specifies the length of the run; then we
  612.    switch colors.  This goes on for VECTOR_SIZE transitions.  */
  613.  
  614. void
  615. paintrow (row, init_color, transition_vector, vector_size)
  616.      screenrow row;
  617.      pixelcolor init_color;
  618.      transspec transition_vector;
  619.      screencol vector_size;
  620. {
  621. #ifndef TRAP
  622.   if (mfwp->mfwsw_paintrow)
  623.     ((*mfwp->mfwsw_paintrow) (row, init_color,
  624.                   transition_vector, vector_size));
  625.   else
  626.     {
  627.       printf ("Paintrow r=%d  c=%d  v=");
  628.       while (vector_size-- > 0)
  629.     printf ("%d  ", transition_vector++);
  630.       printf ("\n");
  631.     }
  632. #else /* TRAP */
  633.   unsigned k;
  634.  
  635.   fprintf (logfile, "Calling PAINTROW(%d,%d;", row, init_color);
  636.   for (k = 0; k <= vector_size; k++)
  637.     {
  638.       fprintf (logfile, "%d", transition_vector[k]);
  639.       if (k != vector_size)
  640.     fprintf (logfile, ",");
  641.     }
  642.   fprintf (logfile, ")\n");
  643. #endif
  644. }
  645. #endif /* not TeX */
  646.