home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume2 / accell-text / Part1 next >
Encoding:
Internet Message Format  |  1991-08-07  |  60.6 KB

  1. From: ustel@well.UUCP (Mark Hargrove)
  2. Newsgroups: comp.sources.misc
  3. Subject: v02i050: Unify TEXT fields from ACCELL Part 1/5
  4. Message-ID: <7218@ncoast.UUCP>
  5. Date: 11 Feb 88 00:43:57 GMT
  6. Approved: allbery@ncoast.UUCP
  7.  
  8. Comp.sources.misc: Volume 2, Issue 50
  9. Submitted-By: "Mark Hargrove" <ustel@well.UUCP>
  10. Archive-Name: accell-text/Part1
  11.  
  12. [Sendlist gave me a size warning; this may get truncated.  ++bsa]
  13.  
  14.     The following collection of stuff allows you to access
  15.     and use UNIFY Text (and by extension, Binary)  fields
  16.     from within the Accell environment.  Also included is
  17.     a deliberately crippled version of micro-gnu emacs that
  18.     has been mangled into presenting a very Accell-like
  19.     "look and feel" to the user.  On an NCR Tower, the resulting
  20.     executable is only about 55K.  For casual users, this
  21.     has turned out to be a better editor than say, vi or
  22.     ed :-)  As with UNIFY, your choice of editors is 
  23.     available via the EDIT environment variable.
  24.  
  25.     The C-hooks which write the text out to the database 
  26.     HAVE been modified to work around the recently discovered
  27.     (and rather gruesome) UNIFY bug which frequently led to
  28.     corruption of file.dbv.  Remember that using ENTER to 
  29.     edit a text field WILL STILL CAUSE CORRUPTION OF FILE.DBV.
  30.  
  31.     [If you don't know about this bug and you are using text
  32.      fields from either C or via ENTER -- call Unify TS TODAY
  33.      and get a description of the problem ]
  34.  
  35.     Bug reports would be appreciated.
  36.     
  37.         -Mark Hargrove
  38.  
  39. #!/bin/sh
  40. # to extract, remove the header and type "sh filename"
  41. if `test ! -s ./region.c`
  42. then
  43. echo "writing ./region.c"
  44. cat > ./region.c << '\Rogue\Monster\'
  45. /*
  46.  *        Region based commands.
  47.  * The routines in this file
  48.  * deal with the region, that magic space
  49.  * between "." and mark. Some functions are
  50.  * commands. Some functions are just for
  51.  * internal use.
  52.  */
  53. #include    "def.h"
  54.  
  55. /*
  56.  * Kill the region. Ask "getregion"
  57.  * to figure out the bounds of the region.
  58.  * Move "." to the start, and kill the characters.
  59.  */
  60. /*ARGSUSED*/
  61. killregion(f, n, k)
  62. {
  63.     register int    s;
  64.     REGION        region;
  65.  
  66.     if ((s=getregion(®ion)) != TRUE)
  67.         return (s);
  68.     if ((lastflag&CFKILL) == 0)        /* This is a kill type    */
  69.         kdelete();            /* command, so do magic    */
  70.     thisflag |= CFKILL;            /* kill buffer stuff.    */
  71.     curwp->w_dotp = region.r_linep;
  72.     curwp->w_doto = region.r_offset;
  73.     return (ldelete(region.r_size, KFORW));
  74. }
  75.  
  76.  
  77. /*
  78.  * This routine figures out the bound of the region
  79.  * in the current window, and stores the results into the fields
  80.  * of the REGION structure. Dot and mark are usually close together,
  81.  * but I don't know the order, so I scan outward from dot, in both
  82.  * directions, looking for mark. The size is kept in a long. At the
  83.  * end, after the size is figured out, it is assigned to the size
  84.  * field of the region structure. If this assignment loses any bits,
  85.  * then we print an error. This is "type independent" overflow
  86.  * checking. All of the callers of this routine should be ready to
  87.  * get an ABORT status, because I might add a "if regions is big,
  88.  * ask before clobberring" flag.
  89.  */
  90. getregion(rp) register REGION *rp;
  91. {
  92.     register LINE    *flp;
  93.     register LINE    *blp;
  94.     register long    fsize;            /* Long now.        */
  95.     register long    bsize;
  96.  
  97.     if (curwp->w_markp == NULL)
  98.     {
  99.         ewprintf("No mark set in this window");
  100.         return (FALSE);
  101.     }
  102.     if (curwp->w_dotp == curwp->w_markp)
  103.     {    /* "r_size" always ok.    */
  104.         rp->r_linep = curwp->w_dotp;
  105.         if (curwp->w_doto < curwp->w_marko)
  106.         {
  107.             rp->r_offset = curwp->w_doto;
  108.             rp->r_size = (RSIZE) (curwp->w_marko-curwp->w_doto);
  109.         }
  110.         else
  111.         {
  112.             rp->r_offset = curwp->w_marko;
  113.             rp->r_size = (RSIZE) (curwp->w_doto-curwp->w_marko);
  114.         }
  115.         return (TRUE);
  116.     }
  117.     blp = curwp->w_dotp;            /* Get region size.    */
  118.     flp = curwp->w_dotp;
  119.     bsize = curwp->w_doto;
  120.     fsize = llength(flp)-curwp->w_doto+1;
  121.     while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep)
  122.     {
  123.         if (flp != curbp->b_linep)
  124.         {
  125.             flp = lforw(flp);
  126.             if (flp == curwp->w_markp)
  127.             {
  128.                 rp->r_linep = curwp->w_dotp;
  129.                 rp->r_offset = curwp->w_doto;
  130.                 return (setsize(rp,
  131.                     (RSIZE) (fsize+curwp->w_marko)));
  132.             }
  133.             fsize += llength(flp)+1;
  134.         }
  135.         if (lback(blp) != curbp->b_linep)
  136.         {
  137.             blp = lback(blp);
  138.             bsize += llength(blp)+1;
  139.             if (blp == curwp->w_markp)
  140.             {
  141.                 rp->r_linep = blp;
  142.                 rp->r_offset = curwp->w_marko;
  143.                 return (setsize(rp,
  144.                     (RSIZE) (bsize-curwp->w_marko)));
  145.             }
  146.         }
  147.     }
  148.     ewprintf("Bug: lost mark");        /* Gak!            */
  149.     return (FALSE);
  150. }
  151.  
  152. /*
  153.  * Set size, and check for overflow.
  154.  */
  155. setsize(rp, size)
  156.    register REGION *rp;
  157.    register RSIZE size;
  158. {
  159.  
  160.     rp->r_size = size;
  161.     if (rp->r_size != size)
  162.     {
  163.         ewprintf("Region is too large");
  164.         return (FALSE);
  165.     }
  166.     return (TRUE);
  167. }
  168.  
  169. #ifdef    PREFIXREGION
  170. /*
  171.  * Implements one of my favorite keyboard macros; put a string at the
  172.  * beginning of a number of lines in a buffer.  The quote string is
  173.  * settable by using set-prefix-string.  Great for quoting mail, which
  174.  * is the real reason I wrote it, but also has uses for creating bar
  175.  * comments (like the one you're reading) in C code.
  176.  */
  177.  
  178. #define PREFIXLENGTH 40
  179. static char prefix_string[PREFIXLENGTH] = { '>', '\0' };
  180.  
  181. /*
  182.  * Prefix the region with whatever is in prefix_string.
  183.  * Leaves dot at the beginning of the line after the end
  184.  * of the region.  If an argument is given, prompts for the
  185.  * line prefix string.
  186.  */
  187.  
  188. /*ARGSUSED*/
  189. prefixregion(f, n, k)
  190. {
  191.     register int    s;
  192.     register LINE    *first, *last;
  193.     register int    nline;
  194.     REGION        region;
  195.     char        *prefix = prefix_string;
  196.  
  197.     if ((f == TRUE) && ((s = setprefix(FALSE, 1, KRANDOM)) != TRUE))
  198.         return (s);
  199.  
  200.     /* get # of lines to affect */
  201.     if ((s = getregion(®ion)) != TRUE)
  202.         return (s);
  203.     first = region.r_linep;
  204.     last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp;
  205.     for (nline = 1; first != last; nline++)
  206.         first = lforw(first);
  207.  
  208.     /*move to beginning of region */
  209.     curwp->w_dotp = region.r_linep;
  210.     curwp->w_doto = region.r_offset;
  211.  
  212.     /* for each line, go to beginning and insert the prefix string */
  213.     while (nline--)
  214.     {
  215.         gotobol();
  216.         for (prefix = prefix_string; *prefix; prefix++)
  217.             (VOID) linsert((RSIZE) 1, *prefix);
  218.         forwline(FALSE, 1, KRANDOM);
  219.     }
  220.     gotobol();
  221.     return (TRUE);
  222. }
  223.  
  224. /*
  225.  * Set prefix string.
  226.  */
  227.  
  228. /*ARGSUSED*/
  229. setprefix(f, n, k)
  230. {
  231.     char        buf[PREFIXLENGTH];
  232.     register int    s;
  233.  
  234.     if (prefix_string[0] == '\0')
  235.         s = ereply("Prefix string: ",buf,sizeof buf);
  236.     else
  237.         s = ereply("Prefix string (default %s): ",
  238.                 buf,sizeof buf,prefix_string);
  239.     if (s == TRUE)
  240.         (VOID) strcpy(prefix_string, buf);
  241.     if ((s == FALSE) && (prefix_string[0] != '\0'))    /* CR -- use old one */
  242.         s = TRUE;
  243.     return (s);
  244. }
  245. #endif
  246. \Rogue\Monster\
  247. else
  248.   echo "will not over write ./region.c"
  249. fi
  250. if `test ! -s ./search.c`
  251. then
  252. echo "writing ./search.c"
  253. cat > ./search.c << '\Rogue\Monster\'
  254. /*
  255.  *         Search commands.
  256.  * The functions in this file implement the
  257.  * search commands (both plain and incremental searches
  258.  * are supported) and the query-replace command.
  259.  *
  260.  * The plain old search code is part of the original
  261.  * MicroEMACS "distribution". The incremental search code,
  262.  * and the query-replace code, is by Rich Ellison.
  263.  */
  264. #include    "def.h"
  265.  
  266. #define SRCH_BEGIN    (0)            /* Search sub-codes.    */
  267. #define    SRCH_FORW    (-1)
  268. #define SRCH_BACK    (-2)
  269. #define SRCH_NOPR    (-3)
  270. #define SRCH_ACCM    (-4)
  271. #define    SRCH_MARK    (-5)
  272.  
  273. typedef struct  {
  274.     int    s_code;
  275.     LINE    *s_dotp;
  276.     int    s_doto;
  277. }    SRCHCOM;
  278.  
  279. static    SRCHCOM    cmds[NSRCH];
  280. static    int    cip;
  281.  
  282. int    srch_lastdir = SRCH_NOPR;        /* Last search flags.    */
  283.  
  284. VOID    is_cpush();
  285. VOID    is_lpush();
  286. VOID    is_pop();
  287. VOID    is_prompt();
  288. VOID    is_dspl();
  289.  
  290. /*
  291.  * Search forward.
  292.  * Get a search string from the user, and search for it,
  293.  * starting at ".". If found, "." gets moved to just after the
  294.  * matched characters, and display does all the hard stuff.
  295.  * If not found, it just prints a message.
  296.  */
  297. /*ARGSUSED*/
  298. forwsearch(f, n, k)
  299. {
  300.     register int    s;
  301.  
  302.     if ((s=readpattern("Search")) != TRUE)
  303.         return (s);
  304.     if (forwsrch() == FALSE)
  305.     {
  306.         ewprintf("Search failed: \"%s\"", pat);
  307.         return (FALSE);
  308.     }
  309.     srch_lastdir = SRCH_FORW;
  310.     return (TRUE);
  311. }
  312.  
  313. /*
  314.  * Reverse search.
  315.  * Get a search string from the  user, and search, starting at "."
  316.  * and proceeding toward the front of the buffer. If found "." is left
  317.  * pointing at the first character of the pattern [the last character that
  318.  * was matched].
  319.  */
  320. /*ARGSUSED*/
  321. backsearch(f, n, k)
  322. {
  323.     register int    s;
  324.  
  325.     if ((s=readpattern("Search backward")) != TRUE)
  326.         return (s);
  327.     if (backsrch() == FALSE)
  328.     {
  329.         ewprintf("Search failed: \"%s\"", pat);
  330.         return (FALSE);
  331.     }
  332.     srch_lastdir = SRCH_BACK;
  333.     return (TRUE);
  334. }
  335.  
  336. /* 
  337.  * Search again, using the same search string
  338.  * and direction as the last search command. The direction
  339.  * has been saved in "srch_lastdir", so you know which way
  340.  * to go.
  341.  */
  342. /*ARGSUSED*/
  343. searchagain(f, n, k)
  344. {
  345.     if (srch_lastdir == SRCH_FORW)
  346.     {
  347.         if (forwsrch() == FALSE)
  348.         {
  349.             ewprintf("Search failed: \"%s\"", pat);
  350.             return (FALSE);
  351.         }
  352.         return (TRUE);
  353.     }
  354.     if (srch_lastdir == SRCH_BACK)
  355.     {
  356.         if (backsrch() == FALSE)
  357.         {
  358.             ewprintf("Search failed: \"%s\"", pat);
  359.             return (FALSE);
  360.         }
  361.         return (TRUE);
  362.     }
  363.     ewprintf("No last search");
  364.     return (FALSE);
  365. }
  366.  
  367.  
  368. /*
  369.  * This routine does the real work of a
  370.  * forward search. The pattern is sitting in the external
  371.  * variable "pat". If found, dot is updated, the window system
  372.  * is notified of the change, and TRUE is returned. If the
  373.  * string isn't found, FALSE is returned.
  374.  */
  375. forwsrch()
  376. {
  377.     register LINE    *clp;
  378.     register int    cbo;
  379.     register LINE    *tlp;
  380.     register int    tbo;
  381.     register char    *pp;
  382.     register int    c;
  383.  
  384.     clp = curwp->w_dotp;
  385.     cbo = curwp->w_doto;
  386.     while (clp != curbp->b_linep)
  387.     {
  388.         if (cbo == llength(clp))
  389.         {
  390.             clp = lforw(clp);
  391.             cbo = 0;
  392.             c = SEOL;
  393.         } else
  394.             c = lgetc(clp, cbo++);
  395.         if (eq(c, pat[0]) != FALSE)
  396.         {
  397.             tlp = clp;
  398.             tbo = cbo;
  399.             pp  = &pat[1];
  400.             while (*pp != 0)
  401.             {
  402.                 if (tlp == curbp->b_linep)
  403.                     goto fail;
  404.                 if (tbo == llength(tlp))
  405.                 {
  406.                     tlp = lforw(tlp);
  407.                     if (tlp == curbp->b_linep)
  408.                         goto fail;
  409.                     tbo = 0;
  410.                     c = SEOL;
  411.                 } else
  412.                     c = lgetc(tlp, tbo++);
  413.                 if (eq(c, *pp++) == FALSE)
  414.                     goto fail;
  415.             }
  416.             curwp->w_dotp  = tlp;
  417.             curwp->w_doto  = tbo;
  418.             curwp->w_flag |= WFMOVE;
  419.             return (TRUE);
  420.         }
  421.     fail:    ;
  422.     }
  423.     return (FALSE);
  424. }
  425.  
  426. /*
  427.  * This routine does the real work of a
  428.  * backward search. The pattern is sitting in the external
  429.  * variable "pat". If found, dot is updated, the window system
  430.  * is notified of the change, and TRUE is returned. If the
  431.  * string isn't found, FALSE is returned.
  432.  */
  433. backsrch()
  434. {
  435.     register LINE    *clp;
  436.     register int    cbo;
  437.     register LINE    *tlp;
  438.     register int    tbo;
  439.     register int    c;
  440.     register char    *epp;
  441.     char        *pp;
  442.  
  443.     for (epp = &pat[0]; epp[1] != 0; ++epp)
  444.         ;
  445.     clp = curwp->w_dotp;
  446.     cbo = curwp->w_doto;
  447.     for (;;)
  448.     {
  449.         if (cbo == 0)
  450.         {
  451.             clp = lback(clp);
  452.             if (clp == curbp->b_linep)
  453.                 return (FALSE);
  454.             cbo = llength(clp)+1;
  455.         }
  456.         if (--cbo == llength(clp))
  457.             c = SEOL;
  458.         else
  459.             c = lgetc(clp,cbo);
  460.         if (eq(c, *epp) != FALSE)
  461.         {
  462.             tlp = clp;
  463.             tbo = cbo;
  464.             pp  = epp;
  465.             while (pp != &pat[0])
  466.             {
  467.                 if (tbo == 0)
  468.                 {
  469.                     tlp = lback(tlp);
  470.                     if (tlp == curbp->b_linep)
  471.                         goto fail;
  472.                     tbo = llength(tlp)+1;
  473.                 }
  474.                 if (--tbo == llength(tlp))
  475.                     c = SEOL;
  476.                 else
  477.                     c = lgetc(tlp,tbo);
  478.                 if (eq(c, *--pp) == FALSE)
  479.                     goto fail;
  480.             }
  481.             curwp->w_dotp  = tlp;
  482.             curwp->w_doto  = tbo;
  483.             curwp->w_flag |= WFMOVE;
  484.             return (TRUE);
  485.         }
  486.     fail:    ;
  487.     }
  488.     /* NOTREACHED*/
  489. }
  490.  
  491. /*
  492.  * Compare two characters.
  493.  * The "bc" comes from the buffer.
  494.  * It has its case folded out. The
  495.  * "pc" is from the pattern.
  496.  */
  497. eq(bc, pc)
  498. {
  499.     register int    ibc;
  500.     register int    ipc;
  501.  
  502.     ibc = bc & 0xFF;
  503.     ipc = pc & 0xFF;
  504.     if (ISLOWER(ibc) != FALSE)
  505.         ibc = TOUPPER(ibc);
  506.     if (ISLOWER(ipc) != FALSE)
  507.         ipc = TOUPPER(ipc);
  508.     if (ibc == ipc)
  509.         return (TRUE);
  510.     return (FALSE);
  511. }
  512.  
  513. /*
  514.  * Read a pattern.
  515.  * Stash it in the external variable "pat". The "pat" is
  516.  * not updated if the user types in an empty line. If the user typed
  517.  * an empty line, and there is no old pattern, it is an error.
  518.  * Display the old pattern, in the style of Jeff Lomicka. There is
  519.  * some do-it-yourself control expansion.
  520.  */
  521. readpattern(prompt) char *prompt;
  522. {
  523.     register int    s;
  524.     char        tpat[NPAT];
  525.  
  526.     if (tpat[0] == '\0') s = ereply("%s: ", tpat, NPAT, prompt);
  527.     else s = ereply("%s: (default %s) ", tpat, NPAT, prompt, pat);
  528.  
  529.     if (s == TRUE)                /* Specified        */
  530.         (VOID) strcpy(pat, tpat);
  531.     else if (s==FALSE && pat[0]!=0)        /* CR, but old one    */
  532.         s = TRUE;
  533.     return (s);
  534. }
  535. \Rogue\Monster\
  536. else
  537.   echo "will not over write ./search.c"
  538. fi
  539. if `test ! -s ./spawn.c`
  540. then
  541. echo "writing ./spawn.c"
  542. cat > ./spawn.c << '\Rogue\Monster\'
  543. /*
  544.  * Name:    MicroEMACS
  545.  *        Spawn CLI for System V.
  546.  * Version:    0
  547.  * Last edit:    17-Apr-86
  548.  * By:        gonzo!daveb
  549.  *        {sun, amdahl, mtxinu}!rtech!daveb
  550.  *
  551.  * Spawn for System V.
  552.  */
  553. #include    "def.h"
  554.  
  555. #include    <signal.h>
  556. #include    <stdio.h>
  557.  
  558. extern    char    *getenv();
  559.  
  560. /*
  561.  * Execute a single command using the shell. If no argument,
  562.  * then print the file in the top (only) buffer, after making
  563.  * sure that it has been flushed to disk.
  564.  */
  565. /*ARGSUSED*/
  566. spawncmd( f, n, k)
  567.    int f, n;
  568.    char **k;
  569. {
  570.    char cmdbuf[80];
  571.    extern char *getenv();
  572.    register int   pid;
  573.    register int   wpid;
  574.    int   (*oqsig)();
  575.    int   (*oisig)();
  576.    int      status;
  577.    int      errp = FALSE;
  578.  
  579.    if (f == FALSE)      /* no command provided */
  580.    {
  581.       char *printcmd;
  582.       char *argv[32];
  583.       char argbuf[128];
  584.       char *ptr;
  585.       int argc;
  586.  
  587.       (void)memset(argbuf, 0, 128);
  588.       if ((printcmd = getenv("SPOOLER")) == NULL)
  589.          printcmd = "lp -s";
  590.       (void)strcpy( argbuf, printcmd);
  591. #ifdef DEBUG
  592.     fprintf(stderr, "spooler='%s'\n", argbuf);
  593. #endif
  594.       for (argc=0, ptr=argbuf; *ptr; )
  595.       {
  596.          while (*ptr && (*ptr == ' ' || *ptr == '\t'))
  597.        {
  598.          *ptr++ = '\0';
  599.        }
  600.          argv[argc++] = ptr;
  601.          while (*ptr && *ptr != ' ' && *ptr != '\t')
  602.             ++ptr;
  603.       }
  604.       if (argv[argc-1][0] == '\0')
  605.          argv[argc-1] = NULL;
  606.       argv[argc] = NULL;
  607. #ifdef DEBUG
  608.     {
  609.     int i;
  610.         fprintf(stderr, "argc=%d,", argc);
  611.         fprintf(stderr, " argv='%s'", argv[0]);
  612.         for (i=1; i<=argc; ++i)
  613.            fprintf(stderr, ",'%s'", argv[i]);
  614.         fprintf(stderr, "\n");
  615.     }
  616. #endif
  617.       (void)strcpy( cmdbuf, wheadp->w_bufp->b_fname);
  618.  
  619.       ewprintf("Please Wait...");
  620.       oqsig = signal(SIGQUIT, SIG_IGN);
  621.       oisig = signal(SIGINT,  SIG_IGN);
  622.       if ((pid=fork()) == 0)
  623.       {
  624.          freopen( cmdbuf, "r", stdin);
  625.          execvp( argv[0], argv);
  626.          _exit(1);         /* Should do better!   */
  627.       }
  628.       else if (pid > 0)
  629.       {
  630.          while ((wpid=wait(&status))>=0 && wpid!=pid)
  631.             ;
  632.       }
  633.       else
  634.          errp = TRUE;
  635.  
  636.       signal(SIGQUIT, oqsig);
  637.       signal(SIGINT,  oisig);
  638.       if(errp)
  639.          ewprintf("Print failed (can't create process).");
  640.       else if (status)
  641.          ewprintf("spooler returned error status=%d", status);
  642.       else
  643.          ewprintf("Text Queued for print");
  644.    }
  645.    else
  646.    {
  647.       /*
  648.        * Don't do nuthin currently
  649.        */
  650.    }
  651.    return TRUE;
  652. }
  653.  
  654. #ifdef MENU_INSERT
  655. /*
  656.  * Menu Insert -- spawn a shell with the menu shell script
  657.  */
  658. spawninsert( f, n, k)
  659. {
  660.    extern char   *strrchr(), *strcpy(), *strcat(), *tmpnam();
  661.    register int   pid;
  662.    register int   wpid;
  663.    register int   (*oqsig)();
  664.    register int   (*oisig)();
  665.    int      status;
  666.    int      errp = FALSE;
  667.    char      menup[80], *menuname = NULL;
  668.    char      tempfile[L_tmpnam];
  669.  
  670.    (void)strcpy( menup, getenv("DBBIN"));
  671.    if (menup[strlen(menup)-1] != '/')
  672.       (void)strcat( menup, "/");
  673.    if ((menuname = getenv("EMENU")) == NULL)
  674.    {
  675.       menuname = "mgx-menu.sh";
  676.    }
  677.    (void)strcat(menup, menuname);
  678.    menuname = strrchr( menup, '/' ); 
  679.    menuname = menuname ? menuname++ : menup;
  680.  
  681.    strcpy (tempfile, tmpnam((char *)0));
  682.    ttcolor(CTEXT);
  683.    ttnowindow();
  684.    ttmove(nrow-1, 0);
  685.    if (epresf != FALSE)
  686.    {
  687.       tteeol();
  688.       epresf = FALSE;
  689.    }
  690.    ttclose();
  691.    sgarbf = TRUE;            /* Force repaint.   */
  692.    oqsig = signal(SIGQUIT, SIG_IGN);
  693.    oisig = signal(SIGINT,  SIG_IGN);
  694.    if ((pid=fork()) == 0)
  695.    {
  696.       execlp(menup, menuname, tempfile, NULL);
  697.       _exit(1);         /* Should do better!   */
  698.    }
  699.    else if (pid > 0)
  700.    {
  701.       while ((wpid=wait(&status))>=0 && wpid!=pid)
  702.          ;
  703.    }
  704.    else
  705.       errp = TRUE;
  706.  
  707.    signal(SIGINT,  oisig);
  708.    ttopen();
  709.    if(errp)
  710.       ewprintf("Failed to create process");
  711.    else
  712.    {
  713.       gotobol( FALSE, 0, 0);
  714.       insertfile( tempfile, (char *)0);
  715.    }
  716.    unlink( tempfile);
  717.    return ( errp | status );
  718. }
  719. #endif
  720. \Rogue\Monster\
  721. else
  722.   echo "will not over write ./spawn.c"
  723. fi
  724. if `test ! -s ./symbol.c`
  725. then
  726. echo "writing ./symbol.c"
  727. cat > ./symbol.c << '\Rogue\Monster\'
  728. /*
  729.  * Symbol tables, and keymap setup.
  730.  * The terminal specific parts of building the
  731.  * keymap has been moved to a better place.
  732.  */
  733. #include    "def.h"
  734.  
  735. /*
  736.  * Heavily modified routine for the TINY version of MicroGnuEmacs.
  737.  */
  738.  
  739. /*
  740.  * Defined here so to collect the #ifdef MEYN config stuff in one file
  741.  * If you set either MINDENT or MFILL, then you need to change the bindings
  742.  * in this file to match: KCTRL|'M' -> newline-and-indent and KCTRL|'J' ->
  743.  * insert-newline for MINDENT, and ' ' -> insert-with-wrap for MFILL.
  744.  * MEYN is used for compile-time customization of the system for micros.
  745.  */
  746.  
  747. int    mode = MFILL | MOVRSTK | MFLOW;
  748.  
  749. /*
  750.  * Defined by "main.c".
  751.  */
  752. extern    int    ctrlg();        /* Abort out of things        */
  753. extern    int    quit();            /* Quit                */
  754.  
  755. /*
  756.  * Defined by "search.c".
  757.  */
  758. extern    int    forwsearch();        /* Search forward        */
  759. extern    int    backsearch();        /* Search backwards        */
  760. extern  int    searchagain();        /* Repeat last search command    */
  761.  
  762. /*
  763.  * Defined by "basic.c".
  764.  */
  765. extern    int    gotobol();        /* Move to start of line    */
  766. extern    int    backchar();        /* Move backward by characters    */
  767. extern    int    gotoeol();        /* Move to end of line        */
  768. extern    int    forwchar();        /* Move forward by characters    */
  769. extern    int    gotobob();        /* Move to start of buffer    */
  770. extern    int    gotoeob();        /* Move to end of buffer    */
  771. extern    int    forwline();        /* Move forward by lines    */
  772. extern    int    backline();        /* Move backward by lines    */
  773. extern    int    setmark();        /* Set mark            */
  774. /*
  775.  * Defined by "buffer.c".
  776.  */
  777. extern    int    savebuffers();        /* Save unmodified buffers    */
  778. extern    int    notmodified();        /* Reset modification flag    */
  779.  
  780. #ifdef    DIRLIST
  781. /*
  782.  * Defined by "dirlist.c".
  783.  */
  784. extern    int    dirlist();        /* Directory list.        */
  785. #endif
  786.  
  787. /*
  788.  * Defined by "display.c"
  789.  */
  790. extern    int    rotatmode();        /* rotate mode-line help    */
  791.  
  792. /*
  793.  * Defined by "file.c".
  794.  */
  795. extern    int    filevisit();        /* Get a file, read write    */
  796. extern    int    filewrite();        /* Write a file            */
  797. extern    int    filesave();        /* Save current file        */
  798. extern    int    fileinsert();        /* Insert file into buffer    */
  799. #ifdef    BACKUP
  800. extern    int    makebkfile();        /* Control backups on saves    */
  801. #endif
  802.  
  803. /*
  804.  * Defined by "random.c".
  805.  */
  806. extern    int    selfinsert();        /* Insert character        */
  807. extern    int    showcpos();        /* Show the cursor position    */
  808. extern    int    openline();        /* Open up a blank line        */
  809. extern    int    newline();        /* Insert CR-LF            */
  810. extern    int    forwdel();        /* Forward delete        */
  811. extern    int    backdel();        /* Backward delete in        */
  812. extern    int    killline();        /* Kill forward            */
  813. extern    int    bsmapmode();        /* set bsmap mode        */
  814. extern    int    flowmode();        /* set flow mode        */
  815. extern    int    fillmode();        /* set word-wrap mode        */
  816. extern    int    insovrmode();        /* toggle insert overstrike mode */
  817. extern    int    yank();            /* Yank back from killbuffer.    */
  818.  
  819. /*
  820.  * Defined by "region.c".
  821.  */
  822. extern    int    killregion();        /* Kill region.            */
  823. #ifdef    PREFIXREGION
  824. extern    int    prefixregion();        /* Prefix all lines in region    */
  825. extern    int    setprefix();        /* Set line prefix string    */
  826. #endif
  827.  
  828. /*
  829.  * Defined by "window.c".
  830.  */
  831. extern    int    reposition();        /* Reposition window        */
  832. extern    int    refresh();        /* Refresh the screen        */
  833.  
  834. /*
  835.  * Defined by "word.c".
  836.  */
  837. extern    int    delfword();        /* Delete forward word.        */
  838. extern    int    delbword();        /* Delete backward word.    */
  839.  
  840. /*
  841.  * Defined by "extend.c".
  842.  */
  843. extern    int    extend();        /* Extended commands.        */
  844. extern    int    startover();        /* reread file, restart edit    */
  845. extern    int    reallyquit();        /* kill emacs, don't save files    */
  846. extern    int    deleteline();        /* delete line from anywhere    */
  847. #ifdef    STARTUP
  848. extern    int    evalexpr();        /* Extended commands (again)    */
  849. extern    int    evalbuffer();        /* Evaluate current buffer    */
  850. extern    int    evalfile();        /* Evaluate a file        */
  851. #endif
  852.  
  853. /*
  854.  * defined by "paragraph.c" - the paragraph justification code.
  855.  */
  856. extern    int    gotobop();        /* Move to start of paragraph.    */
  857. extern    int    gotoeop();        /* Move to end of paragraph.    */
  858. extern    int    fillpara();        /* Justify a paragraph.        */
  859. extern    int    killpara();        /* Delete a paragraph.        */
  860. extern    int    setfillcol();        /* Set fill column for justify.    */
  861. extern    int    fillword();        /* Insert char with word wrap.    */
  862.  
  863. #ifdef MISLOG
  864. /*
  865.  * defined by "newlog.c" - the mislog code.
  866.  */
  867. extern    int    newlog();        /* newlog function for MISLOG    */
  868. #endif
  869.  
  870. typedef    struct    {
  871.     KEY    k_key;            /* Key to bind.            */
  872.     int    (*k_funcp)();        /* Function.            */
  873.     char    *k_name;        /* Function name string.    */
  874. }    KEYTAB;
  875.  
  876. /*
  877.  * Default key binding table. This contains
  878.  * the function names, the symbol table name, and (possibly)
  879.  * a key binding for the builtin functions. There are no
  880.  * bindings for C-U or C-X. These are done with special
  881.  * code, but should be done normally.
  882.  */
  883. KEYTAB    key[] = {
  884.     KCTRL|'C',    ctrlg,        "keyboard-quit",
  885.     KCTRL|'D',    forwdel,    "delete-char",
  886.     KCTRL|'E',    gotoeol,    "end-of-line",
  887.     KCTRL|'I',    selfinsert,    "self-insert-command",
  888.     KCTRL|'G',    ctrlg,        "keyboard-quit",
  889.     KCTRL|'M',    newline,    "insert-newline",
  890.     KCTRL|'R',    refresh,    "redraw-display",
  891.     KCTRL|'S',    forwsearch,    "search-forward",
  892.     KCTLX|KCTRL|'Q',quit,        "save-buffers-kill-emacs",
  893.     KCTLX|KCTRL|'F',filevisit,    "find-file",
  894.     KMETA|'X',    extend,        "execute-extended-command",
  895.     KCTRL|'B',    backchar,    "backward-char",
  896.     KCTRL|'F',    forwchar,    "forward-char",
  897.     KCTRL|'N',    forwline,    "next-line",
  898.     KCTRL|'P',    backline,    "previous-line",
  899.     KCTLX|'=',    showcpos,    "what-cursor-position",
  900.     KCTLX|'I',    fileinsert,    "insert-file",
  901.     KMETA|'M',    setmark,    "set-mark-command",
  902.     KMETA|'C',    killregion,    "kill-region",
  903.     KMETA|'P',    yank,        "yank",
  904.     ' ',        fillword,    "insert-with-wrap",
  905.     -1,        backsearch,    "search-backward",
  906.     -1,        gotobol,    "beginning-of-line",
  907.     -1,        reposition,    "recenter",
  908.     -1,        killline,    "kill-line",
  909.     -1,        openline,    "open-line",
  910. #ifdef    DIRLIST
  911.     -1,        dirlist,    "display-directory",
  912. #endif
  913.     -1,        filesave,    "save-buffer",
  914.     -1,        filewrite,    "write-file",
  915.     -1,        savebuffers,    "save-some-buffers",
  916.     -1,        setfillcol,    "set-fill-column",
  917.     -1,        gotoeob,    "end-of-buffer",
  918.     -1,        gotobob,    "beginning-of-buffer",
  919.     -1,        gotobop,    "backward-paragraph",
  920.     -1,        gotoeop,    "forward-paragraph",
  921.     -1,        fillpara,    "fill-paragraph",
  922.     -1,        notmodified,    "not-modified",
  923. #ifdef    STARTUP
  924.     -1,        evalexpr,    "eval-expression",
  925.     -1,        evalbuffer,    "eval-current-buffer",
  926.     -1,        evalfile,    "load",
  927. #endif
  928.     -1,        bsmapmode,    "bsmap-mode",
  929.     -1,        flowmode,    "flow-mode",
  930.     -1,        fillmode,    "auto-fill-mode",
  931.     -1,        searchagain,    "search-again",
  932.     -1,        killpara,    "kill-paragraph",
  933. #ifdef    PREFIXREGION
  934.     -1,        prefixregion,    "prefix-region",
  935.     -1,        setprefix,    "set-prefix-string",
  936. #endif
  937. #ifdef    BACKUP
  938.     -1,        makebkfile,    "make-backup-files",
  939. #endif
  940.     /* new functions for TinyGnuEmacs */
  941.     -1,        insovrmode,    "toggle-insert-overstrike",
  942.     -1,        startover,    "restart-edit",
  943.     -1,        reallyquit,    "kill-emacs",
  944.     -1,        deleteline,    "delete-line",
  945.     -1,        rotatmode,    "rotate-help",
  946. #ifdef MISLOG
  947.     -1,        newlog,        "newlog",
  948. #endif
  949. };
  950.  
  951. #define    NKEY    (sizeof(key) / sizeof(key[0]))
  952.  
  953. /*
  954.  * Just some definitions, to keep ANSI compilers happy.
  955.  */
  956. VOID    keymapinit();
  957. VOID    keyadd();
  958. VOID    keydup();
  959.  
  960. /*
  961.  * Symbol table lookup.
  962.  * Return a pointer to the SYMBOL node, or NULL if
  963.  * the symbol is not found.
  964.  */
  965. SYMBOL    *
  966. symlookup(cp) register char *cp;
  967. {
  968.     register SYMBOL    *sp;
  969.  
  970. #ifdef    HASH
  971.     sp = symbol[symhash(cp)];
  972. #else
  973.     sp = symbol[0];
  974. #endif
  975.     while (sp != NULL)
  976.     {
  977.         if (strcmp(cp, sp->s_name) == 0)
  978.             return (sp);
  979. #ifdef    HASH
  980.         if ((sp->s_flags&SFEND) != 0) break;
  981. #endif
  982.         sp = sp->s_symp;
  983.     }
  984.     return (NULL);
  985. }
  986.  
  987. #ifdef    HASH
  988. /*
  989.  * Take a string, and compute the symbol table
  990.  * bucket number. This is done by adding all of the characters
  991.  * together, and taking the sum mod NSHASH. The string probably
  992.  * should not contain any GR characters; if it does the "*cp"
  993.  * may get a nagative number on some machines, and the "%"
  994.  * will return a negative number!
  995.  */
  996. symhash(cp) register char *cp;
  997. {
  998.     register int    c;
  999.     register int    n;
  1000.  
  1001.     n = 0;
  1002.     while ((c = *cp++) != 0)
  1003.         n += c;
  1004.     return (n % NSHASH);
  1005. }
  1006. #endif
  1007.  
  1008. /*
  1009.  * Build initial keymap. The funny keys
  1010.  * (commands, odd control characters) are mapped using
  1011.  * a big table and calls to "keyadd". The printing characters
  1012.  * are done with some do-it-yourself handwaving. The terminal
  1013.  * specific keymap initialization code is called at the
  1014.  * very end to finish up. All errors are fatal.
  1015.  */
  1016. VOID
  1017. keymapinit()
  1018. {
  1019.     register SYMBOL    *sp;
  1020.     register KEYTAB    *kp;
  1021.     register int    i;
  1022.  
  1023.     for (i=0; i<NKEYS; ++i)
  1024.         binding[i] = NULL;
  1025.     for (kp = &key[0]; kp < &key[NKEY]; ++kp)
  1026.         keyadd(kp->k_key, kp->k_funcp, kp->k_name);
  1027.     keydup((KEY) (KCTLX|KCTRL|'C'),    "keyboard-quit");
  1028.     keydup((KEY) (KMETA|KCTRL|'C'),    "keyboard-quit");
  1029.     keyadd((KEY) (KMETA|0x7F), delbword,
  1030.                 "backward-kill-word");
  1031.     keyadd((KEY) 0x7F, backdel,    "backward-delete-char");
  1032.     /*
  1033.      * Should be bound by "tab" already.
  1034.      */
  1035.     if ((sp=symlookup("self-insert-command")) == NULL)
  1036.         panic("no self-insert-command in keymapinit");
  1037.     if (binding[0x20] == NULL)    /* 0x20 == ' ' may already be    */
  1038.         binding[0x20] = sp;    /* bound to insert-with-wrap    */
  1039.     for (i=0x21; i<0x7F; ++i)
  1040.     {
  1041.         if (binding[i] != NULL)
  1042.             panic("nonull binding in keymapinit");
  1043.         binding[i] = sp;
  1044.     }
  1045.     ttykeymapinit();
  1046. #ifdef    HASH
  1047.     /* Link up the symbol table entries    */
  1048.     for (sp = symbol[i = 0]; i < NSHASH-1; sp = sp->s_symp)
  1049.         if (sp->s_symp == NULL) sp->s_symp = symbol[++i];
  1050. #endif            
  1051. }
  1052.  
  1053. /*
  1054.  * Create a new builtin function "name"
  1055.  * with function "funcp". If the "new" is a real
  1056.  * key, bind it as a side effect. All errors
  1057.  * are fatal.
  1058.  */
  1059. VOID
  1060. keyadd(new, funcp, name) register KEY new; int (*funcp)(); char *name;
  1061. {
  1062.     register SYMBOL    *sp;
  1063. #ifdef    HASH
  1064.     register int    hash;
  1065. #endif
  1066.  
  1067.     if ((sp=(SYMBOL *)malloc(sizeof(SYMBOL))) == NULL)
  1068.         panic("No memory");
  1069. #ifdef    HASH
  1070.     hash = symhash(name);
  1071.     if (symbol[hash] == NULL) sp->s_flags |= SFEND;
  1072.     sp->s_symp = symbol[hash];
  1073.     symbol[hash] = sp;
  1074. #else
  1075.     sp->s_symp = symbol[0];
  1076.         symbol[0] = sp;
  1077. #endif
  1078.     sp->s_name = name;
  1079.     sp->s_funcp = funcp;
  1080.     if (new >= 0)
  1081.     {                /* Bind this key.    */
  1082.         if (binding[new] != NULL)
  1083.         {
  1084.             char buf[80];
  1085.             sprintf(buf,"rebinding old symbol: %s", name);
  1086.             panic(buf);
  1087.         }
  1088.         binding[new] = sp;
  1089.     }
  1090. }
  1091.  
  1092. /*
  1093.  * Bind key "new" to the existing
  1094.  * routine "name". If the name cannot be found,
  1095.  * or the key is already bound, abort.
  1096.  */
  1097. VOID
  1098. keydup(new, name) register KEY new; char *name;
  1099. {
  1100.     register SYMBOL    *sp;
  1101.  
  1102.     if (binding[new]!=NULL || (sp=symlookup(name))==NULL)
  1103.     {
  1104. #ifdef    KEYDUP_ERROR
  1105.         fprintf (stderr, "keydup: binding[%d] = %x",
  1106.                 new, binding[new]);
  1107.         fprintf (stderr, " and symlookup(%s) == %x\n", name, sp);
  1108. #endif
  1109.         panic("keydup");
  1110.     }
  1111.     binding[new] = sp;
  1112. }
  1113. \Rogue\Monster\
  1114. else
  1115.   echo "will not over write ./symbol.c"
  1116. fi
  1117. if `test ! -s ./tty.c`
  1118. then
  1119. echo "writing ./tty.c"
  1120. cat > ./tty.c << '\Rogue\Monster\'
  1121. /*
  1122.  * Termcap/terminfo display driver
  1123.  *
  1124.  * Termcap is a terminal information database and routines to describe 
  1125.  * terminals on most UNIX systems.  Many other systems have adopted
  1126.  * this as a reasonable way to allow for widly varying and ever changing
  1127.  * varieties of terminal types.  This should be used where practical.
  1128.  */
  1129. /* Known problems:
  1130.  *    tputs is always called with the number of lines affected set to
  1131.  *    one.  Therefore, padding may be insufficient on some sequences
  1132.  *    dispite termcap being set up correctly.
  1133.  *
  1134.  *    If you have a terminal with no clear to end of screen and
  1135.  *    memory of lines below the ones visible on the screen, display
  1136.  *    will be wrong in some cases.  I doubt that any such terminal
  1137.  *    was ever made, but I thought everyone with delete line would
  1138.  *    have clear to end of screen too...
  1139.  *
  1140.  *    Code for terminals without clear to end of screen and/or clear
  1141.  *    to end of line has not been extensivly tested.
  1142.  *
  1143.  *    Cost calculations are very rough.  Costs of insert/delete line
  1144.  *    may be far from the truth.  This is accentuated by display.c
  1145.  *    not knowing about multi-line insert/delete.
  1146.  *
  1147.  *    Using scrolling region vs insert/delete line should probably
  1148.  *    be based on cost rather than the assuption that scrolling
  1149.  *    region operations look better.
  1150.  */
  1151. #include    "def.h"
  1152.  
  1153. #define    BEL    0x07            /* BEL character.        */
  1154. #define    LF    0x0A            /* Line feed.            */
  1155.  
  1156. extern    int    ttrow;
  1157. extern    int    ttcol;
  1158. extern    int    tttop;
  1159. extern    int    ttbot;
  1160. extern    int    tthue;
  1161.  
  1162. int    tceeol;            /* Costs are set later */
  1163. int    tcinsl;
  1164. int    tcdell;
  1165.  
  1166. static    int    insdel;        /* Do we have both insert & delete line? */
  1167.  
  1168. #ifdef NO_RESIZE
  1169. static  setttysize();
  1170. #endif
  1171.  
  1172. char    *tgetstr();
  1173. char    *tgoto();
  1174. int    ttputc();
  1175.  
  1176. #define TCAPSLEN 1024
  1177.  
  1178. char tcapbuf[TCAPSLEN];
  1179.  
  1180. /* PC, UP, and BC are used by termlib, so must be extern and have these
  1181.  * names unless you have a non-standard termlib.
  1182.  */
  1183.  
  1184. int    LI;            /* standard # lines */
  1185. char    PC,
  1186.         *CM,
  1187.         *CE,
  1188.         *UP,
  1189.     *BC,
  1190.     *IM,            /* insert mode */
  1191.     *IC,            /* insert a single space */
  1192.     *EI,            /* end insert mode */
  1193.     *DC,
  1194.     *AL,            /* add line */
  1195.     *DL,            /* del line */
  1196.     *pAL,            /* parameterized add line */
  1197.     *pDL,            /* parameterized delete line */
  1198.     *TI,            /* term init -- start using cursor motion */
  1199.     *TE,            /* term end --- end using cursor motion */
  1200.     *SO,
  1201.     *SE,
  1202.         *CD,
  1203.     *CS,            /* set scroll region            */
  1204.     *SR;            /* back index (used with scroll region    */
  1205. #ifdef    XKEYS
  1206. char    *K[NFKEYS],        /* other function key codes        */
  1207.     *L[NFKEYS],        /* labels for other functions keys    */
  1208.     *KS, *KE,        /* enter keypad mode, exit keypad mode    */
  1209.     *KH, *KU, *KD, *KL, *KR; /* home, arrow keys            */
  1210. #endif
  1211. int    SG;    /* number of glitches, 0 for invisable, -1 for none    */
  1212.     /* (yes virginia, there are terminals with invisible glitches)    */
  1213.  
  1214. /*
  1215.  * Initialize the terminal when the editor
  1216.  * gets started up.
  1217.  */
  1218. static char tcbuf[1024];
  1219.  
  1220. ttinit() {
  1221. #ifndef __50SERIES
  1222.         char *getenv();
  1223.         char *tv_stype;
  1224. #else
  1225.         fortran void gv$get();
  1226.         short code;
  1227.         static struct {short len; char data[15];} TERM
  1228.             = {15, '.'|0200, 'T'|0200, 'E'|0200, 'R'|0200, 'M'|0200,
  1229.                    'I'|0200, 'N'|0200, 'A'|0200, 'L'|0200, '_'|0200,
  1230.                    'T'|0200, 'Y'|0200, 'P'|0200, 'E'|0200, '$'|0200};
  1231.         struct {short len; char data[32];} termtype;
  1232. #       define tv_stype termtype.data
  1233. #endif
  1234.         char *t, *p, *tgetstr();
  1235. #ifdef    XKEYS
  1236.     char kname[3], lname[3];
  1237.     int i;
  1238. #endif
  1239.  
  1240. #ifdef    VAXC
  1241.         if ((tv_stype = trnlnm("TERM")) == NULL)
  1242.     {
  1243.         ttclose();
  1244.                 panic("Environment variable TERM not defined!");
  1245.     }
  1246. #else
  1247. #ifndef __50SERIES
  1248.         if ((tv_stype = getenv("TERM")) == NULL)/* Don't want VAX C getenv() */
  1249.     {
  1250.         ttclose();
  1251.                 panic("Environment variable TERM not defined!");
  1252.     }
  1253. #else
  1254.         gv$get(TERM, termtype, 31, code);
  1255.         if (code)
  1256.     {
  1257.         ttclose();
  1258.         panic("Global variable .Terminal_Type$ not defined");
  1259.         }
  1260.     termtype.data[termtype.len] = '\0';
  1261.         t = tv_stype;
  1262.         while(*t) *t++ &= 0177;
  1263. #endif
  1264. #endif
  1265.         if((tgetent(tcbuf, tv_stype)) != 1)
  1266.     {
  1267.         (VOID) strcpy(tcbuf, "Unknown terminal type ");
  1268.         (VOID) strcat(tcbuf, tv_stype);
  1269.         ttclose();
  1270.                 panic(tcbuf);
  1271.         }
  1272.  
  1273.         p = tcapbuf;
  1274.         t = tgetstr("pc", &p);
  1275.         if(t) PC = *t;
  1276.  
  1277.     LI = tgetnum("li");
  1278.         CD = tgetstr("cd", &p);
  1279.         CM = tgetstr("cm", &p);
  1280.         CE = tgetstr("ce", &p);
  1281.         UP = tgetstr("up", &p);
  1282.     BC = tgetstr("bc", &p);
  1283.     IM = tgetstr("im", &p);
  1284.     IC = tgetstr("ic", &p);
  1285.     EI = tgetstr("ei", &p);
  1286.     DC = tgetstr("dc", &p);
  1287.     AL = tgetstr("al", &p);
  1288.     DL = tgetstr("dl", &p);
  1289.     pAL= tgetstr("AL", &p);    /* parameterized insert and del. line */
  1290.     pDL= tgetstr("DL", &p);
  1291.     TI = tgetstr("ti", &p);
  1292.     TE = tgetstr("te", &p);
  1293.     SO = tgetstr("so", &p);
  1294.     SE = tgetstr("se", &p);
  1295.     CS = tgetstr("cs", &p); /* set scrolling region */
  1296.     SR = tgetstr("sr", &p);
  1297.     SG = tgetnum("sg");    /* standout glitch     */
  1298. #ifdef    XKEYS
  1299.     /* get the 10 standard termcap keys */
  1300.     strcpy(kname,"kx");
  1301.     strcpy(lname,"lx");
  1302.     for (i = 1; i < 10; i++) {
  1303.         kname[1] = i + '0';
  1304.         K[i] = tgetstr(kname, &p);
  1305.         lname[1] = i + '0';
  1306.         L[i] = tgetstr(lname, &p);
  1307.     }
  1308.     kname[1] = 'A';
  1309.     K[0] = tgetstr(kname, &p);
  1310.     lname[1] = 'A';
  1311.     L[0] = tgetstr(lname, &p);
  1312.  
  1313.     /* Hack to get another bunch */
  1314.     strcpy(kname,"Kx");
  1315.     strcpy(lname,"Lx");
  1316.     for (i = 1; i < 10; i++) {
  1317.         kname[1] = i + '0';
  1318.         K[10 + i] = tgetstr(kname, &p);
  1319.         lname[1] = i + '0';
  1320.         L[10 + i] = tgetstr(lname, &p);
  1321.     }
  1322.     kname[1] = 'A';
  1323.     K[10] = tgetstr(kname, &p);
  1324.     lname[1] = 'A';
  1325.     L[10] = tgetstr(lname, &p);
  1326.  
  1327.     /* Get the rest of the sequences */
  1328.     KS = tgetstr("ks", &p);
  1329.     KE = tgetstr("ke", &p);
  1330.     KH = tgetstr("kh", &p);
  1331.     KU = tgetstr("ku", &p);
  1332.     KD = tgetstr("kd", &p);
  1333.     KL = tgetstr("kl", &p);
  1334.     KR = tgetstr("kr", &p);
  1335. #endif
  1336.  
  1337.         if(CM == NULL || UP == NULL)
  1338.     {
  1339.         ttclose();
  1340.         panic("This terminal is too stupid to run MicroGnuEmacs\n");
  1341.     }
  1342.     ttresize();            /* set nrow & ncol    */
  1343.  
  1344.     /* watch out for empty capabilities (sure to be wrong)    */
  1345.     if (CE && !*CE) CE = NULL;
  1346.     if (CS && !*CS) CS = NULL;
  1347.     if (SR && !*SR) SR = NULL;
  1348.     if (AL && !*AL) AL = NULL;
  1349.     if (DL && !*DL) DL = NULL;
  1350.     if (pAL && !*pAL) pAL = NULL;
  1351.     if (pDL && !*pDL) pDL = NULL;
  1352.     if (CD && !*CD) CD = NULL;
  1353.  
  1354.     if(!CE)    tceeol = ncol;
  1355.     else     tceeol = charcost(CE);
  1356.  
  1357.     /* Estimate cost of inserting a line */
  1358.     if (CS && SR)    tcinsl = charcost(CS)*2 + charcost(SR);
  1359.     else if (pAL)   tcinsl = charcost(pAL);
  1360.     else if (AL)    tcinsl = charcost(AL);
  1361.     else        tcinsl = NROW * NCOL;    /* make this cost high enough */
  1362.  
  1363.     /* Estimate cost of deleting a line */
  1364.     if (CS)        tcdell = charcost(CS)*2 + 1;
  1365.     else if (pDL)   tcdell = charcost(pDL);
  1366.     else if (DL)    tcdell = charcost(DL);
  1367.     else        tcdell = NROW * NCOL;    /* make this cost high enough */
  1368.  
  1369.     /* Flag to indicate that we can both insert and delete lines */
  1370.     insdel = (AL || pAL) && (DL || pDL);
  1371.  
  1372.         if (p >= &tcapbuf[TCAPSLEN])
  1373.     {
  1374.         ttclose();
  1375.         panic("Terminal description too big!\n");
  1376.     }
  1377.     if (TI && *TI)
  1378.         putpad (TI);    /* init the term */
  1379. }
  1380.  
  1381. /*
  1382.  * Clean up the terminal, in anticipation of
  1383.  * a return to the command interpreter. This is a no-op
  1384.  * on the ANSI display. On the SCALD display, it sets the
  1385.  * window back to half screen scrolling. Perhaps it should
  1386.  * query the display for the increment, and put it
  1387.  * back to what it was.
  1388.  */
  1389. tttidy() {
  1390.     if (TE && *TE) putpad (TE);    /* set the term back to normal mode */
  1391. #ifdef    XKEYS
  1392.     ttykeymaptidy();
  1393. #endif
  1394. }
  1395.  
  1396. /*
  1397.  * Move the cursor to the specified
  1398.  * origin 0 row and column position. Try to
  1399.  * optimize out extra moves; redisplay may
  1400.  * have left the cursor in the right
  1401.  * location last time!
  1402.  */
  1403. ttmove(row, col) {
  1404.     char        *tgoto();
  1405.  
  1406.     if (ttrow!=row || ttcol!=col) {
  1407.     putpad(tgoto(CM, col, row));
  1408.     ttrow = row;
  1409.     ttcol = col;
  1410.     }
  1411. }
  1412.  
  1413. /*
  1414.  * Erase to end of line.
  1415.  */
  1416. tteeol() {
  1417.     if(CE) putpad(CE);
  1418.     else {
  1419.     register int i=ncol-ttcol;
  1420.     while(i--) ttputc(" ");
  1421.     ttrow = ttcol = HUGE;
  1422.     }
  1423. }
  1424.  
  1425. /*
  1426.  * Erase to end of page.
  1427.  */
  1428. tteeop() {
  1429.     if(CD) putpad(CD);
  1430.     else {
  1431.         putpad(CE);
  1432.     if (insdel) ttdell(ttrow + 1, LI, LI - ttrow - 1);
  1433.     else {        /* do it by hand */
  1434.         register int line;
  1435.         for (line = ttrow + 1; line <= LI; ++line) {
  1436.             ttmove(line, 0);
  1437.         tteeol();
  1438.         }
  1439.     }
  1440.     ttrow = ttcol = HUGE;
  1441.     }
  1442. }
  1443.  
  1444. /*
  1445.  * Make a noise.
  1446.  */
  1447. ttbeep() {
  1448.     ttputc(BEL);
  1449.     ttflush();
  1450. }
  1451.  
  1452. /*
  1453.  * Insert nchunk blank line(s) onto the
  1454.  * screen, scrolling the last line on the
  1455.  * screen off the bottom.  Use the scrolling
  1456.  * region if possible for a smoother display.
  1457.  * If no scrolling region, use a set
  1458.  * of insert and delete line sequences
  1459.  */
  1460. ttinsl(row, bot, nchunk) {
  1461.     register int    i;
  1462.     
  1463.     if (row == bot) {        /* Case of one line insert is     */
  1464.     ttmove(row, 0);        /*    special            */
  1465.     tteeol();
  1466.     return;
  1467.     }
  1468.     if (CS && SR) {        /* Use scroll region and back index    */
  1469.     ttwindow(row,bot);
  1470.     ttmove(row, 0);
  1471.     while (nchunk--) putpad(SR);
  1472.     ttnowindow();
  1473.     return;
  1474.     } else if (insdel) {
  1475.     ttmove(1+bot-nchunk, 0);
  1476.     if (pDL) putpad (tgoto(pDL, 0, nchunk));
  1477.     else for (i=0; i<nchunk; i++)    /* For all lines in the chunk    */
  1478.         putpad(DL);
  1479.     ttmove(row, 0);
  1480.     if (pAL) putpad (tgoto(pAL, 0, nchunk));
  1481.     else for (i=0; i<nchunk; i++)    /* For all lines in the chunk    */
  1482.         putpad(AL);
  1483.     ttrow = HUGE;
  1484.     ttcol = HUGE;
  1485.     } else panic("ttinsl: Can't insert/delete line");
  1486. }
  1487.  
  1488. /*
  1489.  * Delete nchunk line(s) from "row", replacing the
  1490.  * bottom line on the screen with a blank line. 
  1491.  * Unless we're using the scrolling region, this is 
  1492.  * done with a crafty sequences of insert and delete 
  1493.  * lines.  The presence of the echo area makes a
  1494.  * boundry condition go away.
  1495.  */
  1496. ttdell(row, bot, nchunk)
  1497. {
  1498.     register int    i;
  1499.     
  1500.     if (row == bot) {        /* One line special case    */
  1501.     ttmove(row, 0);
  1502.     tteeol();
  1503.     return;
  1504.     }
  1505.     if (CS) {            /* scrolling region    */
  1506.     ttwindow(row, bot);
  1507.     ttmove(bot, 0);
  1508.     while (nchunk--) ttputc(LF);
  1509.     ttnowindow();
  1510.     }
  1511.     else if(insdel) {
  1512.     ttmove(row, 0);            /* Else use insert/delete line    */
  1513.     if (pDL) putpad (tgoto(pDL, 0, nchunk));
  1514.     else for (i=0; i<nchunk; i++)    /* For all lines in the chunk    */
  1515.         putpad(DL);
  1516.     ttmove(1+bot-nchunk,0);
  1517.     if (pAL) putpad (tgoto(pAL, 0, nchunk));
  1518.     else for (i=0; i<nchunk; i++)    /* For all lines in the chunk    */
  1519.         putpad(AL);
  1520.     ttrow = HUGE;
  1521.     ttcol = HUGE;
  1522.     } else panic("ttdell: Can't insert/delete line");
  1523. }
  1524.  
  1525. /*
  1526.  * This routine sets the scrolling window
  1527.  * on the display to go from line "top" to line
  1528.  * "bot" (origin 0, inclusive). The caller checks
  1529.  * for the pathalogical 1 line scroll window that
  1530.  * doesn't work right, and avoids it. The "ttrow"
  1531.  * and "ttcol" variables are set to a crazy value
  1532.  * to ensure that the next call to "ttmove" does
  1533.  * not turn into a no-op (the window adjustment
  1534.  * moves the cursor).
  1535.  * 
  1536.  */
  1537. ttwindow(top, bot)
  1538. {
  1539.     if (CS && (tttop!=top || ttbot!=bot)) {
  1540.         putpad(tgoto(CS, bot, top));
  1541.         ttrow = HUGE;            /* Unknown.        */
  1542.         ttcol = HUGE;
  1543.         tttop = top;            /* Remember region.    */
  1544.         ttbot = bot;
  1545.     }
  1546. }
  1547.  
  1548. /*
  1549.  * Switch to full screen scroll. This is
  1550.  * used by "spawn.c" just before is suspends the
  1551.  * editor, and by "display.c" when it is getting ready
  1552.  * to exit.  This function gets to full screen scroll 
  1553.  * by telling the terminal to set a scrolling regin
  1554.  * that is LI or nrow rows high, whichever is larger.
  1555.  * This behavior seems to work right on systems
  1556.  * where you can set your terminal size.
  1557.  */
  1558. ttnowindow()
  1559. {
  1560.     if (CS) {
  1561.     putpad(tgoto(CS, (nrow > LI ? nrow : LI) - 1, 0));
  1562.     ttrow = HUGE;            /* Unknown.        */
  1563.     ttcol = HUGE;
  1564.     tttop = HUGE;            /* No scroll region.    */
  1565.     ttbot = HUGE;
  1566.     }
  1567. }
  1568.  
  1569. /*
  1570.  * Set the current writing color to the
  1571.  * specified color. Watch for color changes that are
  1572.  * not going to do anything (the color is already right)
  1573.  * and don't send anything to the display.
  1574.  * The rainbow version does this in putline.s on a
  1575.  * line by line basis, so don't bother sending
  1576.  * out the color shift. The "color already right" optimization
  1577.  * doesn't work on some terminals (such as Falco): it's gone!
  1578.  */
  1579. ttcolor(color) register int color; {
  1580.     if (color == CTEXT) {        /* Normal video.    */
  1581.         putpad(SE);
  1582.     } else if (color == CMODE) {    /* Reverse video.    */
  1583.         putpad(SO);
  1584.     }
  1585.     tthue = color;            /* Save the color.    */
  1586. }
  1587.  
  1588. /*
  1589.  * This routine is called by the
  1590.  * "refresh the screen" command to try and resize
  1591.  * the display. The new size, which must be deadstopped
  1592.  * to not exceed the NROW and NCOL limits, it stored
  1593.  * back into "nrow" and "ncol". Display can always deal
  1594.  * with a screen NROW by NCOL. Look in "window.c" to
  1595.  * see how the caller deals with a change.
  1596.  */
  1597. ttresize() {
  1598.     setttysize();            /* found in "ttyio.c",    */
  1599.                     /* ask OS for tty size    */
  1600.     if (nrow < 1)            /* Check limits.    */
  1601.         nrow = 1;
  1602.     else if (nrow > NROW)
  1603.         nrow = NROW;
  1604.     if (ncol < 1)
  1605.         ncol = 1;
  1606.     else if (ncol > NCOL)
  1607.         ncol = NCOL;
  1608. }
  1609.  
  1610. #ifdef NO_RESIZE
  1611. static setttysize() {
  1612.     nrow = tgetnum("li");
  1613.     ncol = tgetnum("co");
  1614. }
  1615. #endif
  1616.  
  1617. static int cci;
  1618.  
  1619. static            /* fake char output for charcost() */
  1620. fakec(c) char c; {
  1621. #ifdef    lint
  1622.     c++;
  1623. #endif
  1624.     cci++;
  1625. }
  1626.  
  1627. /* calculate the cost of doing string s */
  1628. charcost (s) char *s; {
  1629.     cci = 0;
  1630.  
  1631.     tputs(s, nrow, fakec);
  1632.     return cci;
  1633. }
  1634.  
  1635. putpad(str) char *str; {
  1636.         tputs(str, 1, ttputc);
  1637. }
  1638. \Rogue\Monster\
  1639. else
  1640.   echo "will not over write ./tty.c"
  1641. fi
  1642. if `test ! -s ./ttyio.c`
  1643. then
  1644. echo "writing ./ttyio.c"
  1645. cat > ./ttyio.c << '\Rogue\Monster\'
  1646. /*
  1647.  * Name:    MicroEMACS
  1648.  *        System V terminal I/O.
  1649.  * Version:    0
  1650.  * Last edit:    Tue Aug 26 23:57:57 PDT 1986
  1651.  * By:        gonzo!daveb
  1652.  *        {sun, amdahl, mtxinu}!rtech!gonzo!daveb
  1653.  *
  1654.  * The functions in this file
  1655.  * negotiate with the operating system for
  1656.  * keyboard characters, and write characters to
  1657.  * the display in a barely buffered fashion.
  1658.  *
  1659.  * This version goes along with tty/termcap/tty.c.
  1660.  * Terminal size is determined there, rather than here, and
  1661.  * this does not open the termcap file
  1662.  */
  1663. #include    "def.h"
  1664.  
  1665. #include    <sys/types.h>
  1666. #include    <fcntl.h>
  1667. #include    <termio.h>
  1668.  
  1669. #define    NOBUF    512            /* Output buffer size.        */
  1670.  
  1671. char    obuf[NOBUF];            /* Output buffer.        */
  1672. int    nobuf;                /* buffer count            */
  1673.  
  1674. static struct termio    ot;        /* entry state of the terminal    */
  1675. static struct termio    nt;        /* editor's terminal state    */
  1676.  
  1677. static int ttyactivep = FALSE;        /* terminal in editor mode?    */
  1678. static int ttysavedp = FALSE;        /* terminal state saved?    */
  1679.  
  1680. int    nrow;                /* Terminal size, rows.        */
  1681. int    ncol;                /* Terminal size, columns.    */
  1682.  
  1683. /* These are used to implement typeahead on System V */
  1684.  
  1685. int kbdflgs;            /* saved keyboard fd flags    */
  1686. int kbdpoll;            /* in O_NDELAY mode            */
  1687. int kbdqp;            /* there is a char in kbdq    */
  1688. char kbdq;            /* char we've already read    */
  1689.  
  1690. /*
  1691.  * This function gets called once, to set up
  1692.  * the terminal channel.  This version turns off flow
  1693.  * control.  This may be wrong for your system, but no
  1694.  * good solution has really been found (daveb).
  1695.  */
  1696. ttopen()
  1697. {
  1698.     register char    *cp;
  1699.     extern char    *getenv();
  1700.  
  1701.     if (ttyactivep)
  1702.         return;
  1703.  
  1704.     if( !ttysavedp )
  1705.     {
  1706.         if (ioctl(0, TCGETA, &ot) < 0)
  1707.             abort();
  1708.         nt = ot;        /* save entry state        */
  1709.         nt.c_cc[VMIN] = 1;    /* one character read is OK    */
  1710.         nt.c_cc[VTIME] = 0;    /* Never time out.        */
  1711.         nt.c_iflag |= IGNBRK;
  1712.         nt.c_iflag &= ~( ICRNL | INLCR | ISTRIP | IXON | IXOFF );
  1713.         nt.c_oflag &= ~OPOST;
  1714. #ifdef BIT7EVEN
  1715.         nt.c_cflag &= ~CS8;
  1716.         nt.c_cflag |= CS7;    /* disallow 8th bit on input    */
  1717.         nt.c_cflag |= PARENB;    /* check parity            */
  1718.         nt.c_cflag &= ~PARODD;    /* even parity            */
  1719. #else
  1720.         nt.c_cflag |= CS8;    /* allow 8th bit on input    */
  1721.         nt.c_cflag &= ~PARENB;    /* Don't check parity        */
  1722. #endif
  1723.         nt.c_lflag &= ~( ECHO | ICANON | ISIG );
  1724.  
  1725.         kbdflgs = fcntl( 0, F_GETFL, 0 );
  1726.         kbdpoll = FALSE;
  1727.     
  1728.         ttysavedp = TRUE;
  1729.     }
  1730.     
  1731.     if (ioctl(0, TCSETAF, &nt) < 0)
  1732.         abort();
  1733.  
  1734.     /* This really belongs in tty/termcap... */
  1735.  
  1736.     if ((cp=getenv("TERMCAP")) == NULL
  1737.     || (nrow=getvalue(cp, "li")) <= 0
  1738.     || (ncol=getvalue(cp, "co")) <= 0) {
  1739.         nrow = 24;
  1740.         ncol = 80;
  1741.     }
  1742.     if (nrow > NROW)            /* Don't crash if the    */
  1743.         nrow = NROW;            /* termcap entry is    */
  1744.     if (ncol > NCOL)            /* too big.        */
  1745.         ncol = NCOL;
  1746.  
  1747.     ttyactivep = TRUE;
  1748. }
  1749.  
  1750. /*
  1751.  * This routine scans a string, which is
  1752.  * actually the return value of a getenv call for the TERMCAP
  1753.  * variable, looking for numeric parameter "name". Return the value
  1754.  * if found. Return -1 if not there. Assume that "name" is 2
  1755.  * characters long. This limited use of the TERMCAP lets us find
  1756.  * out the size of a window on the X display.
  1757.  */
  1758. getvalue(cp, name)
  1759. register char    *cp;
  1760. register char    *name;
  1761. {
  1762.     for (;;) {
  1763.         while (*cp!=0 && *cp!=':')
  1764.             ++cp;
  1765.         if (*cp++ == 0)            /* Not found.        */
  1766.             return (-1);
  1767.         if (cp[0]==name[0] && cp[1]==name[1] && cp[2]=='#')
  1768.             return (atoi(cp+3));    /* Stops on ":".    */
  1769.     }
  1770. }
  1771.  
  1772. /*
  1773.  * This function gets called just
  1774.  * before we go back home to the shell. Put all of
  1775.  * the terminal parameters back.
  1776.  */
  1777. ttclose()
  1778. {
  1779.     if(!ttysavedp || !ttyactivep)
  1780.         return;
  1781.     ttflush();
  1782.     if (ioctl(0, TCSETAF, &ot) < 0 || fcntl( 0, F_SETFL, kbdflgs ) < 0)
  1783.         abort();
  1784.     ttyactivep = FALSE;
  1785. }
  1786.  
  1787. /*
  1788.  * Write character to the display.
  1789.  * Characters are buffered up, to make things
  1790.  * a little bit more efficient.
  1791.  */
  1792. ttputc(c)
  1793. {
  1794.     if (nobuf >= NOBUF)
  1795.         ttflush();
  1796.     obuf[nobuf++] = c;
  1797. }
  1798.  
  1799. /*
  1800.  * Flush output.
  1801.  */
  1802. ttflush()
  1803. {
  1804.     if (nobuf != 0) {
  1805.         write(1, obuf, nobuf);
  1806.         nobuf = 0;
  1807.     }
  1808. }
  1809.  
  1810. /*
  1811.  * Read character from terminal.
  1812.  * All 8 bits are returned, so that you can use
  1813.  * a multi-national terminal.
  1814.  *
  1815.  * If keyboard 'queue' already has typeahead from a typeahead() call,
  1816.  * just return it.  Otherwise, make sure we are in blocking i/o mode
  1817.  * and read a character.
  1818.  */
  1819. ttgetc()
  1820. {
  1821.     if( kbdqp )
  1822.         kbdqp = FALSE;
  1823.     else
  1824.     {
  1825.         if( kbdpoll && fcntl( 0, F_SETFL, kbdflgs ) < 0 )
  1826.             abort();
  1827.         kbdpoll = FALSE;
  1828.         while (read(0, &kbdq, 1) != 1)
  1829.             ;
  1830.     }
  1831. #ifdef BIT7EVEN
  1832.     return ( kbdq & 0x7f );
  1833. #else
  1834.     return ( kbdq & 0xff );
  1835. #endif
  1836. }
  1837.  
  1838. /*
  1839.  * Return non-FALSE if typeahead is pending.
  1840.  *
  1841.  * If already got unread typeahead, do nothing.
  1842.  * Otherwise, set keyboard to O_NDELAY if not already, and try
  1843.  * a one character read.
  1844.  */
  1845. typeahead()
  1846. {
  1847.     if( !kbdqp )
  1848.     {
  1849.         if( !kbdpoll && fcntl( 0, F_SETFL, kbdflgs | O_NDELAY ) < 0 )
  1850.             abort();
  1851.         kbdqp = (1 == read( 0, &kbdq, 1 ));
  1852.     }
  1853.     return ( kbdqp );
  1854. }
  1855.  
  1856.  
  1857. /*
  1858.  * panic:  print error and die, leaving core file.
  1859.  * Don't know why this is needed (daveb).
  1860.  */
  1861. panic(s)
  1862. char *s;
  1863. {
  1864.     fprintf(stderr, "%s\r\n", s);
  1865.     abort();
  1866. }
  1867.  
  1868.  
  1869. /*
  1870. ** This should check the size of the window, and reset if needed.
  1871. */
  1872.  
  1873. setttysize()
  1874. {
  1875. #ifdef    TIOCGWINSZ
  1876.     if (ioctl(0, TIOCGWINSZ, (char *) &winsize) == 0) {
  1877.         nrow = winsize . ws_row;
  1878.         ncol = winsize . ws_col;
  1879.     } else
  1880. #endif
  1881.     if ((nrow=tgetnum ("li")) <= 0
  1882.     || (ncol=tgetnum ("co")) <= 0) {
  1883.         nrow = 24;
  1884.         ncol = 80;
  1885.     }
  1886.     if (nrow > NROW)            /* Don't crash if the    */
  1887.         nrow = NROW;            /* termcap entry is    */
  1888.     if (ncol > NCOL)            /* too big.        */
  1889.         ncol = NCOL;
  1890. }
  1891.  
  1892. \Rogue\Monster\
  1893. else
  1894.   echo "will not over write ./ttyio.c"
  1895. fi
  1896. if `test ! -s ./ttykbd.c`
  1897. then
  1898. echo "writing ./ttykbd.c"
  1899. cat > ./ttykbd.c << '\Rogue\Monster\'
  1900. /*
  1901.  * Name:    MicroEmacs
  1902.  * Version:    30
  1903.  *        Termcap keyboard driver
  1904.  * Created:    21-Aug-1986
  1905.  *        Mic Kaczmarczik ...!ihnp4!seismo!ut-sally!ut-ngp!mic
  1906.  * Last edit:    20-Feb-1987
  1907.  *
  1908.  * [ Several of the nasty comments about the XKEYS code are
  1909.  *   by me.  [Bob Larson (usc-oberon!blarson)]  It is my opinion
  1910.  *   that function keys cannot be made to work with standard
  1911.  *   emacs keybindings except on a very limited set of terminals.
  1912.  *   I just work with to many that do not fit the assumptions Mic's
  1913.  *   XKEYS code makes to consider it useful to me, and think that
  1914.  *   others considering using this code should look and see what
  1915.  *   it realy does first.
  1916.  * ]
  1917.  *
  1918.  * If XKEYS is defined this routine looks for the following 
  1919.  * termcap sequences, which are obtained by "tty.c":
  1920.  *
  1921.  *    ks    -- start keypad transmit mode
  1922.  *    ke    -- end keypad transmit mode
  1923.  *    kh    -- home key
  1924.  *    ku    -- up arrow
  1925.  *    kd    -- down arrow
  1926.  *    kl    -- left arrow
  1927.  *    kr    -- right arrow
  1928.  *    k0-k9    -- standard termcap function keys
  1929.  *    l0-l9    -- labels for termcap function keys
  1930.  *    (nonstandard)
  1931.  *    K0-K9    -- extra keys that we look for -- the get mapped
  1932.  *           internally to F10-F19
  1933.  *    L0-L9    -- labels for same.
  1934.  *
  1935.  * Bugs/features/problems:
  1936.  *
  1937.  *    XKEYS and DPROMPT do not work together well.
  1938.  *
  1939.  *    If the META introducer is used as the initial character of
  1940.  *    a function key sequence, what should the key parser do when the
  1941.  *    user wants to type a META-ed key, or just the META introducer
  1942.  *    alone?    This is of practical importance on DEC terminals, where
  1943.  *    the META introducer is the Escape key.  Even worse things happen
  1944.  *    on terminals that have something (or more than one thing) other
  1945.  *    than the META introducer as the inital character of a function
  1946.  *    sequence.
  1947.  *
  1948.  *    The approach I took was that if the META introducer is the first
  1949.  *    character in a function sequence, and the second character c
  1950.  *    isn't part of a function key sequence, the parser returns
  1951.  *    (KMETA | c).  If it sees two META introducers in a row, it
  1952.  *    returns one instance of METACH.   This approach is subject to
  1953.  *    discussion and debate, but it works.  [In at lease some cases.]
  1954.  *
  1955.  *    If the META introducer is NOT the first character in a function
  1956.  *    sequence (including arrow keys) this code has a very nasty
  1957.  *    side effect of eating that key.  For example, on an Adds viewpoint
  1958.  *    60, six normal control characters are eaten if you have defined
  1959.  *    XKEYS and put the keys in the termcap.  More than a little 
  1960.  *    creativity is needed because ^U is one of the arrow keys, and
  1961.  *    prefixes aren't bindable.
  1962.  *
  1963.  *    [ From a quick look at the code, it seems that a single character
  1964.  *      funciton key won't work, but it is still put in the table.
  1965.  *    ]
  1966.  */
  1967. #include    "def.h"
  1968.  
  1969. /*
  1970.  * Default key name table.  Can be overridden by
  1971.  * definitions of l0-l9 in the termcap entry.  You
  1972.  * can't redefine the names for the arrow keys
  1973.  * and the home key.
  1974.  */
  1975.  
  1976. #ifdef    XKEYS
  1977. /* key sequences (from tty.c) */
  1978. extern    char    *K[], *L[], *KS, *KE, *KH, *KU, *KD, *KL, *KR;
  1979. extern    int    putpad();    /* also from tty.c */
  1980. char    *keystrings[] = {
  1981.     NULL,        "Home",        "Down-Arrow",    "Up-Arrow",
  1982.     "Left-Arrow",    "Right-Arrow",    "F0",        "F1",
  1983.     "F2",        "F3",        "F4",        "F5",
  1984.     "F6",        "F7",        "F8",        "F9",
  1985.     "F10",        "F11",        "F12",        "F13",
  1986.     "F14",        "F15",        "F16",        "F17",
  1987.     "F18",        "F19",        NULL,        NULL,
  1988.     NULL,        NULL,        NULL,        NULL
  1989. };
  1990. #else
  1991. char    *keystrings[] = {
  1992.     NULL,        NULL,        NULL,        NULL,
  1993.     NULL,        NULL,        NULL,        NULL,
  1994.     NULL,        NULL,        NULL,        NULL,
  1995.     NULL,        NULL,        NULL,        NULL,
  1996.     NULL,        NULL,        NULL,        NULL,
  1997.     NULL,        NULL,        NULL,        NULL,
  1998.     NULL,        NULL,        NULL,        NULL,
  1999.     NULL,        NULL,        NULL,        NULL
  2000. };
  2001. #endif
  2002.  
  2003. #ifdef    XKEYS
  2004. /*
  2005.  * Type declarations for data structure we
  2006.  * use to parse for function key sequences
  2007.  */
  2008. #define    NODE        0    /* internal node        */
  2009. #define    VALUE        1    /* internal key code value    */
  2010. #define SENTINEL    2    /* sentinel value        */
  2011.  
  2012. typedef struct trienode {
  2013.     int type;    /* one of NODE, LEAF */
  2014.     struct trienode *sibling, *child;
  2015.     KEY value;
  2016. } TRIENODE, *TRIE;
  2017.  
  2018. TRIE keywords, sentinel, talloc(), tinsert();
  2019. #endif
  2020.  
  2021. /*
  2022.  * Get keyboard character, and interpret
  2023.  * any special keys on the keyboard.  If XKEYS is
  2024.  * #defined, use a dictionary organized as a
  2025.  * trie to keep the parsing overhead down.
  2026.  *
  2027.  * To keep the function call overhead down, do the
  2028.  * first level of parse() inside getkbd().
  2029.  *
  2030.  * Also, since ESC (the usual value of METACH) is
  2031.  * the first character in many function key sequences,
  2032.  * we  return (KMETA | ch) if METACH-<ch> is not
  2033.  * the start of an escape sequence.  Blecch.  Furthermore,
  2034.  * if we see METACH-METACH, we return the value METACH.
  2035.  * Phhhht.
  2036.  */
  2037. getkbd()
  2038. {
  2039. #ifndef    XKEYS
  2040.     return (ttgetc());
  2041. #else
  2042.     register TRIE    t;
  2043.     register int    c;
  2044.     KEY        code;
  2045.  
  2046.     c = ttgetc();
  2047.     for (t = keywords; t->type == NODE; t = t->sibling)
  2048.         if (t->value == c)
  2049.         {    /* possible function key sequence  */
  2050.             if (c != METACH)
  2051.                 return (parse(t->child));
  2052.             else
  2053.             {        /* maybe sequence, maybe META char */
  2054.                 c = ttgetc();
  2055.                 for (t = t->child; t->type == NODE; t = t->sibling)
  2056.                     if (t->value == c)
  2057.                         return (parse(t->child));
  2058.                 /* METACH-METACH -> METACH */
  2059.                 if (c == METACH)
  2060.                     return (METACH);
  2061.                 /* Else make c into a META character */
  2062.                 if (ISLOWER(c) != FALSE)
  2063.                     c = TOUPPER(c);
  2064.                 if (c>=0x00 && c<=0x1F)
  2065.                     c = KCTRL | (c+'@');
  2066.                 return (KMETA | c);
  2067.             }
  2068.         }
  2069.     return (c);
  2070. #endif
  2071. }
  2072.  
  2073. #ifdef    XKEYS
  2074. static parse(first)
  2075. TRIE first;
  2076. {
  2077.     register TRIE    t;
  2078.     register int    c;
  2079.  
  2080.     if (first->type == VALUE)        /* found a match!    */
  2081.         return (first->value);
  2082.  
  2083.     c = ttgetc();
  2084.     for (t = first; t->type == NODE; t = t->sibling)/* look thru list   */
  2085.         if (t->value == c)
  2086.             return (parse(t->child));    /* try next level   */
  2087.     return (c);    /* nothing matched */
  2088. }
  2089. #endif
  2090.  
  2091. /*
  2092.  * If XKEYS is defined, get key definitions from the termcap 
  2093.  * entry and put them in the parse table.
  2094.  *
  2095.  * If DO_METAKEY is defined, kbd.c expects function keys to have
  2096.  * KCTRL set to differentiate them from real meta-ized control
  2097.  * characters. To do this, we put the code (KCTRL | fkey) into
  2098.  * the dictionary, instead of the code itself.  Trust me...
  2099.  */
  2100.  
  2101. #ifdef    DO_METAKEY
  2102. #define    FNKEY(c) ((KEY) (KCTRL | c))
  2103. #else
  2104. #define    FNKEY(c) ((KEY) c)
  2105. #endif
  2106.  
  2107. ttykeymapinit()
  2108. {
  2109. #ifdef    XKEYS
  2110.     register int    i;
  2111.     register int    s;
  2112.     register char    *cp;
  2113.     register SYMBOL    *sp;
  2114.     extern     int    spawncmd();
  2115.     extern   int    spawninsert();
  2116.  
  2117.     if (KS && *KS)            /* turn on keypad    */
  2118.         putpad(KS);        
  2119.  
  2120.     tinit();            /* set up initial trie */
  2121.  
  2122.     for (i = 0; i < NFKEYS; i++)
  2123.     {
  2124.         if (K[i] && *K[i])
  2125.             adddict(K[i], FNKEY(KF0 + i));
  2126.         if (L[i] && *L[i])    /* record new name */
  2127.             keystrings[(KF0-KFIRST)+i] = L[i];
  2128.     }
  2129.  
  2130.     /*
  2131.      * Add the home and arrow keys
  2132.      */
  2133.     if (KH && *KH)
  2134.         adddict(KH, FNKEY(KHOME));
  2135.     if (KU && *KU)
  2136.         adddict(KU, FNKEY(KUP));
  2137.     if (KD && *KD)
  2138.         adddict(KD, FNKEY(KDOWN));
  2139.     if (KL && *KL)
  2140.         adddict(KL, FNKEY(KLEFT));
  2141.     if (KR && *KR)
  2142.         adddict(KR, FNKEY(KRIGHT));
  2143.  
  2144.     /*
  2145.      * Bind things to the movement keys
  2146.      */
  2147.     keydup(KHOME,    "beginning-of-buffer");    /* for now */
  2148.     keydup(KUP,    "previous-line");
  2149.     keydup(KDOWN,    "next-line");
  2150.     keydup(KLEFT,    "backward-char");
  2151.     keydup(KRIGHT,    "forward-char");
  2152.  
  2153.     keydup( KF1,    "save-buffers-kill-emacs");
  2154. #ifdef MISLOG
  2155.     keydup( KF2,    "newlog");
  2156. #endif
  2157.     keydup( KF3,    "previous-line");
  2158.     keydup( KF4,    "next-line");
  2159.     keydup( KF5,    "open-line");            /* modified function */
  2160.     keydup( KF6,    "fill-paragraph");
  2161. #ifdef MENU_INSERT
  2162.     keyadd( KF7,    spawninsert,    "spawn-insert-file");/* new function */
  2163. #endif
  2164.     keydup( KF8,    "toggle-insert-overstrike");    /* new function */
  2165.     keydup( KF9,    "save-buffer");
  2166.     keydup( KF0,    "rotate-help");            /* new function */
  2167.     keydup( KF11,    "restart-edit");        /* new function */
  2168.     keyadd( KF12,    spawncmd,    "print-buffer");/* new function */
  2169.     keydup( KF13,    "search-forward");
  2170.     keydup( KF14,    "backward-paragraph");
  2171.     keydup( KF15,    "forward-paragraph");
  2172.     keydup( KF16,    "beginning-of-line");
  2173.     keydup( KF17,    "end-of-line");
  2174.     keydup( KF18,    "delete-line");            /* new function */
  2175.     keydup( KF19,    "kill-emacs");            /* new function */
  2176.  
  2177. #endif    XKEYS
  2178. }
  2179.  
  2180. #ifdef    XKEYS
  2181. /*
  2182.  * Clean up the keyboard -- called by tttidy()
  2183.  */
  2184. ttykeymaptidy()
  2185. {
  2186.     tdelete(keywords);    /* get rid of parse tree    */
  2187.     free(sentinel);        /* remove sentinel value    */
  2188.     if (KE && *KE)
  2189.         putpad(KE);    /* turn off keypad        */
  2190. }
  2191.  
  2192. /*
  2193.  * * * * * * * * Dictionary management * * * * * * * * *
  2194.  */
  2195.  
  2196. /*
  2197.  * Add a key string to the dictionary.
  2198.  */
  2199.  
  2200. static adddict(kstr, kcode)
  2201. char *kstr;
  2202. KEY kcode;
  2203. {
  2204.     keywords = tinsert(kstr, kcode, keywords);
  2205. }
  2206.  
  2207. /*
  2208.  * Initialize the parse tree by creating the sentinel value
  2209.  */
  2210.  
  2211. static tinit()
  2212. {
  2213.     keywords = sentinel = talloc();
  2214.     sentinel->type = SENTINEL;
  2215.     sentinel->value = (KEY) -1;
  2216.     sentinel->sibling = sentinel->child = sentinel;    /* set up a loop */
  2217. }
  2218.  
  2219. /*
  2220.  * Deallocate all the space used by the trie --
  2221.  * Tell all the siblings to deallocate space, then
  2222.  * all the children.
  2223.  */
  2224.  
  2225. static tdelete(t)
  2226. register TRIE t;
  2227. {
  2228.     if (t->type != SENTINEL)
  2229.     {
  2230.         tdelete(t->sibling);
  2231.         tdelete(t->child);
  2232.         free(t);
  2233.     }
  2234. }
  2235.  
  2236. /*
  2237.  * Insert a dictionary key string and a value into the dictionary,
  2238.  * returning as the value the first sibling in the current sublevel,
  2239.  * which may have been changed by an insertion into the list of siblings.
  2240.  */
  2241.  
  2242. static TRIE tinsert(kstring, kcode, first)
  2243. register char *kstring;
  2244. register KEY kcode;
  2245. TRIE first;
  2246. {
  2247.     register TRIE    match;
  2248.     register TRIE    p;
  2249.     
  2250.     if (!*kstring)
  2251.     {    /* base case -- return a value node */
  2252.         p = talloc();
  2253.         p->type = VALUE;
  2254.         p->value = kcode;
  2255.         p->sibling = p->child = sentinel;
  2256.         return (p);
  2257.     }
  2258.     /* recursive case -- insert rest of string in trie */
  2259.  
  2260.     /* search for sibling that matches the current character */
  2261.     match = NULL;
  2262.     for (p = first; p->type == NODE; p = p->sibling)
  2263.         if (p->value == *kstring)
  2264.         {
  2265.             match = p;
  2266.             break;
  2267.         }
  2268.  
  2269.     if (match == NULL)
  2270.     {    /* if not, add it to beginning of the list */
  2271.         match = talloc();
  2272.         match->type = NODE;
  2273.         match->value = *kstring;
  2274.         match->sibling = first;
  2275.         match->child = sentinel;
  2276.         first = match;
  2277.     }
  2278.     /* add rest of string to this child's subtrie */
  2279.     match->child = tinsert(kstring+1, kcode, match->child);
  2280.     return (first);
  2281. }
  2282.  
  2283. /*
  2284.  * Allocate a trie node
  2285.  */
  2286. static TRIE talloc()
  2287. {
  2288.     char *malloc();
  2289.     TRIE t;
  2290.  
  2291.     if ((t = (TRIE) malloc(sizeof(TRIENODE))) == NULL)
  2292.         panic("talloc: can't allocate trie node!");
  2293.     return (t);
  2294. }
  2295. #endif
  2296. \Rogue\Monster\
  2297. else
  2298.   echo "will not over write ./ttykbd.c"
  2299. fi
  2300. if `test ! -s ./version.c`
  2301. then
  2302. echo "writing ./version.c"
  2303. cat > ./version.c << '\Rogue\Monster\'
  2304. /*
  2305.  * This file contains the string that get written 
  2306.  * out by the emacs-version command.
  2307.  * Rich had it generated by a command file. I do
  2308.  * it manually, until I can figure out a way to get
  2309.  * the MicroGnuEmacs version number generated in an
  2310.  * reasonable and automatic manner.
  2311.  */
  2312.  
  2313. char    *version = "TinyGnuEmacs 1b" ;
  2314.  
  2315. #ifdef __50SERIES
  2316. #ifndef __CI
  2317. static void dummmy(){}          /* work around bug in primos 64v mode */
  2318. #endif
  2319. #endif
  2320. \Rogue\Monster\
  2321. else
  2322.   echo "will not over write ./version.c"
  2323. fi
  2324. if `test ! -s ./window.c`
  2325. then
  2326. echo "writing ./window.c"
  2327. cat > ./window.c << '\Rogue\Monster\'
  2328. /*
  2329.  *        Window handling.
  2330.  */
  2331. #include    "def.h"
  2332.  
  2333. /*
  2334.  * Reposition dot in the current
  2335.  * window to line "n". If the argument is
  2336.  * positive, it is that line. If it is negative it
  2337.  * is that line from the bottom. If it is 0 the window
  2338.  * is centered (this is what the standard redisplay code
  2339.  * does).  If GOSREC is undefined, default is 0, so it acts like GNU.
  2340.  * If GOSREC is defined, with no argument it defaults to 1
  2341.  * and works like in Gosling.
  2342.  */
  2343. /*ARGSUSED*/
  2344. reposition(f, n, k)
  2345. {
  2346. #ifndef    GOSREC
  2347.     curwp->w_force = ((f == FALSE) ? 0 : n) ;
  2348. #else
  2349.     curwp->w_force = n;
  2350. #endif
  2351.     curwp->w_flag |= WFFORCE;
  2352.     sgarbf = TRUE;
  2353.     return (TRUE);
  2354. }
  2355.  
  2356. /*
  2357.  * Refresh the display. A call is made to the
  2358.  * "ttresize" entry in the terminal handler, which tries
  2359.  * to reset "nrow" and "ncol". They will, however, never
  2360.  * be set outside of the NROW or NCOL range. If the display
  2361.  * changed size, arrange that everything is redone, then
  2362.  * call "update" to fix the display. We do this so the
  2363.  * new size can be displayed. In the normal case the
  2364.  * call to "update" in "main.c" refreshes the screen,
  2365.  * and all of the windows need not be recomputed.
  2366.  * Note that when you get to the "display unusable"
  2367.  * message, the screen will be messed up. If you make
  2368.  * the window bigger again, and send another command,
  2369.  * everything will get fixed!
  2370.  */
  2371. /*ARGSUSED*/
  2372. refresh(f, n, k)
  2373. {
  2374.     register WINDOW    *wp;
  2375.     register int    oldnrow;
  2376.     register int    oldncol;
  2377.  
  2378.     oldnrow = nrow;
  2379.     oldncol = ncol;
  2380.     ttresize();
  2381.     if (nrow!=oldnrow || ncol!=oldncol)
  2382.     {
  2383.         wp = wheadp;            /* Find last.        */
  2384.         while (wp->w_wndp != NULL)
  2385.             wp = wp->w_wndp;
  2386.         if (nrow < wp->w_toprow+3)
  2387.         {    /* Check if too small.    */
  2388.             ewprintf("Display unusable");
  2389.             return (FALSE);
  2390.         }        
  2391.         wp->w_ntrows = nrow-wp->w_toprow-2;
  2392.         sgarbf = TRUE;
  2393.         update();
  2394.         if (kbdmop == NULL) ewprintf("New size %d by %d", nrow, ncol);
  2395.     }
  2396.     else
  2397.         sgarbf = TRUE;
  2398.     return (TRUE);
  2399. }
  2400. \Rogue\Monster\
  2401. else
  2402.   echo "will not over write ./window.c"
  2403. fi
  2404. if `test ! -s ./word.c`
  2405. then
  2406. echo "writing ./word.c"
  2407. cat > ./word.c << '\Rogue\Monster\'
  2408. /*
  2409.  *        Word mode commands.
  2410.  * The routines in this file
  2411.  * implement commands that work word at
  2412.  * a time. There are all sorts of word mode
  2413.  * commands. If I do any sentence and/or paragraph
  2414.  * mode commands, they are likely to be put in
  2415.  * this file.
  2416.  */
  2417. #include    "def.h"
  2418.  
  2419.  
  2420. /*
  2421.  * Kill forward by "n" words.
  2422.  */
  2423. /*ARGSUSED*/
  2424. delfword(f, n, k)
  2425. {
  2426.     register RSIZE    size;
  2427.     register LINE    *dotp;
  2428.     register int    doto;
  2429.  
  2430.     if (n < 0)
  2431.         return (FALSE);
  2432.     if ((lastflag&CFKILL) == 0)        /* Purge kill buffer.    */
  2433.         kdelete();
  2434.     thisflag |= CFKILL;
  2435.     dotp = curwp->w_dotp;
  2436.     doto = curwp->w_doto;
  2437.     size = 0;
  2438.     while (n--)
  2439.     {
  2440.         while (inword() == FALSE)
  2441.         {
  2442.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2443.                 goto out;    /* Hit end of buffer.    */
  2444.             ++size;
  2445.         }
  2446.         while (inword() != FALSE)
  2447.         {
  2448.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2449.                 goto out;    /* Hit end of buffer.    */
  2450.             ++size;
  2451.         }
  2452.     }
  2453. out:
  2454.     curwp->w_dotp = dotp;
  2455.     curwp->w_doto = doto;
  2456.     return (ldelete(size, KFORW));
  2457. }
  2458.  
  2459. /*
  2460.  * Kill backwards by "n" words. The rules
  2461.  * for success and failure are now different, to prevent
  2462.  * strange behavior at the start of the buffer. The command
  2463.  * only fails if something goes wrong with the actual delete
  2464.  * of the characters. It is successful even if no characters
  2465.  * are deleted, or if you say delete 5 words, and there are
  2466.  * only 4 words left. I considered making the first call
  2467.  * to "backchar" special, but decided that that would just
  2468.  * be wierd. Normally this is bound to "M-Rubout" and
  2469.  * to "M-Backspace".
  2470.  */
  2471. /*ARGSUSED*/
  2472. delbword(f, n, k)
  2473. {
  2474.     register RSIZE    size;
  2475.  
  2476.     if (n < 0)
  2477.         return (FALSE);
  2478.     if ((lastflag&CFKILL) == 0)        /* Purge kill buffer.    */
  2479.         kdelete();
  2480.     thisflag |= CFKILL;
  2481.     if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2482.         return (TRUE);            /* Hit buffer start.    */
  2483.     size = 1;                /* One deleted.        */
  2484.     while (n--)
  2485.     {
  2486.         while (inword() == FALSE)
  2487.         {
  2488.             if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2489.                 goto out;    /* Hit buffer start.    */
  2490.             ++size;
  2491.         }
  2492.         while (inword() != FALSE)
  2493.         {
  2494.             if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2495.                 goto out;    /* Hit buffer start.    */
  2496.             ++size;
  2497.         }
  2498.     }
  2499.     if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2500.         return (FALSE);
  2501.     --size;                    /* Undo assumed delete.    */
  2502. out:
  2503.     return (ldelete(size, KBACK));
  2504. }
  2505.  
  2506. /*
  2507.  * Return TRUE if the character at dot
  2508.  * is a character that is considered to be
  2509.  * part of a word. The word character list is hard
  2510.  * coded. Should be setable.
  2511.  */
  2512. inword()
  2513. {
  2514.     if (curwp->w_doto == llength(curwp->w_dotp))
  2515.         return (FALSE);
  2516.     if (ISWORD(lgetc(curwp->w_dotp, curwp->w_doto)) != FALSE)
  2517.         return (TRUE);
  2518.     return (FALSE);
  2519. }
  2520. \Rogue\Monster\
  2521. else
  2522.   echo "will not over write ./word.c"
  2523. fi
  2524. echo "Finished archive 1 of 5"
  2525. exit
  2526.  
  2527. -- 
  2528. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  2529. Mark A. Hargrove                                             U.S. TeleCenters
  2530. Voice: 408-496-1800                                          Santa Clara, CA
  2531. uucp : {dual, hoptoad, hplabs, portal, ptsfa}!well!ustel
  2532.