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

  1. From: ustel@well.UUCP (Mark Hargrove)
  2. Newsgroups: comp.sources.misc
  3. Subject: v02i052: Unify TEXT fields from ACCELL Part 3/5
  4. Message-ID: <7220@ncoast.UUCP>
  5. Date: 11 Feb 88 00:49:28 GMT
  6. Approved: allbery@ncoast.UUCP
  7.  
  8. Comp.sources.misc: Volume 2, Issue 52
  9. Submitted-By: "Mark Hargrove" <ustel@well.UUCP>
  10. Archive-Name: accell-text/Part3
  11.  
  12. [Nice to know someone else posts Unify/Accell tools.  ++bsa]
  13.  
  14. #!/bin/sh
  15. # to extract, remove the header and type "sh filename"
  16. if `test ! -s ./cinfo.c`
  17. then
  18. echo "writing ./cinfo.c"
  19. cat > ./cinfo.c << '\Rogue\Monster\'
  20. /*
  21.  *        Character class tables.
  22.  * Do it yourself character classification
  23.  * macros, that understand the multinational character set,
  24.  * and let me ask some questions the standard macros (in
  25.  * ctype.h) don't let you ask.
  26.  */
  27. #include    "def.h"
  28.  
  29. /*
  30.  * This table, indexed by a character drawn
  31.  * from the 256 member character set, is used by my
  32.  * own character type macros to answer questions about the
  33.  * type of a character. It handles the full multinational
  34.  * character set, and lets me ask some questions that the
  35.  * standard "ctype" macros cannot ask.
  36.  */
  37. char    cinfo[256] = {
  38.     _C,        _C,        _C,        _C,    /* 0x0X    */
  39.     _C,        _C,        _C,        _C,
  40.     _C,        _C,        _C,        _C,
  41.     _C,        _C,        _C,        _C,
  42.     _C,        _C,        _C,        _C,    /* 0x1X    */
  43.     _C,        _C,        _C,        _C,
  44.     _C,        _C,        _C,        _C,
  45.     _C,        _C,        _C,        _C,
  46.     0,        _P,        0,        0,    /* 0x2X    */
  47.     _W,        _W,        0,        _W,
  48.     0,        0,        0,        0,
  49.     0,        0,        _P,        0,
  50.     _W,        _W,        _W,        _W,    /* 0x3X    */
  51.     _W,        _W,        _W,        _W,
  52.     _W,        _W,        0,        0,
  53.     0,        0,        0,        _P,
  54.     0,        _U|_W,        _U|_W,        _U|_W,    /* 0x4X    */
  55.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  56.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  57.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  58.     _U|_W,        _U|_W,        _U|_W,        _U|_W,    /* 0x5X    */
  59.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  60.     _U|_W,        _U|_W,        _U|_W,        0,
  61.     0,        0,        0,        0,
  62.     0,        _L|_W,        _L|_W,        _L|_W,    /* 0x6X    */
  63.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  64.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  65.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  66.     _L|_W,        _L|_W,        _L|_W,        _L|_W,    /* 0x7X    */
  67.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  68.     _L|_W,        _L|_W,        _L|_W,        0,
  69.     0,        0,        0,        _C,
  70.     0,        0,        0,        0,    /* 0x8X    */
  71.     0,        0,        0,        0,
  72.     0,        0,        0,        0,
  73.     0,        0,        0,        0,
  74.     0,        0,        0,        0,    /* 0x9X    */
  75.     0,        0,        0,        0,
  76.     0,        0,        0,        0,
  77.     0,        0,        0,        0,
  78.     0,        0,        0,        0,    /* 0xAX    */
  79.     0,        0,        0,        0,
  80.     0,        0,        0,        0,
  81.     0,        0,        0,        0,
  82.     0,        0,        0,        0,    /* 0xBX    */
  83.     0,        0,        0,        0,
  84.     0,        0,        0,        0,
  85.     0,        0,        0,        0,
  86.     _U|_W,        _U|_W,        _U|_W,        _U|_W,    /* 0xCX    */
  87.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  88.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  89.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  90.     0,        _U|_W,        _U|_W,        _U|_W,    /* 0xDX    */
  91.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  92.     _U|_W,        _U|_W,        _U|_W,        _U|_W,
  93.     _U|_W,        _U|_W,        0,        _W,
  94.     _L|_W,        _L|_W,        _L|_W,        _L|_W,    /* 0xEX    */
  95.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  96.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  97.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  98.     0,        _L|_W,        _L|_W,        _L|_W,    /* 0xFX    */
  99.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  100.     _L|_W,        _L|_W,        _L|_W,        _L|_W,
  101.     _L|_W,        _L|_W,        0,        0
  102. };
  103.  
  104. #ifdef __50SERIES
  105.   /* Primos C blows up without this - wierd, really wierd... */
  106.   static void dummy(){}
  107. #endif
  108. \Rogue\Monster\
  109. else
  110.   echo "will not over write ./cinfo.c"
  111. fi
  112. if `test ! -s ./display.c`
  113. then
  114. echo "writing ./display.c"
  115. cat > ./display.c << '\Rogue\Monster\'
  116. /*
  117.  * The functions in this file handle redisplay. The
  118.  * redisplay system knows almost nothing about the editing
  119.  * process; the editing functions do, however, set some
  120.  * hints to eliminate a lot of the grinding. There is more
  121.  * that can be done; the "vtputc" interface is a real
  122.  * pig. Two conditional compilation flags; the GOSLING
  123.  * flag enables dynamic programming redisplay, using the
  124.  * algorithm published by Jim Gosling in SIGOA. The MEMMAP
  125.  * changes things around for memory mapped video. With
  126.  * both off, the terminal is a VT52.
  127.  */
  128. #include    "def.h"
  129.  
  130. /*
  131.  * You can change these back to the types
  132.  * implied by the name if you get tight for space. If you
  133.  * make both of them "int" you get better code on the VAX.
  134.  * They do nothing if this is not Gosling redisplay, except
  135.  * for change the size of a structure that isn't used.
  136.  * A bit of a cheat.
  137.  */
  138. /* These defines really belong in sysdef.h */
  139. #ifndef XCHAR
  140. #  define    XCHAR    int
  141. #  define    XSHORT    int
  142. #endif
  143.  
  144. #ifdef    STANDOUT_GLITCH
  145. extern int SG;                /* number of standout glitches    */
  146. #endif
  147.  
  148. /*
  149.  * A video structure always holds
  150.  * an array of characters whose length is equal to
  151.  * the longest line possible. Only some of this is
  152.  * used if "ncol" isn't the same as "NCOL".
  153.  */
  154. typedef    struct    {
  155.     short    v_hash;            /* Hash code, for compares.    */
  156.     short    v_flag;            /* Flag word.            */
  157.     short    v_color;        /* Color of the line.        */
  158.     XSHORT    v_cost;            /* Cost of display.        */
  159.     char    v_text[NCOL];        /* The actual characters.    */
  160. }    VIDEO;
  161.  
  162. #define    VFCHG    0x0001            /* Changed.            */
  163. #define    VFHBAD    0x0002            /* Hash and cost are bad.    */
  164.  
  165. /*
  166.  * SCORE structures hold the optimal
  167.  * trace trajectory, and the cost of redisplay, when
  168.  * the dynamic programming redisplay code is used.
  169.  * If no fancy redisplay, this isn't used. The trace index
  170.  * fields can be "char", and the score a "short", but
  171.  * this makes the code worse on the VAX.
  172.  */
  173. typedef    struct    {
  174.     XCHAR    s_itrace;        /* "i" index for track back.    */
  175.     XCHAR    s_jtrace;        /* "j" index for trace back.    */
  176.     XSHORT    s_cost;            /* Display cost.        */
  177. }    SCORE;
  178.  
  179. int    sgarbf    = TRUE;            /* TRUE if screen is garbage.    */
  180. int    vtrow    = 0;            /* Virtual cursor row.        */
  181. int    vtcol    = 0;            /* Virtual cursor column.    */
  182. int    tthue    = CNONE;        /* Current color.        */
  183. int    ttrow    = HUGE;            /* Physical cursor row.        */
  184. int    ttcol    = HUGE;            /* Physical cursor column.    */
  185. int    tttop    = HUGE;            /* Top of scroll region.    */
  186. int    ttbot    = HUGE;            /* Bottom of scroll region.    */
  187.  
  188. VIDEO    *vscreen[NROW-1];        /* Edge vector, virtual.    */
  189. VIDEO    *pscreen[NROW-1];        /* Edge vector, physical.    */
  190. VIDEO    video[2*(NROW-1)];        /* Actual screen data.        */
  191. VIDEO    blanks;                /* Blank line image.        */
  192.  
  193. /*
  194.  * Some predeclerations to make ANSI compilers happy
  195.  */
  196. VOID    vtinit();
  197. VOID    vttidy();
  198. VOID    vtmove();
  199. VOID    vtputc();
  200. VOID    vteeol();
  201. VOID    update();
  202. VOID    ucopy();
  203. VOID    uline();
  204. VOID    modeline();
  205. VOID    hash();
  206. VOID    setscores();
  207. VOID    traceback();
  208.  
  209. #ifdef    GOSLING
  210. /*
  211.  * This matrix is written as an array because
  212.  * we do funny things in the "setscores" routine, which
  213.  * is very compute intensive, to make the subscripts go away.
  214.  * It would be "SCORE    score[NROW][NROW]" in old speak.
  215.  * Look at "setscores" to understand what is up.
  216.  */
  217. SCORE    score[NROW*NROW];
  218. #endif
  219.  
  220. /*
  221.  * Initialize the data structures used
  222.  * by the display code. The edge vectors used
  223.  * to access the screens are set up. The operating
  224.  * system's terminal I/O channel is set up. Fill the
  225.  * "blanks" array with ASCII blanks. The rest is done
  226.  * at compile time. The original window is marked
  227.  * as needing full update, and the physical screen
  228.  * is marked as garbage, so all the right stuff happens
  229.  * on the first call to redisplay.
  230.  */
  231. VOID
  232. vtinit()
  233. {
  234.     register VIDEO    *vp;
  235.     register int    i;
  236.  
  237.     ttopen();
  238.     ttinit();
  239.     vp = &video[0];
  240.     for (i=0; i<NROW-1; ++i)
  241.     {
  242.         vscreen[i] = vp;
  243.         ++vp;
  244.         pscreen[i] = vp;
  245.         ++vp;
  246.     }
  247.     blanks.v_color = CTEXT;
  248.     for (i=0; i<NCOL; ++i)
  249.         blanks.v_text[i] = ' ';
  250. }
  251.  
  252. /*
  253.  * Tidy up the virtual display system
  254.  * in anticipation of a return back to the host
  255.  * operating system. Right now all we do is position
  256.  * the cursor to the last line, erase the line, and
  257.  * close the terminal channel.
  258.  */
  259. VOID
  260. vttidy()
  261. {
  262.     ttcolor(CTEXT);
  263.     ttnowindow();                /* No scroll window.    */
  264.     ttmove(nrow-1, 0);            /* Echo line.        */
  265.     tteeol();
  266.     tttidy();
  267.     ttflush();
  268.     ttclose();
  269. }
  270.  
  271. /*
  272.  * Move the virtual cursor to an origin
  273.  * 0 spot on the virtual display screen. I could
  274.  * store the column as a character pointer to the spot
  275.  * on the line, which would make "vtputc" a little bit
  276.  * more efficient. No checking for errors.
  277.  */
  278. VOID
  279. vtmove(row, col)
  280. {
  281.     vtrow = row;
  282.     vtcol = col;
  283. }
  284.  
  285. /*
  286.  * Write a character to the virtual display,
  287.  * dealing with long lines and the display of unprintable
  288.  * things like control characters. Also expand tabs every 8
  289.  * columns. This code only puts printing characters into 
  290.  * the virtual display image. Special care must be taken when
  291.  * expanding tabs. On a screen whose width is not a multiple
  292.  * of 8, it is possible for the virtual cursor to hit the
  293.  * right margin before the next tab stop is reached. This
  294.  * makes the tab code loop if you are not careful.
  295.  * Three guesses how we found this.
  296.  */
  297. VOID
  298. vtputc(c) register int c;
  299. {
  300.     register VIDEO    *vp;
  301.  
  302.     vp = vscreen[vtrow];
  303.     if (vtcol >= ncol)
  304.         vp->v_text[ncol-1] = '$';
  305.         else if (
  306. #ifdef    NOTAB
  307.          !(mode&MNOTAB) &&
  308. #endif
  309.          c == '\t')
  310.     {
  311.         do {
  312.             vtputc(' ');
  313.         } while (vtcol<ncol && (vtcol&0x07)!=0);
  314.     }
  315.     else if (ISCTRL(c) != FALSE)
  316.     {
  317.         vtputc('^');
  318.         vtputc(c ^ 0x40);
  319.     } else
  320.         vp->v_text[vtcol++] = c;        
  321. }
  322.  
  323. /*
  324.  * Erase from the end of the
  325.  * software cursor to the end of the
  326.  * line on which the software cursor is
  327.  * located. The display routines will decide
  328.  * if a hardware erase to end of line command
  329.  * should be used to display this.
  330.  */
  331. VOID
  332. vteeol()
  333. {
  334.     register VIDEO    *vp;
  335.  
  336.     vp = vscreen[vtrow];
  337.     while (vtcol < ncol)
  338.         vp->v_text[vtcol++] = ' ';
  339. }
  340.  
  341. /*
  342.  * Make sure that the display is
  343.  * right. This is a three part process. First,
  344.  * scan through all of the windows looking for dirty
  345.  * ones. Check the framing, and refresh the screen.
  346.  * Second, make sure that "currow" and "curcol" are
  347.  * correct for the current window. Third, make the
  348.  * virtual and physical screens the same.
  349.  */
  350. VOID
  351. update()
  352. {
  353.     register LINE    *lp;
  354.     register WINDOW    *wp;
  355.     register VIDEO    *vp1;
  356.     VIDEO        *vp2;
  357.     register int    i;
  358.     register int    j;
  359.     register int    c;
  360.     register int    hflag;
  361.     register int    currow;
  362.     register int    curcol;
  363.     register int    offs;
  364.     register int    size;
  365.     VOID traceback ();
  366.     VOID uline ();
  367.  
  368.     if (typeahead()) return;
  369.     if (sgarbf)
  370.     {                /* must update everything */
  371.         wp = wheadp; 
  372.         while(wp != NULL)
  373.         {
  374.             wp->w_flag |= WFMODE | WFHARD;
  375.             wp = wp->w_wndp;
  376.         }
  377.     }
  378.     hflag = FALSE;                /* Not hard.        */
  379.     wp = wheadp;
  380.     while (wp != NULL)
  381.     {
  382.         if (wp->w_flag != 0)
  383.         {        /* Need update.        */
  384.             if ((wp->w_flag&WFFORCE) == 0)
  385.             {
  386.                 lp = wp->w_linep;
  387.                 for (i=0; i<wp->w_ntrows; ++i)
  388.                 {
  389.                     if (lp == wp->w_dotp)
  390.                         goto out;
  391.                     if (lp == wp->w_bufp->b_linep)
  392.                         break;
  393.                     lp = lforw(lp);
  394.                 }
  395.             }
  396.             i = wp->w_force;    /* Reframe this one.    */
  397.             if (i > 0)
  398.             {
  399.                 --i;
  400.                 if (i >= wp->w_ntrows)
  401.                     i = wp->w_ntrows-1;
  402.             } else if (i < 0)
  403.             {
  404.                 i += wp->w_ntrows;
  405.                 if (i < 0)
  406.                     i = 0;
  407.             } else
  408.                 i = wp->w_ntrows/2;
  409.             lp = wp->w_dotp;
  410.             while (i!=0 && lback(lp)!=wp->w_bufp->b_linep)
  411.             {
  412.                 --i;
  413.                 lp = lback(lp);
  414.             }
  415.             wp->w_linep = lp;
  416.             wp->w_flag |= WFHARD;    /* Force full.        */
  417.         out:
  418.             lp = wp->w_linep;    /* Try reduced update.    */
  419.             i  = wp->w_toprow;
  420.             if ((wp->w_flag&~WFMODE) == WFEDIT)
  421.             {
  422.                 while (lp != wp->w_dotp)
  423.                 {
  424.                     ++i;
  425.                     lp = lforw(lp);
  426.                 }
  427.                 vscreen[i]->v_color = CTEXT;
  428.                 vscreen[i]->v_flag |= (VFCHG|VFHBAD);
  429.                 vtmove(i, 0);
  430.                 for (j=0; j<llength(lp); ++j)
  431.                     vtputc(lgetc(lp, j));
  432.                 vteeol();
  433.             }
  434.             else if ((wp->w_flag&(WFEDIT|WFHARD)) != 0)
  435.             {
  436.                 hflag = TRUE;
  437.                 while (i < wp->w_toprow+wp->w_ntrows)
  438.                 {
  439.                     vscreen[i]->v_color = CTEXT;
  440.                     vscreen[i]->v_flag |= (VFCHG|VFHBAD);
  441.                     vtmove(i, 0);
  442.                     if (lp != wp->w_bufp->b_linep)
  443.                     {
  444.                         for (j=0; j<llength(lp); ++j)
  445.                             vtputc(lgetc(lp, j));
  446.                         lp = lforw(lp);
  447.                     }
  448.                     vteeol();
  449.                     ++i;
  450.                 }
  451.             }
  452.             if ((wp->w_flag&WFMODE) != 0)
  453.                 modeline(wp);
  454.             wp->w_flag  = 0;
  455.             wp->w_force = 0;
  456.         }        
  457.         wp = wp->w_wndp;
  458.     }
  459.     lp = curwp->w_linep;            /* Cursor location.    */
  460.     currow = curwp->w_toprow;
  461.     while (lp != curwp->w_dotp)
  462.     {
  463.         ++currow;
  464.         lp = lforw(lp);
  465.     }
  466.     curcol = 0;
  467.     i = 0;
  468.     while (i < curwp->w_doto)
  469.     {
  470.         c = lgetc(lp, i++);
  471.                 if (
  472. #ifdef    NOTAB
  473.             !(mode&MNOTAB) &&
  474. #endif
  475.             c == '\t')
  476.             curcol |= 0x07;
  477.         else if (ISCTRL(c) != FALSE)
  478.             ++curcol;
  479.         ++curcol;
  480.     }
  481.     if (curcol >= ncol)            /* Long line.        */
  482.         curcol = ncol-1;
  483.     if (sgarbf != FALSE)
  484.     {                    /* Screen is garbage.    */
  485.         sgarbf = FALSE;            /* Erase-page clears    */
  486.         epresf = FALSE;            /* the message area.    */
  487.         tttop  = HUGE;            /* Forget where you set    */
  488.         ttbot  = HUGE;            /* scroll region.    */
  489.         tthue  = CNONE;            /* Color unknown.    */
  490.         ttmove(0, 0);
  491.         tteeop();
  492.         for (i=0; i<nrow-1; ++i)
  493.         {
  494.             uline(i, vscreen[i], &blanks);
  495.             ucopy(vscreen[i], pscreen[i]);
  496.         }
  497.         ttmove(currow, curcol);
  498.         ttflush();
  499.         return;
  500.     }
  501. #ifdef    GOSLING
  502.     if (hflag != FALSE)
  503.     {            /* Hard update?        */
  504.         for (i=0; i<nrow-1; ++i)
  505.         {    /* Compute hash data.    */
  506.             hash(vscreen[i]);
  507.             hash(pscreen[i]);
  508.         }
  509.         offs = 0;            /* Get top match.    */
  510.         while (offs != nrow-1)
  511.         {
  512.             vp1 = vscreen[offs];
  513.             vp2 = pscreen[offs];
  514.             if (vp1->v_color != vp2->v_color
  515.             ||  vp1->v_hash  != vp2->v_hash)
  516.                 break;
  517.             uline(offs, vp1, vp2);
  518.             ucopy(vp1, vp2);
  519.             ++offs;
  520.         }
  521.         if (offs == nrow-1)
  522.         {        /* Might get it all.    */
  523.             ttmove(currow, curcol);
  524.             ttflush();
  525.             return;
  526.         }
  527.         size = nrow-1;            /* Get bottom match.    */
  528.         while (size != offs)
  529.         {
  530.             vp1 = vscreen[size-1];
  531.             vp2 = pscreen[size-1];
  532.             if (vp1->v_color != vp2->v_color
  533.             ||  vp1->v_hash  != vp2->v_hash)
  534.                 break;
  535.             uline(size-1, vp1, vp2);
  536.             ucopy(vp1, vp2);
  537.             --size;
  538.         }
  539.         if ((size -= offs) == 0)    /* Get screen size.    */
  540.             panic("Illegal screen size in update");
  541.         setscores(offs, size);        /* Do hard update.    */
  542.         traceback(offs, size, size, size);
  543.         for (i=0; i<size; ++i)
  544.             ucopy(vscreen[offs+i], pscreen[offs+i]);
  545.         ttmove(currow, curcol);
  546.         ttflush();
  547.         return;            
  548.     }
  549. #endif
  550.     for (i=0; i<nrow-1; ++i)
  551.     {        /* Easy update.        */
  552.         vp1 = vscreen[i];
  553.         vp2 = pscreen[i];
  554.         if ((vp1->v_flag&VFCHG) != 0)
  555.         {
  556.             uline(i, vp1, vp2);
  557.             ucopy(vp1, vp2);
  558.         }
  559.     }
  560.     ttmove(currow, curcol);
  561.     ttflush();
  562. }
  563.  
  564. /*
  565.  * Update a saved copy of a line,
  566.  * kept in a VIDEO structure. The "vvp" is
  567.  * the one in the "vscreen". The "pvp" is the one
  568.  * in the "pscreen". This is called to make the
  569.  * virtual and physical screens the same when
  570.  * display has done an update.
  571.  */
  572. VOID
  573. ucopy(vvp, pvp) register VIDEO *vvp; register VIDEO *pvp;
  574. {
  575.  
  576.     vvp->v_flag &= ~VFCHG;            /* Changes done.    */
  577.     pvp->v_flag  = vvp->v_flag;        /* Update model.    */
  578.     pvp->v_hash  = vvp->v_hash;
  579.     pvp->v_cost  = vvp->v_cost;
  580.     pvp->v_color = vvp->v_color;
  581.     bcopy(vvp->v_text, pvp->v_text, ncol);
  582. }
  583.  
  584. /*
  585.  * Update a single line. This routine only
  586.  * uses basic functionality (no insert and delete character,
  587.  * but erase to end of line). The "vvp" points at the VIDEO
  588.  * structure for the line on the virtual screen, and the "pvp"
  589.  * is the same for the physical screen. Avoid erase to end of
  590.  * line when updating CMODE color lines, because of the way that
  591.  * reverse video works on most terminals.
  592.  */
  593. VOID uline(row, vvp, pvp) VIDEO *vvp; VIDEO *pvp;
  594. {
  595. #ifdef    MEMMAP
  596.     putline(row+1, 1, &vvp->v_text[0]);
  597. #else
  598.     register char    *cp1;
  599.     register char    *cp2;
  600.     register char    *cp3;
  601.     char        *cp4;
  602.     char        *cp5;
  603.     register int    nbflag;
  604.  
  605.     if (vvp->v_color != pvp->v_color)
  606.     {                /* Wrong color,            */
  607.         ttmove(row, 0);        /* do a full redraw.        */
  608. #ifdef    STANDOUT_GLITCH
  609.         if (pvp->v_color != CTEXT && SG >= 0) tteeol();
  610. #endif
  611.         ttcolor(vvp->v_color);
  612. #ifdef    STANDOUT_GLITCH
  613.         cp1 = &vvp->v_text[SG > 0 ? SG : 0];
  614.         /* the odd code for SG==0 is to avoid putting the invisable
  615.          * glitch character on the next line.  
  616.          * (Hazeltine executive 80 model 30)
  617.          */
  618.         cp2 = &vvp->v_text[ncol - (SG >= 0 ? (SG!=0 ? SG : 1) : 0)];
  619. #else
  620.         cp1 = &vvp->v_text[0];
  621.         cp2 = &vvp->v_text[ncol];
  622. #endif
  623.         while (cp1 != cp2)
  624.         {
  625.             ttputc(*cp1++);
  626.             ++ttcol;
  627.         }
  628. #ifndef    MOVE_STANDOUT
  629.         ttcolor(CTEXT);
  630. #endif
  631.         return;
  632.     }
  633.     cp1 = &vvp->v_text[0];            /* Compute left match.    */
  634.     cp2 = &pvp->v_text[0];
  635.     while (cp1!=&vvp->v_text[ncol] && cp1[0]==cp2[0])
  636.     {
  637.         ++cp1;
  638.         ++cp2;
  639.     }
  640.     if (cp1 == &vvp->v_text[ncol])        /* All equal.        */
  641.         return;
  642.     nbflag = FALSE;
  643.     cp3 = &vvp->v_text[ncol];        /* Compute right match.    */
  644.     cp4 = &pvp->v_text[ncol];
  645.     while (cp3[-1] == cp4[-1])
  646.     {
  647.         --cp3;
  648.         --cp4;
  649.         if (cp3[0] != ' ')        /* Note non-blanks in    */
  650.             nbflag = TRUE;        /* the right match.    */
  651.     }
  652.     cp5 = cp3;                /* Is erase good?    */
  653.     if (nbflag==FALSE && vvp->v_color==CTEXT)
  654.     {
  655.         while (cp5!=cp1 && cp5[-1]==' ')
  656.             --cp5;
  657.         /* Alcyon hack */
  658.         if ((int)(cp3-cp5) <= tceeol)
  659.             cp5 = cp3;
  660.     }
  661.     /* Alcyon hack */
  662.     ttmove(row, (int)(cp1-&vvp->v_text[0]));
  663. #ifdef    STANDOUT_GLITCH
  664.     if (vvp->v_color != CTEXT && SG > 0)
  665.     {
  666.         if(cp1 < &vvp->v_text[SG]) cp1 = &vvp->v_text[SG];
  667.         if(cp5 > &vvp->v_text[ncol-SG]) cp5 = &vvp->v_text[ncol-SG];
  668.     } else if (SG < 0)
  669. #endif
  670.     ttcolor(vvp->v_color);
  671.     while (cp1 != cp5)
  672.     {
  673.         ttputc(*cp1++);
  674.         ++ttcol;
  675.     }
  676.     if (cp5 != cp3)                /* Do erase.        */
  677.         tteeol();
  678. #endif
  679. }
  680.  
  681. #define LAST_ROT 5
  682. static int rotat_pos = 1;
  683. /*
  684.  * The mode line reflects the the Function-Key help
  685.  * information, rather than the state of the current window/buffer
  686.  * (since there is only one window in the TINY version).
  687.  */
  688. VOID
  689. modeline(wp)
  690. register WINDOW *wp;
  691. {
  692.     register int    row,    /* display row */
  693.             col;    /* current column */
  694.     register BUFFER    *bp;
  695.  
  696.     row = wp->w_toprow+wp->w_ntrows;    /* Location.        */
  697.     vscreen[row]->v_color = CMODE;        /* Mode line color.    */
  698.     vscreen[row]->v_flag |= (VFCHG|VFHBAD);    /* Recompute, display.    */
  699.     vtmove(row, 0);                /* Seek to right line.    */
  700.     bp = wp->w_bufp;
  701.     if ((mode & MOVRSTK) == 0)
  702.         col = vtputs(" Insert |");
  703.     else
  704.         col = vtputs(" Replace|");
  705.  
  706.     switch (rotat_pos)
  707.     {
  708.         case 1:        /* Function Keys 1-4 */
  709.             col += vtputs("F1 -Prv Form |");
  710. #ifdef MISLOG
  711.             col += vtputs("F2 -Time Stmp|");
  712. #else
  713.             col += vtputs("             |");
  714. #endif
  715.             col += vtputs("F3 -Prv Line |");
  716.             col += vtputs("F4 -Nxt Line |");
  717.             break;
  718.         case 2:        /* Function Keys 5-8 */
  719.             col += vtputs("F5 -Open Line|");
  720.             col += vtputs("F6 -Fix Para |");
  721. #ifdef MENU_INSERT
  722.             col += vtputs("F7 -Ins File |");
  723. #else
  724.             col += vtputs("             |");
  725. #endif
  726.             col += vtputs("F8 -Rep/Ins  |");
  727.             break;
  728.         case 3:        /* Function Keys 9,11-13 */
  729.             col += vtputs("F9 -Save     |");
  730.             col += vtputs("F11-Restart  |");
  731.             col += vtputs("F12-Print    |");
  732.             col += vtputs("F13-Search   |");
  733.             break;
  734.         case 4:        /* Function Keys 14-17 */
  735.             col += vtputs("F14-Prv Para |");
  736.             col += vtputs("F15-Nxt Para |");
  737.             col += vtputs("F16-Beg Line |");
  738.             col += vtputs("F17-End Line |");
  739.             break;
  740.         case 5:        /* Function Keys 18-19+ */
  741.             col += vtputs("F18-Del Line |");
  742.             col += vtputs("F19-Zoom Can |");
  743.             col += vtputs("             |");
  744.             col += vtputs("             |");
  745.             break;
  746.         default:    /* shouldn't get here. set to known state */
  747.             rotat_pos = 1;
  748.             break;
  749.     } /* end switch */
  750.     while (col < 60)
  751.     {
  752.         vtputc(' ');
  753.         ++col;
  754.     }
  755.     col += vtputs("F10- More Key");
  756.     while (col < ncol)
  757.     {            /* Pad out.        */
  758.         vtputc(' ');
  759.         ++col;
  760.     }
  761. }
  762.  
  763. /*
  764.  * This routine does the actual rotating of the fields
  765.  * of the mode-line help message.
  766.  */
  767. /*ARGSUSED*/
  768. rotatmode( f, n, k)
  769. {
  770.     rotat_pos += 1;
  771.     if (rotat_pos > LAST_ROT)
  772.         rotat_pos = 1;
  773.     modeline(wheadp);        /* NOTE: this only works because only */
  774.     wheadp->w_flag &= WFHARD;    /* one window allowed in TINY version */
  775.     return TRUE;
  776. }
  777.  
  778. /*
  779.  * output a string to the mode line, report how long it was.
  780.  */
  781. vtputs(s) register char *s;
  782. {
  783.     register int n = 0;
  784.  
  785.     while (*s != '\0')
  786.     {
  787.         vtputc(*s++);
  788.         ++n;
  789.     }
  790.     return n;
  791. }
  792. #ifdef    GOSLING
  793. /*
  794.  * Compute the hash code for
  795.  * the line pointed to by the "vp". Recompute
  796.  * it if necessary. Also set the approximate redisplay
  797.  * cost. The validity of the hash code is marked by
  798.  * a flag bit. The cost understand the advantages
  799.  * of erase to end of line. Tuned for the VAX
  800.  * by Bob McNamara; better than it used to be on
  801.  * just about any machine.
  802.  */
  803. VOID
  804. hash(vp) register VIDEO *vp;
  805. {
  806.     register int    i;
  807.     register int    n;
  808.     register char    *s;
  809.  
  810.     if ((vp->v_flag&VFHBAD) != 0)
  811.     {        /* Hash bad.        */
  812.         s = &vp->v_text[ncol-1];
  813.         for (i=ncol; i!=0; --i, --s)
  814.             if (*s != ' ')
  815.                 break;
  816.         n = ncol-i;            /* Erase cheaper?    */
  817.         if (n > tceeol)
  818.             n = tceeol;
  819.         vp->v_cost = i+n;        /* Bytes + blanks.    */
  820.         for (n=0; i!=0; --i, --s)
  821.             n = (n<<5) + n + *s;
  822.         vp->v_hash = n;            /* Hash code.        */
  823.         vp->v_flag &= ~VFHBAD;        /* Flag as all done.    */
  824.     }
  825. }
  826.  
  827. /*
  828.  * Compute the Insert-Delete
  829.  * cost matrix. The dynamic programming algorithm
  830.  * described by James Gosling is used. This code assumes
  831.  * that the line above the echo line is the last line involved
  832.  * in the scroll region. This is easy to arrange on the VT100
  833.  * because of the scrolling region. The "offs" is the origin 0
  834.  * offset of the first row in the virtual/physical screen that
  835.  * is being updated; the "size" is the length of the chunk of
  836.  * screen being updated. For a full screen update, use offs=0
  837.  * and size=nrow-1.
  838.  *
  839.  * Older versions of this code implemented the score matrix by
  840.  * a two dimensional array of SCORE nodes. This put all kinds of
  841.  * multiply instructions in the code! This version is written to
  842.  * use a linear array and pointers, and contains no multiplication
  843.  * at all. The code has been carefully looked at on the VAX, with
  844.  * only marginal checking on other machines for efficiency. In
  845.  * fact, this has been tuned twice! Bob McNamara tuned it even
  846.  * more for the VAX, which is a big issue for him because of
  847.  * the 66 line X displays.
  848.  *
  849.  * On some machines, replacing the "for (i=1; i<=size; ++i)" with
  850.  * i = 1; do { } while (++i <=size)" will make the code quite a
  851.  * bit better; but it looks ugly.
  852.  */
  853. VOID
  854. setscores(offs, size)
  855. {
  856.     register SCORE    *sp;
  857.     SCORE        *sp1;
  858.     register int    tempcost;
  859.     register int    bestcost;
  860.     register int    j;
  861.     register int    i;
  862.     register VIDEO    **vp;
  863.     VIDEO        **pp, **vbase, **pbase;
  864.  
  865.     vbase = &vscreen[offs-1];        /* By hand CSE's.    */
  866.     pbase = &pscreen[offs-1];
  867.     score[0].s_itrace = 0;            /* [0, 0]        */
  868.     score[0].s_jtrace = 0;
  869.     score[0].s_cost   = 0;
  870.     sp = &score[1];                /* Row 0, inserts.    */
  871.     tempcost = 0;
  872.     vp = &vbase[1];
  873.     for (j=1; j<=size; ++j)
  874.     {
  875.         sp->s_itrace = 0;
  876.         sp->s_jtrace = j-1;
  877.         tempcost += tcinsl;
  878.         tempcost += (*vp)->v_cost;
  879.         sp->s_cost = tempcost;
  880.         ++vp;
  881.         ++sp;
  882.     }
  883.     sp = &score[NROW];            /* Column 0, deletes.    */
  884.     tempcost = 0;
  885.     for (i=1; i<=size; ++i)
  886.     {
  887.         sp->s_itrace = i-1;
  888.         sp->s_jtrace = 0;
  889.         tempcost  += tcdell;
  890.         sp->s_cost = tempcost;
  891.         sp += NROW;
  892.     }
  893.     sp1 = &score[NROW+1];            /* [1, 1].        */
  894.     pp = &pbase[1];
  895.     for (i=1; i<=size; ++i)
  896.     {
  897.         sp = sp1;
  898.         vp = &vbase[1];
  899.         for (j=1; j<=size; ++j)
  900.         {
  901.             sp->s_itrace = i-1;
  902.             sp->s_jtrace = j;
  903.             bestcost = (sp-NROW)->s_cost;
  904.             if (j != size)        /* Cd(A[i])=0 @ Dis.    */
  905.                 bestcost += tcdell;
  906.             tempcost = (sp-1)->s_cost;
  907.             tempcost += (*vp)->v_cost;
  908.             if (i != size)        /* Ci(B[j])=0 @ Dsj.    */
  909.                 tempcost += tcinsl;
  910.             if (tempcost < bestcost)
  911.             {
  912.                 sp->s_itrace = i;
  913.                 sp->s_jtrace = j-1;
  914.                 bestcost = tempcost;
  915.             }
  916.             tempcost = (sp-NROW-1)->s_cost;
  917.             if ((*pp)->v_color != (*vp)->v_color
  918.             ||  (*pp)->v_hash  != (*vp)->v_hash)
  919.                 tempcost += (*vp)->v_cost;
  920.             if (tempcost < bestcost)
  921.             {
  922.                 sp->s_itrace = i-1;
  923.                 sp->s_jtrace = j-1;
  924.                 bestcost = tempcost;
  925.             }
  926.             sp->s_cost = bestcost;
  927.             ++sp;            /* Next column.        */
  928.             ++vp;
  929.         }
  930.         ++pp;
  931.         sp1 += NROW;            /* Next row.        */
  932.     }
  933. }
  934.  
  935. /*
  936.  * Trace back through the dynamic programming cost
  937.  * matrix, and update the screen using an optimal sequence
  938.  * of redraws, insert lines, and delete lines. The "offs" is
  939.  * the origin 0 offset of the chunk of the screen we are about to
  940.  * update. The "i" and "j" are always started in the lower right
  941.  * corner of the matrix, and imply the size of the screen.
  942.  * A full screen traceback is called with offs=0 and i=j=nrow-1.
  943.  * There is some do-it-yourself double subscripting here,
  944.  * which is acceptable because this routine is much less compute
  945.  * intensive then the code that builds the score matrix!
  946.  */
  947. VOID traceback(offs, size, i, j)
  948. {
  949.     register int    itrace;
  950.     register int    jtrace;
  951.     register int    k;
  952.     register int    ninsl;
  953.     register int    ndraw;
  954.     register int    ndell;
  955.  
  956.     if (i==0 && j==0)            /* End of update.    */
  957.         return;
  958.     itrace = score[(NROW*i) + j].s_itrace;
  959.     jtrace = score[(NROW*i) + j].s_jtrace;
  960.     if (itrace == i)
  961.     {            /* [i, j-1]        */
  962.         ninsl = 0;            /* Collect inserts.    */
  963.         if (i != size)
  964.             ninsl = 1;
  965.         ndraw = 1;
  966.         while (itrace!=0 || jtrace!=0)
  967.         {
  968.             if (score[(NROW*itrace) + jtrace].s_itrace != itrace)
  969.                 break;
  970.             jtrace = score[(NROW*itrace) + jtrace].s_jtrace;
  971.             if (i != size)
  972.                 ++ninsl;
  973.             ++ndraw;
  974.         }
  975.         traceback(offs, size, itrace, jtrace);
  976.         if (ninsl != 0)
  977.         {
  978.             ttcolor(CTEXT);
  979.             ttinsl(offs+j-ninsl, offs+size-1, ninsl);
  980.         }
  981.         do {                /* B[j], A[j] blank.    */
  982.             k = offs+j-ndraw;
  983.             uline(k, vscreen[k], &blanks);
  984.         } while (--ndraw);
  985.         return;
  986.     }
  987.     if (jtrace == j)
  988.     {            /* [i-1, j]        */
  989.         ndell = 0;            /* Collect deletes.    */
  990.         if (j != size)
  991.             ndell = 1;
  992.         while (itrace!=0 || jtrace!=0)
  993.         {
  994.             if (score[(NROW*itrace) + jtrace].s_jtrace != jtrace)
  995.                 break;
  996.             itrace = score[(NROW*itrace) + jtrace].s_itrace;
  997.             if (j != size)
  998.                 ++ndell;
  999.         }
  1000.         if (ndell != 0)
  1001.         {
  1002.             ttcolor(CTEXT);
  1003.             ttdell(offs+i-ndell, offs+size-1, ndell);
  1004.         }
  1005.         traceback(offs, size, itrace, jtrace);
  1006.         return;
  1007.     }
  1008.     traceback(offs, size, itrace, jtrace);
  1009.     k = offs+j-1;
  1010.     uline(k, vscreen[k], pscreen[offs+i-1]);
  1011. }
  1012. #endif
  1013. \Rogue\Monster\
  1014. else
  1015.   echo "will not over write ./display.c"
  1016. fi
  1017. if `test ! -s ./echo.c`
  1018. then
  1019. echo "writing ./echo.c"
  1020. cat > ./echo.c << '\Rogue\Monster\'
  1021. /*
  1022.  *        Echo line reading and writing.
  1023.  *
  1024.  * Common routines for reading
  1025.  * and writing characters in the echo line area
  1026.  * of the display screen. Used by the entire
  1027.  * known universe.
  1028.  */
  1029. #include    "def.h"
  1030. #ifdef    VARARGS
  1031. #  include    <varargs.h>
  1032.     static veread();
  1033. VOID    ewprintf();
  1034. #endif
  1035. static VOID    eformat();
  1036. static VOID    eputi();
  1037. static VOID    eputl();
  1038. static VOID    eputs();
  1039. static VOID    eputc();
  1040.  
  1041. int    epresf    = FALSE;        /* Stuff in echo line flag.    */
  1042. /*
  1043.  * Erase the echo line.
  1044.  */
  1045. VOID
  1046. eerase()
  1047. {
  1048.     ttcolor(CTEXT);
  1049.     ttmove(nrow-1, 0);
  1050.     tteeol();
  1051.     ttflush();
  1052.     epresf = FALSE;
  1053. }
  1054.  
  1055. /*
  1056.  * Ask "yes" or "no" question.
  1057.  * Return ABORT if the user answers the question
  1058.  * with the abort ("^G") character. Return FALSE
  1059.  * for "no" and TRUE for "yes". No formatting
  1060.  * services are available. No newline required.
  1061.  */
  1062. eyorn(sp) char *sp;
  1063. {
  1064.     register KEY    s;
  1065.  
  1066.     if (kbdmop == NULL) ewprintf("%s? (y or n) ", sp);
  1067.     for (;;)
  1068.     {
  1069.         s = getkey(0);
  1070.         if (s == 'y' || s == 'Y') return (TRUE);
  1071.         if (s == 'n' || s == 'N') return (FALSE);
  1072.         if (s == (KCTRL|'G') || s == (KCTLX|KCTRL|'G')
  1073.         ||  s == (KMETA|KCTRL|'G'))
  1074.         {
  1075.             (VOID) ctrlg(FALSE, 1, KRANDOM);
  1076.             return ABORT;
  1077.         }
  1078.         if (kbdmop == NULL)
  1079.             ewprintf("Please answer y or n.  %s? (y or n) ", sp);
  1080.     }
  1081.     /*NOTREACHED*/
  1082. }
  1083.  
  1084. /*
  1085.  * Like eyorn, but for more important question. User must type either all of
  1086.  * "yes" or "no", and the trainling newline.
  1087.  */
  1088. eyesno(sp) char *sp;
  1089. {
  1090.     register int    s;
  1091.     char        buf[64];
  1092.  
  1093.     s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp);
  1094.     for (;;)
  1095.     {
  1096.         if (s == ABORT) return ABORT;
  1097.         if (s != FALSE)
  1098.         {
  1099.             if ((buf[0] == 'y' || buf[0] == 'Y')
  1100.             &&  (buf[1] == 'e' || buf[1] == 'E')
  1101.             &&  (buf[2] == 's' || buf[2] == 'S')) return TRUE;
  1102.             if ((buf[0] == 'n' || buf[0] == 'N')
  1103.             &&  (buf[1] == 'o' || buf[0] == 'O')) return FALSE;
  1104.         }
  1105.         s = ereply("Please answer yes or no.  %s? (yes or no) ",
  1106.                buf, sizeof(buf), sp);
  1107.     }
  1108.     /*NOTREACHED*/
  1109. }
  1110. /*
  1111.  * Write out a prompt, and read back a
  1112.  * reply. The prompt is now written out with full "ewprintf"
  1113.  * formatting, although the arguments are in a rather strange
  1114.  * place. This is always a new message, there is no auto
  1115.  * completion, and the return is echoed as such.
  1116.  */
  1117. #ifdef    VARARGS
  1118. ereply(va_alist)
  1119. va_dcl
  1120. {
  1121.     register int i;
  1122.     va_list pvar;
  1123.     register char *fp, *buf;
  1124.     register int nbuf;
  1125.     
  1126.     va_start(pvar);
  1127.     fp = va_arg(pvar, char *);
  1128.     buf = va_arg(pvar, char *);
  1129.     nbuf = va_arg(pvar, int);
  1130.     i = veread(fp, buf, nbuf, EFNEW|EFCR, &pvar);
  1131.     va_end(pvar);
  1132.     return i;
  1133. }
  1134. #else
  1135. /* VARARGS3 */
  1136. ereply(fp, buf, nbuf, arg) char *fp, *buf; int nbuf; long arg;
  1137. {
  1138.     return (eread(fp, buf, nbuf, EFNEW|EFCR, (char *)&arg));
  1139. }
  1140. #endif
  1141.  
  1142. /*
  1143.  * This is the general "read input from the
  1144.  * echo line" routine. The basic idea is that the prompt
  1145.  * string "prompt" is written to the echo line, and a one
  1146.  * line reply is read back into the supplied "buf" (with
  1147.  * maximum length "len"). The "flag" contains EFNEW (a
  1148.  * new prompt), an EFFUNC (autocomplete), or EFCR (echo
  1149.  * the carriage return as CR).
  1150.  */
  1151. /* VARARGS4 */
  1152. #ifdef    VARARGS
  1153. eread(va_alist)
  1154. va_dcl
  1155. {
  1156.     va_list pvar;
  1157.     char *fp, *buf;
  1158.     int nbuf, flag, i;
  1159.     va_start(pvar);
  1160.     fp   = va_arg(pvar, char *);
  1161.     buf  = va_arg(pvar, char *);
  1162.     nbuf = va_arg(pvar, int);
  1163.     flag = va_arg(pvar, int);
  1164.     i = veread(fp, buf, nbuf, flag, &pvar);
  1165.     va_end(pvar);
  1166.     return i;
  1167. }
  1168. #endif
  1169.  
  1170. #ifdef    VARARGS
  1171. static veread(fp, buf, nbuf, flag, ap) char *fp; char *buf; va_list *ap;
  1172. {
  1173. #else
  1174. eread(fp, buf, nbuf, flag, ap) char *fp; char *buf; char *ap;
  1175. {
  1176. #endif
  1177.     register int    cpos;
  1178.     register int    i;
  1179.     register KEY    c;
  1180.  
  1181.     cpos = 0;
  1182.     if (kbdmop != NULL)
  1183.     {            /* In a macro.        */
  1184.         while ((c = *kbdmop++) != '\0')
  1185.             buf[cpos++] = (char) c;
  1186.         buf[cpos] = '\0';
  1187.         goto done;
  1188.     }
  1189.     if ((flag&EFNEW)!=0 || ttrow!=nrow-1)
  1190.     {
  1191.         ttcolor(CTEXT);
  1192.         ttmove(nrow-1, 0);
  1193.         epresf = TRUE;
  1194.     } else
  1195.         eputc(' ');
  1196.     eformat(fp, ap);
  1197.     tteeol();
  1198.     ttflush();
  1199.     for (;;)
  1200.     {
  1201.         c = getkey(KQUOTE|KNOMAC);
  1202.         if ((flag&EFAUTO) != 0 && (c == ' ' || c == CCHR('I')))
  1203.         {
  1204.             cpos += complete(flag, c, buf, cpos);
  1205.             continue;
  1206.         }
  1207.         switch (c)
  1208.         {
  1209.         case 0x0A:
  1210.         case 0x0D:            /* Return, done.    */
  1211.             if ((flag&EFFUNC) != 0)
  1212.             {
  1213.                 if ((i = complete(flag, c, buf, cpos)) == 0)
  1214.                     continue;
  1215.                 if (i > 0) cpos += i;
  1216.             }
  1217.             buf[cpos] = '\0';
  1218.             if ((flag&EFCR) != 0)
  1219.             {
  1220.                 ttputc(0x0D);
  1221.                 ttflush();
  1222.             }
  1223.             if (kbdmip != NULL)
  1224.             {
  1225.                 if (kbdmip+cpos+1 > &kbdm[NKBDM-3])
  1226.                 {
  1227.                     ewprintf("Keyboard macro overflow");
  1228.                     ttflush();
  1229.                     return FALSE;
  1230.                 }
  1231.                 for (i = 0; i <= cpos; ++i)
  1232.                     *kbdmip++ = (KEY) buf[i];
  1233.             }
  1234.             goto done;
  1235.  
  1236.         case CCHR('G'):            /* Bell, abort.        */
  1237.             eputc(CCHR('G'));
  1238.             (VOID) ctrlg(FALSE, 0, KRANDOM);
  1239.             ttflush();
  1240.             return (ABORT);
  1241.  
  1242.         case 0x7F:            /* Rubout, erase.    */
  1243.             if (cpos != 0)
  1244.             {
  1245.                 ttputc('\b');
  1246.                 ttputc(' ');
  1247.                 ttputc('\b');
  1248.                 --ttcol;
  1249.                 if (ISCTRL(buf[--cpos]) != FALSE)
  1250.                 {
  1251.                     ttputc('\b');
  1252.                     ttputc(' ');
  1253.                     ttputc('\b');
  1254.                     --ttcol;
  1255.                 }
  1256.                 ttflush();
  1257.             }
  1258.             break;
  1259.  
  1260.         case CCHR('X'):            /* C-X            */
  1261.         case CCHR('U'):            /* C-U, kill line.    */
  1262.             while (cpos != 0)
  1263.             {
  1264.                 ttputc('\b');
  1265.                 ttputc(' ');
  1266.                 ttputc('\b');
  1267.                 --ttcol;
  1268.                 if (ISCTRL(buf[--cpos]) != FALSE)
  1269.                 {
  1270.                     ttputc('\b');
  1271.                     ttputc(' ');
  1272.                     ttputc('\b');
  1273.                     --ttcol;
  1274.                 }
  1275.             }
  1276.             ttflush();
  1277.             break;
  1278.  
  1279.         case CCHR('Q'):            /* C-Q, quote next    */
  1280.             c = getkey(KQUOTE|KNOMAC) ;
  1281.         default:            /* All the rest.    */
  1282.             if (cpos < nbuf-1)
  1283.             {
  1284.                 buf[cpos++] = (char) c;
  1285.                 eputc((char) c);
  1286.                 ttflush();
  1287.             }
  1288.         }
  1289.     }
  1290. done:
  1291.     if (buf[0] == '\0')
  1292.         return (FALSE);
  1293.     return (TRUE);
  1294. }
  1295.  
  1296. /*
  1297.  * do completion on a list of objects.
  1298.  */
  1299. complete(flags, c, buf, cpos) register char *buf; register int cpos;
  1300. {
  1301.     register LIST    *lh, *lh2;
  1302.     int        i, nxtra;
  1303.     int        nhits, bxtra;
  1304.     int        wflag = FALSE;
  1305.     int        msglen, nshown;
  1306.     char        *msg;
  1307.  
  1308.     if ((flags&EFFUNC) != 0) lh = &(symbol[0]->s_list);
  1309.     else if ((flags&EFBUF) != 0) lh = &(bheadp->b_list);
  1310.     else panic("broken complete call: flags");
  1311.  
  1312.     if (c == ' ') wflag = TRUE;
  1313.     else if (c != '\t' && c != 0x0D && c != 0x0A)
  1314.         panic("broken complete call: c");
  1315.  
  1316.     nhits = 0;
  1317.     nxtra = HUGE;
  1318.  
  1319.     while (lh != NULL)
  1320.     {
  1321.         for (i=0; i<cpos; ++i)
  1322.         {
  1323.             if (buf[i] != lh->l_name[i])
  1324.                 break;
  1325.         }
  1326.         if (i == cpos)
  1327.         {
  1328.             if (nhits == 0)
  1329.                 lh2 = lh;
  1330.             ++nhits;
  1331.             if (lh->l_name[i] == '\0') nxtra = -1;
  1332.             else
  1333.             {
  1334.                 bxtra = getxtra(lh, lh2, cpos, wflag);
  1335.                 if (bxtra < nxtra) nxtra = bxtra;
  1336.                 lh2 = lh;
  1337.             }
  1338.         }
  1339.         lh = lh->l_next;
  1340.     }
  1341.     if (nhits == 0)
  1342.         msg = " [No match]";
  1343.     else if (nhits > 1 && nxtra == 0)
  1344.         msg = " [Ambiguous]";
  1345.     else
  1346.     {        /* Got a match, do it to it */
  1347.         /*
  1348.          * Being lazy - ought to check length, but all things
  1349.          * autocompleted have known types/lengths.
  1350.          */ 
  1351.         if (nxtra < 0 && nhits > 1 && c == ' ') nxtra = 1;
  1352.         for (i = 0; i < nxtra; ++i)
  1353.         {
  1354.             buf[cpos] = lh2->l_name[cpos];
  1355.             eputc(buf[cpos++]);
  1356.         }
  1357.         ttflush();
  1358.         if (nxtra < 0 && c != 0x0D && c != 0x0A) return 0;
  1359.         return nxtra;
  1360.     }
  1361.         /* Set up backspaces, etc., being mindful of echo line limit */
  1362.     msglen = strlen(msg);
  1363.     nshown = (ttcol + msglen + 2 > ncol) ? 
  1364.             ncol - ttcol - 2 : msglen;
  1365.     eputs(msg);
  1366.     ttcol -= (i = nshown);        /* update ttcol!        */
  1367.     while (i--)            /* move back before msg        */
  1368.         ttputc('\b');
  1369.     ttflush();            /* display to user        */
  1370.     i = nshown;
  1371.     while (i--)            /* blank out    on next flush    */
  1372.         eputc(' ');
  1373.     ttcol -= (i = nshown);        /* update ttcol on BS's        */
  1374.     while (i--)
  1375.         ttputc('\b');        /* update ttcol again!        */
  1376.     return 0;
  1377.  
  1378. }
  1379.  
  1380. /*
  1381.  * The "lp1" and "lp2" point to list structures. The
  1382.  * "cpos" is a horizontal position in the name.
  1383.  * Return the longest block of characters that can be
  1384.  * autocompleted at this point. Sometimes the two
  1385.  * symbols are the same, but this is normal.
  1386.   */
  1387. getxtra(lp1, lp2, cpos, wflag) register LIST *lp1, *lp2; register int wflag;
  1388. {
  1389.     register int    i;
  1390.  
  1391.     i = cpos;
  1392.     for (;;)
  1393.     {
  1394.         if (lp1->l_name[i] != lp2->l_name[i]) break;
  1395.         if (lp1->l_name[i] == '\0') break;
  1396.         ++i;
  1397.         if (wflag && !ISWORD(lp1->l_name[i-1])) break;
  1398.     }
  1399.     return (i - cpos);
  1400. }
  1401.  
  1402. /*
  1403.  * Special "printf" for the echo line.
  1404.  * Each call to "ewprintf" starts a new line in the
  1405.  * echo area, and ends with an erase to end of the
  1406.  * echo line. The formatting is done by a call
  1407.  * to the standard formatting routine.
  1408.  */
  1409. #ifdef    VARARGS
  1410. VOID
  1411. ewprintf(va_alist)
  1412. va_dcl
  1413. {
  1414.     va_list pvar;
  1415.     register char *fp;
  1416.  
  1417.     va_start(pvar);
  1418.     fp = va_arg(pvar, char *);
  1419. #else
  1420. /* VARARGS1 */
  1421. ewprintf(fp, arg) char *fp;
  1422. {
  1423. #endif
  1424.     ttcolor(CTEXT);
  1425.     ttmove(nrow-1, 0);
  1426. #ifdef    VARARGS
  1427.     eformat(fp, &pvar);
  1428.     va_end(pvar);
  1429. #else
  1430.     eformat(fp, (char *)&arg);
  1431. #endif
  1432.     tteeol();
  1433.     ttflush();
  1434.     epresf = TRUE;
  1435. }
  1436.  
  1437. /*
  1438.  * Printf style formatting. This is
  1439.  * called by both "ewprintf" and "ereply" to provide
  1440.  * formatting services to their clients. The move to the
  1441.  * start of the echo line, and the erase to the end of
  1442.  * the echo line, is done by the caller.
  1443.  * Note: %c works, and prints the "name" of the key. However
  1444.  * the key must be cast to an int to avoid tripping over
  1445.  * various oddities in C argument passing.
  1446.  */
  1447. static VOID
  1448. eformat(fp, ap) register char *fp;
  1449. #ifdef VARARGS
  1450. register va_list *ap;
  1451. #else
  1452. register char *ap;
  1453. #endif
  1454. {
  1455.     register int    c;
  1456.     char        kname[NKNAME];
  1457.  
  1458.     while ((c = *fp++) != '\0')
  1459.     {
  1460.         if (c != '%')
  1461.             eputc(c);
  1462.         else
  1463.         {
  1464.             c = *fp++;
  1465.             switch (c)
  1466.             {
  1467.             case 'c':
  1468. #ifdef    VARARGS
  1469.                 keyname(kname, va_arg(*ap, int));
  1470. #else
  1471.                 /*NOSTRICT*/
  1472.                 keyname(kname, *(int *)ap);
  1473.                 ap += sizeof(int);
  1474. #endif
  1475.                 eputs(kname);
  1476.                 break;
  1477.  
  1478.             case 'd':
  1479. #ifdef    VARARGS
  1480.                 eputi(va_arg(*ap, int), 10);
  1481. #else
  1482.                 /*NOSTRICT*/
  1483.                 eputi(*(int *)ap, 10);
  1484.                 ap += sizeof(int);
  1485. #endif
  1486.                 break;
  1487.  
  1488.             case 'o':
  1489. #ifdef    VARARGS
  1490.                 eputi(va_arg(*ap, int), 8);
  1491. #else
  1492.                 /*NOSTRICT*/
  1493.                 eputi(*(int *)ap,  8);
  1494.                 ap += sizeof(int);
  1495. #endif
  1496.                 break;
  1497.  
  1498.             case 's':
  1499. #ifdef    VARARGS
  1500.                 eputs(va_arg(*ap, char *));
  1501. #else
  1502.                 /*NOSTRICT*/
  1503.                 eputs(*(char **)ap);
  1504.                 ap += sizeof(char *);
  1505. #endif
  1506.                 break;
  1507.             case 'l':/* explicit longword */
  1508.                 c = *fp++;
  1509.                 switch(c)
  1510.                 {
  1511.                 case 'd':
  1512. #ifdef    VARARGS
  1513.                     eputl((long)va_arg(*ap, long), 10L);
  1514. #else
  1515.                     /*NOSTRICT*/
  1516.                     eputl(*(long *)ap, 10L);
  1517.                     ap += sizeof(long);
  1518. #endif
  1519.                     break;
  1520.                 default:
  1521.                     eputc(c);
  1522.                     break;
  1523.                 }
  1524.                 break;
  1525.  
  1526.             default:
  1527.                 eputc(c);
  1528.             }
  1529.         }
  1530.     }
  1531. }
  1532.  
  1533. /*
  1534.  * Put integer, in radix "r".
  1535.  */
  1536. static VOID
  1537. eputi(i, r) register int i; register int r;
  1538. {
  1539.     register int    q;
  1540.  
  1541.     if ((q=i/r) != 0)
  1542.         eputi(q, r);
  1543.     eputc(i%r+'0');
  1544. }
  1545.  
  1546. /*
  1547.  * Put long, in radix "r".
  1548.  */
  1549. static VOID
  1550. eputl(l, r) register long l; register long r;
  1551. {
  1552.     register long    q;
  1553.  
  1554.     if ((q=l/r) != 0)
  1555.         eputl(q, r);
  1556.     eputc((int)(l%r)+'0');
  1557. }
  1558.  
  1559. /*
  1560.  * Put string.
  1561.  */
  1562. static VOID
  1563. eputs(s) register char *s;
  1564. {
  1565.     register int    c;
  1566.  
  1567.     while ((c = *s++) != '\0')
  1568.         eputc(c);
  1569. }
  1570.  
  1571. /*
  1572.  * Put character. Watch for
  1573.  * control characters, and for the line
  1574.  * getting too long.
  1575.  */
  1576. static VOID
  1577. eputc(c) register char c;
  1578. {
  1579.     if (ttcol+2 < ncol)
  1580.     {
  1581.         if (ISCTRL(c) != FALSE)
  1582.         {
  1583.             eputc('^');
  1584.             c ^= 0x40;
  1585.         }
  1586.         ttputc(c);
  1587.         ++ttcol;
  1588.     }
  1589. }
  1590.  
  1591. \Rogue\Monster\
  1592. else
  1593.   echo "will not over write ./echo.c"
  1594. fi
  1595. if `test ! -s ./extend.c`
  1596. then
  1597. echo "writing ./extend.c"
  1598. cat > ./extend.c << '\Rogue\Monster\'
  1599. /*
  1600.  *        Extended (M-X) commands.
  1601.  */
  1602. #include    "def.h"
  1603.  
  1604.  
  1605. /*
  1606.  * Extended command. Call the message line
  1607.  * routine to read in the command name and apply autocompletion
  1608.  * to it. When it comes back, look the name up in the symbol table
  1609.  * and run the command if it is found and has the right type.
  1610.  * Print an error if there is anything wrong.
  1611.  */
  1612. /*ARGSUSED*/
  1613. extend(f, n, k)
  1614. {
  1615.     register SYMBOL    *sp;
  1616.     register int    s;
  1617.     char        xname[NXNAME];
  1618.  
  1619.     if (f == FALSE)
  1620.         s = eread("M-x ", xname, NXNAME, EFNEW|EFFUNC
  1621. #ifndef VARARGS
  1622.              , (char *) NULL
  1623. #endif
  1624.              ) ;
  1625.     else
  1626.         s = eread("%d M-x ", xname, NXNAME, EFNEW|EFFUNC, 
  1627. #ifdef    VARARGS
  1628.              n
  1629. #else
  1630.              (char *) &n, (char *) NULL
  1631. #endif
  1632.              ) ;
  1633.     if (s != TRUE) return (s);
  1634.     if ((sp=symlookup(xname)) != NULL)
  1635.         return ((*sp->s_funcp)(f, n, KRANDOM));
  1636.     ewprintf("[No match]");
  1637.     return FALSE;
  1638. }
  1639.  
  1640. /*
  1641.  * This function will erase the current buffer, re-read the file, and
  1642.  * cancel the modification flag. It has to remember the file name.
  1643.  */
  1644. /*ARGSUSED*/
  1645. startover( f, n, k)
  1646. {
  1647.     BUFFER *bp;
  1648.  
  1649.     bp = wheadp->w_bufp;
  1650.     if (bclear(bp) != FALSE)    /* user did not abort it */
  1651.     {
  1652.         insertfile( bp->b_fname, (char *)NULL);
  1653.         notmodified( FALSE, 0, KRANDOM);
  1654.         sgarbf = TRUE;
  1655.     }
  1656. }
  1657.  
  1658. /*
  1659.  * This function will quit Emacs without saving any files,
  1660.  * or asking about saving them. Just call quit with an argument.
  1661.  */
  1662. /*ARGSUSED*/
  1663. reallyquit( f, n, k)
  1664. {
  1665.     extern int quit();
  1666.  
  1667.     quit( TRUE, 1, KRANDOM);
  1668. }
  1669.  
  1670. /*
  1671.  * This function will delete the current line. It is easy because
  1672.  * all of the work is done in "killline". The cursor may be anywhere
  1673.  * on it, not just at the beginning.
  1674.  */
  1675. /*ARGSUSED*/
  1676. deleteline( f, n, k)
  1677. {
  1678.     killline( TRUE, 0, KRANDOM);    /* kill beginning of line */
  1679.     killline( TRUE, 1, KRANDOM);    /* kill end including nl */
  1680. }
  1681.  
  1682. #ifdef    STARTUP
  1683. /*
  1684.  * Define the commands needed to do startup-file processing.
  1685.  * This code is mostly a kludge just so we can get startup-file processing.
  1686.  *
  1687.  * If you're serious about having this code, you should rewrite it.
  1688.  * To wit: 
  1689.  *    It has lots of funny things in it to make the startup-file look
  1690.  *    like a GNU startup file; mostly dealing with parens and semicolons.
  1691.  *    This should all vanish.
  1692.  *
  1693.  *    It uses the same buffer as keyboard macros. The fix is easy (make
  1694.  *    a new function "execmacro" that takes a pointer to char and
  1695.  *    does what ctlxe does on it. Make ctlxe and excline both call it.)
  1696.  *    but would slow down the non-micro version.
  1697.  *
  1698.  * We define eval-expression because it's easy. It's pretty useless,
  1699.  * since it duplicates the functionality of execute-extended-command.
  1700.  * All of this is just to support startup files, and should be turned
  1701.  * off for micros.
  1702.  */
  1703.  
  1704. /*
  1705.  * evalexpr - get one line from the user, and run it. Identical in function
  1706.  *    to extend, but easy.
  1707.  */
  1708. /*ARGSUSED*/
  1709. evalexpr(f, n, k)
  1710. {
  1711.     register int    s;
  1712.     char        exbuf[NKBDM];
  1713.  
  1714.     if ((s = ereply("Eval: ", exbuf, NKBDM)) != TRUE)
  1715.         return s;
  1716.     return excline(exbuf);
  1717. }
  1718. /*
  1719.  * evalbuffer - evaluate the current buffer as line commands. Useful
  1720.  *    for testing startup files.
  1721.  */
  1722. /*ARGSUSED*/
  1723. evalbuffer(f, n, k)
  1724. {
  1725.     register LINE    *lp;
  1726.     register BUFFER    *bp = curbp;
  1727.     register int    s;
  1728.     static char    excbuf[NKBDM];
  1729.     char        *strncpy();
  1730.  
  1731.     for (lp = lforw(bp->b_linep); lp != bp->b_linep; lp = lforw(lp))
  1732.     {
  1733.         if (llength(lp) >= NKBDM + 1) return FALSE ;
  1734.         (VOID) strncpy(excbuf, ltext(lp), NKBDM);
  1735.         if ((s = excline(excbuf)) != TRUE) return s;
  1736.     }
  1737.     return TRUE;
  1738. }
  1739. /*
  1740.  * evalfile - go get a file and evaluate it as line commands. You can
  1741.  *    go get your own startup file if need be.
  1742.  */
  1743. /*ARGSUSED*/
  1744. evalfile(f, n, k)
  1745. {
  1746.     register int    s;
  1747.     char        fname[NFILEN];
  1748.  
  1749.     if ((s = ereply("Load file: ", fname, NFILEN)) != TRUE)
  1750.         return s;
  1751.     return load(fname);
  1752. }
  1753.  
  1754. /*
  1755.  * load - go load the file name we got passed.
  1756.  */
  1757. load(fname) char *fname;
  1758. {
  1759.     register int    s;
  1760.     char        excbuf[NKBDM];
  1761.  
  1762.     if (((s = ffropen(fname)) == FIOERR) || (s == FIOFNF))
  1763.         return FALSE;
  1764.     while ((s = ffgetline(excbuf, NKBDM)) == FIOSUC)
  1765.         if (excline(excbuf) != TRUE) break;
  1766.     (VOID) ffclose();
  1767.     return s == FIOEOF;
  1768. }
  1769.  
  1770. /*
  1771.  * excline - run a line from a load file or eval-expression.
  1772.  */
  1773. excline(line) register char *line;
  1774. {
  1775.     register char    *funcp, *argp = NULL;
  1776.     char        *skipwhite(), *parsetoken(), *backquote();
  1777.     int        status;
  1778.  
  1779.     /* Don't know if it works; don't care - mwm */
  1780.     if (kbdmip != NULL || kbdmop != NULL)
  1781.     {
  1782.         ewprintf("Not now!") ;
  1783.         return FALSE;
  1784.     }
  1785.  
  1786.     funcp = skipwhite(line);
  1787.     if (*funcp == '\0') return TRUE;    /* No error on blank lines */
  1788.     line = parsetoken(funcp);
  1789.     if (*line != '\0')
  1790.     {
  1791.         *line++ = '\0';
  1792.         line = skipwhite(line);
  1793.         if ((*line >= '0' && *line <= '9') || *line == '-')
  1794.         {
  1795.             argp = line;
  1796.             line = parsetoken(line);
  1797.         }
  1798.     }
  1799.  
  1800.     kbdmip = &kbdm[0];
  1801.     if (argp != NULL)
  1802.     {
  1803.         *kbdmip++ = (KEY) (KCTRL|'U');
  1804.         *kbdmip++ = (KEY) atoi(argp);
  1805.     }
  1806.     *kbdmip++ = (KEY) (KMETA|'X');
  1807.     /* Pack in function */
  1808.     while (*funcp != '\0')
  1809.         if (kbdmip+1 <= &kbdm[NKBDM-3])
  1810.             *kbdmip++ = (KEY) *funcp++;
  1811.         else
  1812.         {
  1813.             ewprintf("eval-expression macro overflow");
  1814.             ttflush();
  1815.             return FALSE;
  1816.         }
  1817.     *kbdmip++ = '\0';    /* done with function */
  1818.     /* Pack away all the args now...    */
  1819.     while (*line != '\0')
  1820.     {
  1821.         argp = skipwhite(line);
  1822.         if (*argp == '\0') break ;
  1823.         line = parsetoken(argp) ;
  1824.         /* Slightly bogus for strings. But they should be SHORT! */
  1825.         if (kbdmip+(line-argp)+1 > &kbdm[NKBDM-3])
  1826.         {
  1827.             ewprintf("eval-expression macro overflow");
  1828.             ttflush();
  1829.             return FALSE;
  1830.         }
  1831.         if (*line != '\0') *line++ = '\0';
  1832.         if (*argp != '"')
  1833.         {
  1834.             if (*argp == '\'') ++argp;
  1835.             while (*argp != '\0')
  1836.                 *kbdmip++ = (KEY) *argp++;
  1837.             *kbdmip++ = '\0';
  1838.         }
  1839.         else
  1840.         {    /* Quoted strings special again */
  1841.             ++argp;
  1842.             while (*argp != '"' && *argp != '\0')
  1843.                 if (*argp != '\\') *kbdmip++ = (KEY) *argp++;
  1844.                 else argp = backquote(++argp, TRUE);
  1845.             /* Quotes strings are gotkey'ed, so no trailing null */
  1846.         }
  1847.     }
  1848.     *kbdmip++ = (KEY) (KCTLX|')');
  1849.     *kbdmip++ = '\0';
  1850.     kbdmip = NULL;
  1851.     status = ctlxe(FALSE, 1, KRANDOM);
  1852.     kbdm[0] = (KCTLX|')');
  1853.     return status;
  1854. }
  1855. /*
  1856.  * a pair of utility functions for the above
  1857.  */
  1858. char *
  1859. skipwhite(s) register char *s;
  1860. {
  1861.  
  1862.     while ((*s == ' ' || *s == '\t' || *s == ')' || *s == '(')
  1863.         && *s != '\0')
  1864.         if (*s == ';') *s = '\0' ;
  1865.         else s++;
  1866.     return s;
  1867. }
  1868.  
  1869. char *
  1870. parsetoken(s) register char *s;
  1871. {
  1872.  
  1873.     if (*s != '"')
  1874.         while (*s != ' ' && *s != '\t' && *s != '(' && *s != ')'
  1875.                 && *s != '\0')
  1876.         {
  1877.             if (*s == ';')
  1878.                 *s = '\0';
  1879.             else
  1880.                 s++;
  1881.         }
  1882.     else    /* Strings get special treatment */
  1883.         do {
  1884.             /* Beware: You can \ out the end of the string! */
  1885.             if (*s == '\\')
  1886.                 ++s;
  1887.             if (ISLOWER(*s))
  1888.                 *s = TOUPPER(*s);
  1889.             } while (*++s != '"' && *s != '\0');
  1890.     return s;
  1891. }
  1892. /*
  1893.  * Put a backquoted string element into the keyboard macro. Return pointer
  1894.  * to char following backquoted stuff.
  1895.  */
  1896. /* Don't want to get the objects in isdigit.c just for this */
  1897. #define    isdigit(c)    (((c) >= '0') && ((c) <= '9'))
  1898.  
  1899. char *
  1900. backquote(in, flag) char *in;
  1901. {
  1902.     register KEY    keycode;
  1903.  
  1904.     switch (*in++)
  1905.     {
  1906.         case 'T': *kbdmip++ = (KEY) (KCTRL|'I');
  1907.               break;
  1908.         case 'N': *kbdmip++ = (KEY) (KCTRL|'J');
  1909.               break; 
  1910.         case 'R': *kbdmip++ = (KEY) (KCTRL|'M');
  1911.               break;
  1912.         case '^': *kbdmip = (KEY) (KCTRL|*in++);
  1913.         if (flag != FALSE && *kbdmip == (KEY) (KCTRL|'X'))
  1914.         {
  1915.             if (*in == '\\')
  1916.                 in = backquote(++in, FALSE);
  1917.             else
  1918.                 *kbdmip++ = (KEY) *in++;
  1919.             kbdmip[-1] |= (KEY) KCTLX;
  1920.         }
  1921.         else ++kbdmip;
  1922.               break;
  1923.         case 'E':
  1924.         if (flag != TRUE)
  1925.             *kbdmip++ = (KEY) (KCTRL|'[');
  1926.         else if (*in != '\\')
  1927.             *kbdmip++ = (KEY) (KMETA|*in++);
  1928.         else
  1929.         {
  1930.             in = backquote(++in, FALSE);
  1931.             kbdmip[-1] |= (KEY) KMETA;
  1932.         }
  1933.         break;
  1934.  
  1935.         /* (L. Frenkel) Convert "\Fd" and "\Fdd" to a function
  1936.          * key code between KFIRST and KLAST. "dd" should be
  1937.          * decimal; codes > KLAST are mapped to KLAST, for want
  1938.          * of a better idea of what to do with them.
  1939.          */
  1940.         case 'F':
  1941.         keycode = 0;
  1942.         if (isdigit(*in))
  1943.             keycode += *in++ - '0';
  1944.         if (isdigit(*in))
  1945.             keycode = (10 * keycode) + *in++ - '0';
  1946.         if ( (keycode += KFIRST) > KLAST)
  1947.             keycode = KLAST;
  1948.         *kbdmip++ = (KEY) keycode;
  1949.         break;
  1950.     }
  1951.     return in;
  1952. }
  1953. #endif    STARTUP
  1954. \Rogue\Monster\
  1955. else
  1956.   echo "will not over write ./extend.c"
  1957. fi
  1958. if `test ! -s ./file.c`
  1959. then
  1960. echo "writing ./file.c"
  1961. cat > ./file.c << '\Rogue\Monster\'
  1962. /*
  1963.  *         File commands.
  1964.  */
  1965. #include    "def.h"
  1966.  
  1967. BUFFER    *findbuffer();
  1968. VOID    makename();
  1969. VOID    upmodes();
  1970.  
  1971. /*
  1972.  * insert a file into the current buffer. Real easy - just call the
  1973.  * insertfile routine with the file name.
  1974.  */
  1975. /*ARGSUSED*/
  1976. fileinsert(f, n, k)
  1977. {
  1978.     register int    s;
  1979.     char        fname[NFILEN];
  1980.  
  1981.     if ((s=ereply("Insert file: ", fname, NFILEN)) != TRUE)
  1982.         return (s);
  1983.     adjustcase(fname);
  1984.     return (insertfile(fname, (char *) NULL)); /* don't set buffer name */
  1985. }
  1986.  
  1987. /*
  1988.  * Select a file for editing.
  1989.  * Look around to see if you can find the
  1990.  * fine in another buffer; if you can find it
  1991.  * just switch to the buffer. If you cannot find
  1992.  * the file, create a new buffer, read in the
  1993.  * text, and switch to the new buffer.
  1994.  */
  1995. /*ARGSUSED*/
  1996. filevisit(f, n, k)
  1997. {
  1998.     register BUFFER    *bp;
  1999.     int        s;
  2000.     char        fname[NFILEN];
  2001.  
  2002.     if ((s=ereply("Find file: ", fname, NFILEN)) != TRUE)
  2003.         return (s);
  2004.     if ((bp = findbuffer(fname, &s)) == NULL) return s;
  2005.     curbp = bp;
  2006.     if (showbuffer(bp, curwp, WFHARD) != TRUE) return FALSE;
  2007.     if (bp->b_fname[0] == 0)
  2008.         return (readin(fname));        /* Read it in.        */
  2009.     return TRUE;
  2010. }
  2011.  
  2012.  
  2013. /*
  2014.  * given a file name, either find the buffer it uses, or create a new
  2015.  * empty buffer to put it in.
  2016.  */
  2017. BUFFER *
  2018. findbuffer(fname, s) char *fname; int *s;
  2019. {
  2020.     register BUFFER    *bp;
  2021.     char        bname[NBUFN];
  2022.  
  2023.     adjustcase(fname);
  2024.     for (bp=bheadp; bp!=NULL; bp=bp->b_bufp)
  2025.     {
  2026.         if (strcmp(bp->b_fname, fname) == 0)
  2027.         {
  2028.             return bp;
  2029.         }
  2030.     }
  2031.     makename(bname, fname);            /* New buffer name.    */
  2032.     while ((bp=bfind(bname, FALSE)) != NULL)
  2033.     {
  2034.         *s = ereply("Buffer name: ", bname, NBUFN);
  2035.         if (*s == ABORT)        /* ^G to just quit    */
  2036.             return NULL;
  2037.         if (*s == FALSE)
  2038.         {        /* CR to clobber it    */
  2039.             bp->b_fname[0] = '\0';
  2040.             break;
  2041.         }
  2042.     }
  2043.     if (bp == NULL) bp = bfind(bname, TRUE);
  2044.     *s = FALSE;
  2045.     return bp;
  2046. }
  2047.  
  2048. /*
  2049.  * Read the file "fname" into the current buffer.
  2050.  * Make all of the text in the buffer go away, after checking
  2051.  * for unsaved changes. This is called by the "read" command, the
  2052.  * "visit" command, and the mainline (for "uemacs file").
  2053.  */
  2054. readin(fname) char *fname;
  2055. {
  2056.     register int        status;
  2057.     register WINDOW        *wp;
  2058.  
  2059.     if (bclear(curbp) != TRUE)        /* Might be old.    */
  2060.         return TRUE;
  2061.     status = insertfile(fname, fname) ;
  2062.     curbp->b_flag &= ~BFCHG;        /* No change.        */
  2063.     for (wp=wheadp; wp!=NULL; wp=wp->w_wndp)
  2064.     {
  2065.         if (wp->w_bufp == curbp)
  2066.         {
  2067.             wp->w_linep = lforw(curbp->b_linep);
  2068.             wp->w_dotp  = lforw(curbp->b_linep);
  2069.             wp->w_doto  = 0;
  2070.             wp->w_markp = NULL;
  2071.             wp->w_marko = 0;
  2072.         }
  2073.     }
  2074.     return status;
  2075. }
  2076. /*
  2077.  * insert a file in the current buffer, after dot. Set mark
  2078.  * at the end of the text inserted, point at the beginning.
  2079.  * Return a standard status. Print a summary (lines read,
  2080.  * error message) out as well. If the
  2081.  * BACKUP conditional is set, then this routine also does the read
  2082.  * end of backup processing. The BFBAK flag, if set in a buffer,
  2083.  * says that a backup should be taken. It is set when a file is
  2084.  * read in, but not on a new file (you don't need to make a backup
  2085.  * copy of nothing).
  2086.  *
  2087.  * Warning: Adds a trainling nl to files that don't end in one!
  2088.  * Need to fix, but later (I suspect that it will require a change
  2089.  * in the fileio files for all systems involved).
  2090.  */
  2091. insertfile(fname, newname) char fname[], newname[];
  2092. {
  2093.     register LINE    *lp1;
  2094.     register LINE    *lp2;
  2095.     LINE        *olp;            /* Line we started at */
  2096.     int        opos;            /* and offset into it */
  2097.     register WINDOW    *wp;
  2098.     register int    i;
  2099.     register int    nbytes;
  2100.     int        s, nline;
  2101.     BUFFER        *bp;
  2102.     char        line[NLINE];
  2103.  
  2104.     bp = curbp;                /* Cheap.        */
  2105.     if (newname != (char *) NULL)
  2106.         (VOID) strcpy(bp->b_fname, newname);
  2107.     if ((s=ffropen(fname)) == FIOERR)     /* Hard file open.    */
  2108.         goto out;
  2109.     if (s == FIOFNF)
  2110.     {            /* File not found.    */
  2111.         if (kbdmop == NULL)
  2112.             if (newname != NULL)
  2113.                 ewprintf("(New file)");
  2114.             else
  2115.                 ewprintf("(File not found)");
  2116.         goto out;
  2117.     }
  2118.     opos = curwp->w_doto;
  2119.     /* Open a new line, at point, and start inserting after it */
  2120.     (VOID) lnewline();
  2121.     olp = lback(curwp->w_dotp);
  2122.     nline = 0;            /* Don't count fake line at end */
  2123.     while ((s=ffgetline(line, NLINE)) == FIOSUC)
  2124.     {
  2125.         nbytes = strlen(line);
  2126.         if ((lp1=lalloc((RSIZE) nbytes)) == NULL)
  2127.         {
  2128.             s = FIOERR;        /* Keep message on the    */
  2129.             break;            /* display.        */
  2130.         }
  2131.         lp2 = lback(curwp->w_dotp);
  2132.         lp2->l_fp = lp1;
  2133.         lp1->l_fp = curwp->w_dotp;
  2134.         lp1->l_bp = lp2;
  2135.         curwp->w_dotp->l_bp = lp1;
  2136.         for (i=0; i<nbytes; ++i)
  2137.             lputc(lp1, i, line[i]);
  2138.         ++nline;
  2139.     }
  2140.     (VOID) ffclose();            /* Ignore errors.    */
  2141.     if (s==FIOEOF && kbdmop==NULL)
  2142.     {    /* Don't zap an error.    */
  2143.         if (nline == 1)
  2144.             ewprintf("(Read 1 line)");
  2145.         else
  2146.             ewprintf("(Read %d lines)", nline);
  2147.     }
  2148.     /* Set mark at the end of the text */
  2149.     curwp->w_markp = curwp->w_dotp;
  2150.     curwp->w_marko = curwp->w_doto;
  2151.     /* Now, delete the results of the lnewline we started with */
  2152.     curwp->w_dotp = olp;
  2153.     curwp->w_doto = opos;
  2154.     (VOID) ldelnewline();
  2155.     curwp->w_doto = opos;            /* and dot is right    */
  2156. #ifdef    BACKUP
  2157.     if (newname != NULL)
  2158.         bp->b_flag |= BFCHG | BFBAK;    /* Need a backup.    */
  2159.     else    bp->b_flag |= BFCHG;
  2160. #else
  2161.     bp->b_flag |= BFCHG;
  2162. #endif
  2163.     /* if the insert was at the end of buffer, set lp1 to the end of
  2164.      * buffer line, and lp2 to the beginning of the newly inserted
  2165.      * text.  (Otherwise lp2 is set to NULL.)  This is 
  2166.      * used below to set pointers in other windows correctly if they
  2167.      * are also at the end of buffer.
  2168.      */
  2169.     lp1 = bp->b_linep;
  2170.     if (curwp->w_markp == lp1)
  2171.         lp2 = curwp->w_dotp;
  2172.     else
  2173.     {
  2174. out:        lp2 = NULL;
  2175.     }
  2176.     for (wp=wheadp; wp!=NULL; wp=wp->w_wndp)
  2177.     {
  2178.         if (wp->w_bufp == curbp)
  2179.         {
  2180.             wp->w_flag |= WFMODE|WFEDIT;
  2181.             if (wp != curwp && lp2 != NULL)
  2182.             {
  2183.                 if (wp->w_dotp == lp1)
  2184.                     wp->w_dotp = lp2;
  2185.                 if (wp->w_markp == lp1)
  2186.                     wp->w_markp = lp2;
  2187.                 if (wp->w_linep == lp1)
  2188.                     wp->w_linep = lp2;
  2189.             }
  2190.         }
  2191.     }
  2192.     if (s == FIOERR)            /* False if error.    */
  2193.         return (FALSE);
  2194.     return (TRUE);
  2195. }
  2196.  
  2197. /*
  2198.  * Take a file name, and from it
  2199.  * fabricate a buffer name. This routine knows
  2200.  * about the syntax of file names on the target system.
  2201.  * BDC1        left scan delimiter.
  2202.  * BDC2        optional second left scan delimiter.
  2203.  * BDC3        optional right scan delimiter.
  2204.  */
  2205. VOID
  2206. makename(bname, fname) char bname[]; char fname[];
  2207. {
  2208.     register char    *cp1;
  2209.     register char    *cp2;
  2210.  
  2211.     cp1 = &fname[0];
  2212.     while (*cp1 != 0)
  2213.         ++cp1;
  2214. #ifdef    BDC2
  2215.     while (cp1!=&fname[0] && cp1[-1]!=BDC1 && cp1[-1]!=BDC2)
  2216.         --cp1;
  2217. #else
  2218.     while (cp1!=&fname[0] && cp1[-1]!=BDC1)
  2219.         --cp1;
  2220. #endif
  2221.     cp2 = &bname[0];
  2222. #ifdef    BDC3
  2223.     while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=BDC3)
  2224.         *cp2++ = *cp1++;
  2225. #else
  2226.     while (cp2!=&bname[NBUFN-1] && *cp1!=0)
  2227.         *cp2++ = *cp1++;
  2228. #endif
  2229.     *cp2 = 0;
  2230. }
  2231.  
  2232. /*
  2233.  * Ask for a file name, and write the
  2234.  * contents of the current buffer to that file.
  2235.  * Update the remembered file name and clear the
  2236.  * buffer changed flag. This handling of file names
  2237.  * is different from the earlier versions, and
  2238.  * is more compatable with Gosling EMACS than
  2239.  * with ITS EMACS.
  2240.  */
  2241. /*ARGSUSED*/
  2242. filewrite(f, n, k)
  2243. {
  2244.     register int    s;
  2245.     char        fname[NFILEN];
  2246.  
  2247.     if ((s=ereply("Write file: ", fname, NFILEN)) != TRUE)
  2248.         return (s);
  2249.     adjustcase(fname);
  2250.     if ((s=writeout(curbp, fname)) == TRUE)
  2251.     {
  2252. #ifdef    BACKUP
  2253.         curbp->b_flag &= ~(BFBAK | BFCHG);
  2254. #else
  2255.         curbp->b_flag &= ~BFCHG;
  2256. #endif
  2257.         upmodes(curbp);
  2258.     }
  2259.     return (s);
  2260. }
  2261.  
  2262. /*
  2263.  * Save the contents of the current buffer back into
  2264.  * its associated file. Do nothing if there have been no changes
  2265.  * (is this a bug, or a feature). Error if there is no remembered
  2266.  * file name. If this is the first write since the read or visit,
  2267.  * then a backup copy of the file is made.
  2268.  * Allow user to select whether or not to make backup files
  2269.  * by looking at the value of makebackup.
  2270.  */
  2271. #ifdef    BACKUP
  2272. static    int    makebackup = 0;
  2273. #endif
  2274.  
  2275. /*ARGSUSED*/
  2276. filesave(f, n, k)
  2277. {
  2278.     register int    s;
  2279.  
  2280.     if ((curbp->b_flag&BFCHG) == 0)
  2281.     {    /* Return, no changes.    */
  2282.         if (kbdmop == NULL) ewprintf("(No changes need to be saved)");
  2283.         return (TRUE);
  2284.     }
  2285.     if (curbp->b_fname[0] == 0)
  2286.     {        /* Must have a name.    */
  2287.         ewprintf("No file name");
  2288.         return (FALSE);
  2289.     }
  2290. #ifdef    BACKUP
  2291.     if (makebackup && ((curbp->b_flag&BFBAK) != 0))
  2292.     {
  2293.         s = fbackupfile(curbp->b_fname);
  2294.         if (s == ABORT)            /* Hard error.        */
  2295.             return FALSE;
  2296.         if (s == FALSE            /* Softer error.    */
  2297.         && (s=eyesno("Backup error, save anyway")) != TRUE)
  2298.             return (s);
  2299.     }
  2300. #endif
  2301.     if ((s=writeout(curbp, curbp->b_fname)) == TRUE)
  2302.     {
  2303. #ifdef    BACKUP
  2304.         curbp->b_flag &= ~(BFCHG | BFBAK);
  2305. #else
  2306.         curbp->b_flag &= ~BFCHG;
  2307. #endif
  2308.         upmodes(curbp);
  2309.     }
  2310.     return (s);
  2311. }
  2312.  
  2313. #ifdef    BACKUP
  2314. /* Since we don't have variables (we probably should)
  2315.  * this is a command processor for changing the value of
  2316.  * the make backup flag.  If no argument is given,
  2317.  * sets makebackup to true, so backups are made.  If
  2318.  * an argument is given, no backup files are made when
  2319.  * saving a new version of a file. Only used when BACKUP
  2320.  * is #defined.
  2321.  */
  2322. /*ARGSUSED*/
  2323. makebkfile(f, n, k)
  2324. {
  2325.     makebackup = !f;    /* make backup if no argument given */
  2326.     ewprintf(makebackup ?    "Backup files enabled" :
  2327.                 "Disabling backup files");
  2328.     return (TRUE);
  2329. }
  2330. #endif
  2331.  
  2332. /*
  2333.  * This function performs the details of file
  2334.  * writing; writing the file in buffer bp to
  2335.  * file fn. Uses the file management routines
  2336.  * in the "fileio.c" package. Most of the grief
  2337.  * is checking of some sort.
  2338.  */
  2339. writeout(bp, fn) register BUFFER *bp; char *fn;
  2340. {
  2341.     register int    s;
  2342.     register LINE    *lp;
  2343.  
  2344.     if ((s=ffwopen(fn)) != FIOSUC)        /* Open writes message.    */
  2345.         return (FALSE);
  2346.     lp = lforw(bp->b_linep);        /* First line.        */
  2347.     while (lp != bp->b_linep)
  2348.     {
  2349.         if ((s=ffputline(&(ltext(lp))[0], llength(lp))) != FIOSUC)
  2350.             break;
  2351.         lp = lforw(lp);
  2352.     }
  2353.     if (s == FIOSUC)
  2354.     {            /* No write error.    */
  2355.         s = ffclose();
  2356.         if (s==FIOSUC && kbdmop==NULL)
  2357.             ewprintf("Text Saved", fn);
  2358.     } else                    /* Ignore close error    */
  2359.         (VOID) ffclose();        /* if a write error.    */
  2360.     if (s != FIOSUC)            /* Some sort of error.    */
  2361.         return (FALSE);
  2362.     return (TRUE);
  2363. }
  2364.  
  2365. /*
  2366.  * Tag all windows for bp (all windows if bp NULL) as needing their
  2367.  * mode line updated.
  2368.  */
  2369. VOID
  2370. upmodes(bp) register BUFFER *bp;
  2371. {
  2372.     register WINDOW    *wp;
  2373.  
  2374.     for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
  2375.         if (bp == NULL || curwp->w_bufp == bp) wp->w_flag |= WFMODE;
  2376. }
  2377. \Rogue\Monster\
  2378. else
  2379.   echo "will not over write ./file.c"
  2380. fi
  2381. echo "Finished archive 3 of 5"
  2382. exit
  2383.  
  2384.  
  2385. -- 
  2386. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  2387. Mark A. Hargrove                                             U.S. TeleCenters
  2388. Voice: 408-496-1800                                          Santa Clara, CA
  2389. uucp : {dual, hoptoad, hplabs, portal, ptsfa}!well!ustel
  2390.