home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / editor / tvx_edit.arc / TVX_1.C < prev    next >
C/C++ Source or Header  |  1986-03-17  |  28KB  |  1,036 lines

  1. /* ========================================================================
  2.  
  3.     TVX - A full screen editor in C
  4.  
  5. Originally developed by:
  6.  
  7.     Dr. Bruce E. Wampler
  8.     University of New Mexico
  9.     Department of Computer Science
  10.     Farris Engineering Center
  11.     Albuquerque, NM 87131
  12.  
  13.     UUCP: ...{ucbvax | ihnp4!lanl | seismo!gatech}!unmvax!wampler
  14.  
  15.  
  16.    This version of TVX Copyright (c) 1986 by Bruce E. Wampler
  17.  
  18.    Permission is hereby granted for free, unrestricted nonprofit
  19.    use of this software.  Please feel free to modify, distribute,
  20.    and share this software as long as you aren't making any money
  21.    from it.  If you want to use this code in a profit making environment,
  22.    please contact the author for permission.
  23.  
  24.  
  25.     Direct comments, bug reports, suggestions to
  26.     Bruce Wampler at above address.
  27.  
  28. Converted from Ratfor to C January 1981 (note: since the editor
  29.     was originally in Ratfor, there are certain remnants of the
  30.     original structure left over.  There are a lot of things that
  31.     could have been done better if written in C originally.
  32.     So it goes.
  33.  
  34. PLEASE! If you are making additional modifications, use the
  35.     indentation scheme used here (line up {,}'s!!!) instead
  36.     of the unmaintainable indentation used by K&R!.
  37.     Also, please mark your changes with initials and date!
  38.     If possible, put your changes in #ifdefs so they can be
  39.     incorporated into the master source easily if appropriate.
  40.  
  41. Description of files required: (names lower case on unix)
  42.  
  43.     TVX_1.C       - main part of code (part 1), mostly os/terminal independent
  44.     TVX_2.C       - main part of code (part 2), mostly os/terminal independent
  45.     TVX_EDIT.C - all emulator version dependent code here.
  46.     TVX_LEX.C  - defaults, some os dependent stuff in here.  Major
  47.              changes in defaults can be fixed by recompiling this file.
  48.     TVX_IO.C   - almost all I/O, including screen, confined to this file.
  49.     TVX_LIB.C  - misc library routines needed by TVX.
  50.     TVX_IBM.C  - IBM-PC specific code, specifically the screen driver
  51.       (TVX_IBM.ASM - hand optimized version of TVX_IBM.C)
  52.     TVX_UNIX.C - contains unix specific code, including termcap driver
  53.     TVX_CFG.C  - used to build CONFIG.TVX file for -c switch
  54.     TVX_PTCH.C - used to permanently patch tvx with config file
  55.  
  56.     TVX_DEFS.IC - #define's for version, os, terminal, defaults
  57.     TVX_GLBL.IC - global data structures
  58.     TVX_TERM.IC - definitions for various terminals and systems
  59.  
  60.     Most distributions will contain other useful files as well.
  61.  
  62. ============================================================================ */
  63.  
  64. #include "tvx_defs.ic"        /* note tv_defs.ic will #include stdio.h */
  65. #include "tvx_glbl.ic"
  66.  
  67.   char clower(),cupper();
  68.  
  69. /* =============================>>> MAIN <<<============================= */
  70.   main (argc,argv)
  71.   int argc;
  72.   char *argv[];
  73.   {
  74.  
  75.     checkos();        /* check operating system version */
  76.     force_tty = FALSE;    /* won't usually force tty mode */
  77.  
  78.     tvinit();
  79.     ttinit();        /* initialize tt: */
  80.     trmini();        /* init terminal if needed */
  81.     csrcmd();        /* make cursor command cursor */
  82.  
  83.     fopenx(argc,argv);    /* open the file, maybe change switches */
  84.  
  85.     tvidefs();        /* set defaults */
  86.     opnbak();        /* may or may not be null routine */
  87.  
  88.     edit();        /* edit the file */
  89.  
  90.     clobak();        /* may be null routine */
  91.  
  92.     file_exit();    /* clean up files */
  93.  
  94.     ttymode = FALSE;
  95.  
  96.     if (*dest_file)
  97.     remark(dest_file);    /* echo final file name */
  98.     else
  99.       {
  100.     prompt("R/O, no changes: ") ; remark(orig_file);
  101.       }
  102.  
  103.     reset();        /* reset anything necessary */
  104.     quit();
  105.   }
  106.  
  107. /* =============================>>> ASK <<<============================= */
  108.   ask(msg,rply,rcnt)
  109.   char *msg,*rply;
  110.   int rcnt;
  111.   {            /* get a reply, via tty if necessary */
  112.     int oldtty;
  113.  
  114.     oldtty = ttymode;
  115.     ttymode = FALSE;    /* force echo on */
  116.     prompt(msg);
  117.     reply(rply,rcnt);
  118.     ttymode = oldtty;    /* back how it was */
  119.   }
  120.  
  121. /* =============================>>> BEGLIN <<<============================= */
  122.   beglin()
  123.   {  /* beglin - move cursor to beginning of current line */
  124.  
  125.     SLOW int xf;
  126.  
  127.     curchr = *(lines+curlin) + 1;    /* point to current character */
  128.     xf = findx();    /* this line needed to make the next */
  129.             /* call eval order independent, if you wondered */
  130.     tvxy(xf,tvy);    /* and move cursor */
  131. #ifdef SCR_BUF
  132.     ttflush();
  133. #endif
  134.   }
  135.  
  136. /* =============================>>> BOTPAG <<<============================= */
  137.   botpag()
  138.   { /* botpag - move cursor to bottom of current page (buffer) */
  139.  
  140.     curlin = nxtlin-1;        /* the last real line of text */
  141.     curchr = *(lines+curlin) + 1; /* the first char of that line */
  142.     endlin();            /* goto end of the line */
  143.     newscr();            /* update the screen */
  144.   }
  145.  
  146. /* ============================>>> CHK_RPT_NR <<<============================ */
  147.   chk_rpt_nr(val)
  148.   int val;
  149.   {        /* see if val is in valid range */
  150.  
  151.     if (val <= 0 || val > REPEATBUFS)    /* out of range */
  152.       {
  153.     tverrb("Bad rpt buff # ");
  154.     return (FALSE);
  155.       }
  156.     else
  157.     return (TRUE);
  158.   }
  159.  
  160. /* =============================>>> CMDERR <<<============================= */
  161.   cmderr(chr)
  162.   char chr;
  163.   {    /* cmderr - invalid command entered */
  164.  
  165.     static char badcmd[] = "Bad command:   ";
  166.  
  167.     if (chr >= ' ')
  168.       {
  169.     badcmd[13] = chr;     /* stick in after : */
  170.     badcmd[14] = ' ';
  171.       }
  172.     else
  173.       {
  174.     badcmd[13] = '^';
  175.     badcmd[14] = chr + '@';
  176.       }
  177.     tverrb(badcmd);
  178.   }
  179.  
  180. /* =============================>>> COMBIN <<<============================= */
  181.   combin()
  182.   { /* combin - combine current line with next line
  183.         update screen -    cursor assumed to be on curlin */
  184.  
  185.     SLOW int to,from,xf;
  186.     SLOW BUFFINDEX newl,k1,k2;
  187.  
  188.     if (curlin+1 >= nxtlin)        /* can't combine */
  189.     return (FALSE);
  190.     if (nxtsav-nxtchr < ALMOSTOUT)    /* check if need g.c. */
  191.     if (! gbgcol())
  192.         return (FALSE);
  193.     newl = nxtchr;            /* where next char goes */
  194.     stcopy(buff,*(lines+curlin),buff,&nxtchr); /* copy over current line */
  195.     curchr = nxtchr;            /* update the curchr */
  196.     k1 = *(lines+curlin);          /* we will kill this line */
  197.     *(lines+curlin) = newl;        /* remember where it is */
  198.     stcopy(buff,*(lines+curlin+1)+1,buff,&nxtchr); /* append the next line */
  199.     ++nxtchr;                /* fix nxtchr */
  200.     to = curlin+1;
  201.     k2 = *(lines+to);            /* we will kill this line */
  202.     for (from=curlin+2; from < nxtlin ; )    /* copy line to end */
  203.       {
  204.     *(lines+to++) = *(lines+from++);
  205.       }
  206.     --nxtlin;        /* update line ptr */
  207.     kline(k1);        /* kill the old lines now */
  208.     kline(k2);
  209.     if (tvdlin <= dsplin)    /* not at end of buffer */
  210.       {
  211.     tvescr();        /* erase rest of screen */
  212.     tvxy(1,tvy);    /* fix it up */
  213.     tvtype(curlin,min(tvlins-tvdlin+1,nxtlin-curlin));
  214.       }
  215.     else            /* at end of buffer */
  216.     newscr();
  217.  
  218.     xf = findx();
  219.     tvxy(xf,tvy); /* home cursor */
  220. #ifdef SCR_BUF
  221.     ttflush();
  222. #endif
  223.     return (TRUE);
  224.   }
  225.  
  226. /* =============================>>> CTRLCH <<<============================= */
  227.   ctrlch(chr)
  228.   char chr;
  229.   { /* ctrlch - echoes a control character for search and lex */
  230.  
  231.     if (chr >= ' ')
  232.     tvcout(chr);    /* echo as is */
  233.     else if (chr == CR)        /* carriage return may be special */
  234.       {
  235.     tvcout(CR);
  236. #ifdef USELF
  237.     tvcout(LF);    /*$$$ some machines need LF */
  238.     if (dsp_mem)
  239.         tvelin();
  240. #endif
  241.       }
  242.     else if (chr == ESC)    /* escape as $ */
  243.     tvcout('$');
  244.     else            /* echo most chars as '^x' */
  245.       {
  246.     tvcout('^');
  247.     tvcout(chr+'@');
  248.       }
  249. #ifdef SCR_BUF
  250.     ttflush();
  251. #endif
  252.   }
  253.  
  254. /* =============================>>> DELNXT <<<============================= */
  255.   int delnxt(cnt)
  256.   int cnt;
  257.   {  /* delnxt - delete next n characters  */
  258.  
  259.     static char chdel;
  260.     SLOW int abscnt,newx;
  261.     SLOW BUFFINDEX to;
  262.     SLOW char ans[2];
  263.     FAST int i;
  264.  
  265.     abscnt = (cnt > 0) ? cnt : (-cnt);    /* remember absolute value of cnt */
  266.     if (abscnt > 100)        /* make sure about this! */
  267.       {                /* they probably meant kill lines! */
  268.     tvclr();
  269.     ask("Kill that many chars? (y/n) ",ans,1);
  270.     verify(1);
  271.     if (clower(ans[0]) != 'y')
  272.         return (TRUE);
  273.       }
  274.  
  275.     if (cnt > 0)        /* deleting forewards */
  276.       {
  277.     chdel = *(buff+curchr); /* remember the char we are deleting */
  278.     for (i=1; curlin < nxtlin && i <= cnt; ++i) /* don't pass end of buff */
  279.       {
  280.         if (*(buff+curchr)==ENDLINE)    /* combine when end of line */
  281.           {
  282.         if (! combin())
  283.           {
  284.             return (FALSE);
  285.           }
  286.           }
  287.         else        /* deleting one character */
  288.           {
  289.         to=curchr;    /* overwrite current line */
  290.         stcopy(buff,curchr+1,buff,&to); /* copy the rest of the line */
  291.         for (++to; *(buff+to) != BEGLINE && to < nxtchr; ++to)
  292.             *(buff+to) = GARBAGE; /* mark the garbage characters */
  293.           }
  294.       }
  295.       }
  296.     else if (cnt < 0)        /* deleting backwards */
  297.       {
  298.     abscnt=(-cnt);
  299.     chdel = *(buff+curchr-1); /* remember the char we are deleting */
  300.     for (i=cnt; curlin >= 1 && i<0; ++i)    /* don't go past start */
  301.       {
  302.         if (*(buff+curchr-1)==BEGLINE)    /* deleting line separator */
  303.           {
  304.         if (curlin > 1)     /* not past beginning */
  305.           {
  306.             dwnlin(-1);        /* go up one line */
  307.             endlin();        /* get end of the line */
  308.             if (!combin())    /* and combine */
  309.               {
  310.             return (FALSE);
  311.               }
  312.           }
  313.           }
  314.         else            /* killing a normal character */
  315.           {
  316.         to=curchr-1;        /* overwrite in place */
  317.         stcopy(buff,curchr,buff,&to); /* copy the rest of the line */
  318.         for (++to; *(buff+to) != BEGLINE && to < nxtchr; ++to)
  319.             *(buff+to)=GARBAGE; /* mark the garbage characters */
  320.         --curchr;
  321.           }
  322.       }
  323.       }
  324.     newx=findx();        /* where cursor will go */
  325.     tvxy(newx,tvy);        /* reposition cursor */
  326.     if (chdel >= ' ' && abscnt == 1 && cdelchr[0])
  327.     sendcs(cdelchr);
  328.     else
  329.       {
  330.     if (chdel < ' ' || abscnt != 1)
  331.         tvelin();        /* erase rest of the line */
  332.     else            /* need to check for tabs following */
  333.       {
  334.         for (i = curchr ; *(buff+i)!=ENDLINE ; ++i)
  335.         if (*(buff+i) < ' ')
  336.           {
  337.             tvelin();    /* need to erase the line */
  338.             break;
  339.           }
  340.       }
  341.     tvtyln(curchr);        /* retype the rest */
  342.     if (chdel >= ' ' && abscnt == 1 && last_col_out < tvcols)
  343.     tvcout(' ');        /* "erase" last char on line */
  344.     tvxy(newx,tvy);        /* restore the cursor */
  345.       }
  346. #ifdef SCR_BUF
  347.     ttflush();
  348. #endif
  349.     return (TRUE);
  350.   }
  351.  
  352. /* =============================>>> DWNLIN <<<============================= */
  353.   dwnlin(cnt)
  354.   int cnt;
  355.   { /* dwnlin - move dot down cnt lines */
  356.  
  357.     SLOW int oldlin,change;
  358.  
  359.     if (curlin==nxtlin-1 && cnt > 0)    /* down from last line? */
  360.       {
  361.     endlin();
  362.     return;
  363.       }
  364.     oldlin=curlin;        /* remember where we started from */
  365.     curlin=max(min(curlin+cnt,nxtlin-1),1);    /* move down lines */
  366.     curchr = *(lines+curlin)+1;    /* point to the current character */
  367.     change=curlin-oldlin;    /* calculate how many lines changed */
  368.     update(change);        /* update the screen */
  369. #ifdef SCR_BUF
  370.     ttflush();
  371. #endif
  372.   }
  373.  
  374. /* =============================>>> EDIT_RPT <<<============================= */
  375.   edit_rpt(val)
  376.   int val;
  377.   {            /* copy repeat buffer val into buffer for editing */
  378.  
  379.     SLOW char *cp;
  380.     SLOW int start_line, old_ef;
  381.     
  382.  
  383.     if (!chk_rpt_nr(val))
  384.     return FALSE;
  385.  
  386.     old_ef = echof;  echof = FALSE;
  387.  
  388.     --val;        /* change to relative */
  389.  
  390.     beglin();        /* start by moving to beginning of current line */
  391.     start_line = curlin;    /* where we started */
  392.  
  393.     
  394.     ins_chr((int)'#'); ins_chr((int)val+'1'); ins_chr((int)':');
  395.     /* start with number */
  396.     ins_chr((int)loop_beg);    /* insert start of repeat loop */
  397.  
  398.     for (cp = &rptbuf[val][0] ; *cp ; ++cp)
  399.     ins_chr((int)*cp);
  400.     ins_chr((int)loop_end);
  401.     ins_chr((int)27); ins_chr((int)27);    /* make a way for store_rpt to find end */
  402.  
  403.     ins_chr((int)CR);        /* terminate line */
  404.     curlin = start_line;
  405.     curchr = *(lines+curlin)+1;
  406.  
  407.     echof = old_ef;
  408.  
  409.     verify(1);
  410. #ifdef SCR_BUF
  411.     ttflush();
  412. #endif
  413.     return (TRUE);
  414.   }
  415.  
  416. /* =============================>>> ENDLIN <<<============================= */
  417.   endlin()
  418.   { /* endlin - move cursor to end of the line */
  419.  
  420.     FAST int cnt;
  421.     SLOW BUFFINDEX i;
  422.  
  423.     cnt=0;
  424.     for (i=curchr; *(buff+i)!=ENDLINE; ++i)    /* find end of line */
  425.     ++cnt;
  426.     right(cnt);     /* move to end of line */
  427. #ifdef SCR_BUF
  428.     ttflush();
  429. #endif
  430.   }
  431.  
  432. /* =============================>>> EXEC_RPT <<<============================= */
  433.   exec_rpt(knt)
  434.   int knt;
  435.   {            /* this is combination of k:r,n& */
  436.     static char chr;
  437.     static int val;
  438.  
  439.     if (! grptch(&chr))        /* get buffer # (k) to use */
  440.     return (FALSE);
  441.  
  442.     val = chr - '0';        /* convert to 0 to 9 */
  443.  
  444.     if (!chk_rpt_nr(val))
  445.     return FALSE;
  446.  
  447.     rptuse=val-1;    /* adjust for 0 index int */
  448.  
  449.     if (knt != 1)
  450.     echof = FALSE;    /* turn off echo */
  451.  
  452.     rptcnt[rptuse] = knt > 0 ? knt : (-knt);
  453.  
  454.     return (TRUE);
  455.   }
  456.  
  457. /* =============================>>> FINDDL <<<============================= */
  458.   finddl(ibeg,cnt)
  459.   int *ibeg,*cnt;
  460.   {  /* finddl - find the display line
  461.     known: current line, calculate where it would go on the screen */
  462.  
  463.     if (curlin <= dsplin)
  464.       {             /* it is in first part of the display */
  465.     *ibeg = 1;
  466.     *cnt = min(tvlins,nxtlin-1);
  467.     tvdlin = curlin;        /* update the display line */
  468.       }
  469.     else if (nxtlin-curlin <= tvlins-dsplin)    /* at bottom of display */
  470.       {
  471.     *ibeg = max(1,nxtlin-tvlins);
  472.     *cnt = min(tvlins,nxtlin-1);
  473.     tvdlin=min(curlin,tvlins-(nxtlin-curlin)+1);
  474.       }
  475.     else            /* normal case: in middle */
  476.       {
  477.     *ibeg=max(1,curlin-dsplin+1);
  478.     *cnt=min(tvlins,nxtlin-(*ibeg));
  479.     tvdlin=dsplin;
  480.       }
  481.  }
  482.  
  483. /* =============================>>> FINDX  <<<============================= */
  484.   int findx()
  485.   {  /* findx - find the x position of the current character
  486.         handles spacing for tabs, control characters etc */
  487.  
  488.     SLOW BUFFINDEX i;
  489.     SLOW int pos,lmold;
  490.  
  491.     pos = 0;
  492.     for (i = *(lines+curlin)+1; i<=curchr; ++i)
  493.     if (*(buff+i-1)<' ' && *(buff+i-1)>0)  /* cur pos depends on last chr */
  494.         if (*(buff+i-1)==TAB)        /* handle tabs */
  495.         for (++pos ; ((pos-1) % tabspc)!=0; ++pos)
  496.             ;
  497.         else        /* control characters (echoed as ^X) */
  498.         pos += 2;    /* 2 spaces for other control character */
  499.     else            /* normal character */
  500.         ++pos;
  501.  
  502.     lmold = leftmg;        /* old left margin */
  503.     for (;;)
  504.       {
  505.     if (pos < leftmg)    /* won't fit on screen */
  506.         leftmg -= 16;    /* shift left */
  507.     else if (pos >= tvcols+leftmg)
  508.         leftmg += 16;
  509.     else
  510.         break;
  511.       }
  512.  
  513.     if (leftmg != lmold)        /* this handles screen shift */
  514.     newscr();
  515.  
  516.     return (pos-leftmg+1);
  517.   }
  518.  
  519. /* =============================>>> FIXEND  <<<============================= */
  520.   fixend()
  521.   { /* fixend - fix the error message line */
  522.  
  523.     SLOW int lastl;
  524.  
  525.     lastl = curlin+(tvlins-tvdlin);    /* the last line on the display */
  526.     tvxy(1,tvhardlines);         /* get to last line */
  527.     tvelin();
  528.     if (lastl < nxtlin && tvlins == tvhardlines)  /* only if really there */
  529.     tvtype(lastl,1);        /* write it out */
  530.     if (curlin >= 1)
  531.     tvhdln();            /* restore cursor */
  532.     else
  533.     tvxy(1,1);
  534. #ifdef SCR_BUF
  535.     ttflush();
  536. #endif
  537.    }
  538.  
  539. /* =============================>>> FOLDCASE <<<============================= */
  540.   foldcase(cnt)
  541.   int cnt;
  542.   {
  543.     /* fold from upper to lower or lower to upper case if letter */
  544.     SLOW int ni;
  545.     SLOW char fchr;
  546.  
  547.     for (ni = 0 ; ni < cnt ; ++ni)
  548.       {
  549.     fchr = *(buff+curchr);    /* get current character */
  550.     if (fchr >= 'a' && fchr <= 'z')
  551.         fchr = cupper(fchr);
  552.     else if (fchr >= 'A' && fchr <= 'Z')
  553.         fchr = clower(fchr);
  554.     if (fchr == ENDLINE)
  555.         right(1);
  556.     else
  557.       {
  558.         delnxt(1);            /* delete cur character */
  559.         insert((int)fchr,FALSE); /* and put back */
  560.       }
  561.       }
  562.   }
  563.  
  564. /* =============================>>> GBGCOL <<<============================= */
  565.   int gbgcol()
  566.   { /* gbgcol - retrieve unused space in buff */
  567.  
  568.     FAST int i;
  569.     SLOW int lastln;
  570.     SLOW BUFFINDEX nxtbad, nxtgud, to, from, whfrom, offset, newlin;
  571.  
  572.     tverrb("Compacting buffer ");    /* let the user know, it might take a while */
  573.     offset = curchr - *(lines+curlin);    /* need to reset curchr later */
  574.  
  575.     for (nxtbad=1 ; *(buff+nxtbad) != GARBAGE && nxtbad < nxtchr; ++nxtbad)
  576.         ;        /* find first space to free */
  577.     nxtgud=nxtbad;
  578.     lastln = 1;     /* where to start search */
  579.     do
  580.       {
  581.     to=nxtbad;
  582.     for (from=nxtgud; *(buff+from) == GARBAGE && from<nxtchr; ++from)
  583.         ;            /* find the next non-garbage character */
  584.  
  585. /*  nxtbad pts to first junk character,
  586.     nxtgud pts to next possibly good character */
  587.  
  588.     if (from >= nxtchr)
  589.         break;        /* at the end of the buffer */
  590.     whfrom=from;        /* where it came from */
  591.     newlin = to;        /* remember start */
  592.     do
  593.       {
  594.         *(buff+to) = *(buff+from++);    /* copy good stuff up */
  595.       }
  596.     while (*(buff+to++) != ENDLINE);
  597.  
  598.     nxtbad = to ; nxtgud = from;
  599.  
  600. /*  now find the old line
  601.     following algorithm assumes next line is likely to
  602.     be near the previous line */
  603.  
  604.     for (i=lastln ; i<nxtlin ; ++i)    /* start where last looked */
  605.         if (*(lines+i)==whfrom)
  606.           {
  607.         *(lines+i)=newlin;    /* point to new position */
  608.         if (curlin==i)
  609.             curchr=newlin+offset;    /* fix curchr if need be */
  610.         break;
  611.           }
  612.  
  613.     if (i >= nxtlin)    /* not found in second half */
  614.       {
  615.         for (i=1 ; i < lastln ; ++i)
  616.         if (*(lines+i)==whfrom)
  617.           {
  618.             *(lines+i)=newlin;        /* point to new position */
  619.             if (curlin==i)
  620.             curchr=newlin+offset;    /* fix curchr if need be */
  621.             break;
  622.           }
  623.         if (i >= lastln)        /* make sure we really found it */
  624.           {
  625.         tverrb("Compactor lost. Quit NOW! ");
  626.         for (i=1 ; i < 32000 ; ++i)
  627.             ;
  628.         return (FALSE);
  629.           }
  630.       }
  631.     lastln = i;            /* start at next line down */
  632.       }
  633.     while (nxtgud < nxtchr);
  634.  
  635.     for (to=nxtbad ; to<=nxtchr ; )
  636.     *(buff+to++) = GARBAGE;
  637.  
  638.     nxtchr=nxtbad;            /* update the next free character */
  639.     tverr("Compactor done");
  640.     return (nxtsav-nxtchr >= 50);
  641.  }
  642.  
  643. /* =============================>>> GETSAV <<<============================= */
  644.   int getsav()
  645.   { /* ## getsav - get text from save buffer */
  646.  
  647.     FAST int to,from;
  648.     SLOW BUFFINDEX fromch;
  649.     SLOW int newlin;
  650.  
  651.     if (mxbuff-nxtsav+savlin >= nxtsav-nxtchr)    /* g.c. */
  652.     if (!gbgcol())
  653.       {
  654.         tverrb("No get room ");
  655.         return (FALSE);
  656.       }
  657.  
  658.     if (nxtsav==mxbuff)        /* nothing to save */
  659.       {
  660.     return (TRUE);
  661.       }
  662.  
  663.     if (mxbuff-nxtsav+savlin >= nxtsav-nxtchr || mxline-nxtlin <= savlin)
  664.       {             /* room to get save buffer? */
  665.     tverrb("No get room ");
  666.     return (FALSE);        /* no room to save */
  667.       }
  668.  
  669. /* check if in middle of line */
  670.     if (curchr > lines[curlin]+1)
  671.     ins_chr((int)CR);
  672.  
  673. /*   # move down line to make space for new */
  674.     from=nxtlin-1;
  675.     nxtlin=nxtlin+savlin;
  676.     to=nxtlin-1;
  677.     while (from >= curlin)    /* copy line ptrs down right amnt. */
  678.     *(lines+(to--)) = *(lines+(from--));
  679.  
  680.     newlin=curlin;        /* will insert new lines here */
  681.     curlin=to+1;
  682.     fromch = mxbuff;        /* where taking saved stuff from */
  683.     for ( ; newlin < curlin; ++newlin)
  684.       {
  685.     *(buff+nxtchr) = BEGLINE; /* insert begline character */
  686.     *(lines+newlin) = nxtchr++; /* update line ptrs to new line */
  687.     do            /* copy stuff from save buffer */
  688.       {
  689.         *(buff+nxtchr++) = *(buff+fromch);
  690.       }
  691.     while (*(buff+fromch--)!=ENDLINE);
  692.       }
  693.     oldlen=0;
  694.     savlen=savlin;
  695.     newscr();
  696.     return (TRUE);
  697.   }
  698.  
  699. /* =============================>>> GRPTCH <<<============================= */
  700.   int grptch(chr)
  701.   char *chr;
  702.   { /* grptch - gets a char from repeat buffer or gkbd */
  703.  
  704.     SLOW char tmpchr;
  705.  
  706.     if (rptcnt[rptuse]>0)    /* need to fetch from repeat buffer */
  707.       {
  708.     if ((*chr=rptbuf[rptuse][nxtrpt[rptuse]]) == 0)
  709.         return (FALSE);
  710.     ++nxtrpt[rptuse];
  711.       }
  712.     else
  713.       {
  714.     gkbd(&tmpchr);    /* read the character from the keyboard */
  715.     *chr=tmpchr;
  716.       }
  717.     return (TRUE);
  718.   }
  719.  
  720. /* =============================>>> ins_pat  <<<============================= */
  721.   ins_pat(lexcnt)
  722.   int lexcnt;
  723.   {
  724.     SLOW char *chrp;
  725.  
  726.     if (!*pat_buff)
  727.     return (FALSE);
  728.     for (chrp = pat_buff ; *chrp ; )    /* simply insert pattern buffer */
  729.       {
  730.     if (!ins_chr((int)*chrp++))    /* make sure it works */
  731.         return (FALSE);
  732.       }
  733.  
  734.     return (TRUE); 
  735.   }
  736.  
  737. /* =============================>>> save_pat  <<<============================= */
  738.   save_pat()
  739.   {  /* save the find pattern, based on oldlen */
  740.  
  741.     SLOW int i;
  742.     SLOW char *chrp;
  743.  
  744.     
  745.     if (oldlen <= 0)
  746.       {
  747.     pat_buff[0] = 0;
  748.     return;                /* nothing to save */
  749.       }
  750.  
  751.     for (i = 1 ; i <= oldlen ; ++i)    /* first, move left */
  752.       {
  753.     --curchr;
  754.     if (*(buff+curchr) == BEGLINE)
  755.       {
  756.         if (curlin > 1)
  757.           {
  758.         --curlin;
  759.         for (curchr = *(lines+curlin) ; *(buff+curchr)!=ENDLINE ;
  760.           ++curchr)
  761.             ;        /* bump curchr to end of the line */
  762.           }
  763.         else
  764.           {
  765.         ++curchr;
  766.         break;
  767.           }
  768.       }
  769.       }
  770.  
  771.      /* now save, go back right */
  772.  
  773.     chrp = pat_buff;            /* put in pattern buffer */
  774.  
  775.     for (i = 1 ; i <= oldlen ; ++i)
  776.       {
  777.     if (*(buff+curchr)==ENDLINE)
  778.       {
  779.         if (curlin+1 >= nxtlin)
  780.         break;        /* don't go beyond end! */
  781.         ++curlin;
  782.         curchr = *(lines+curlin)+1;
  783.         *chrp++ = CR;    /* make a cr */
  784.       }
  785.     else
  786.       {
  787.         if ((chrp - 100) < pat_buff)    /* make sure enough room */
  788.         *chrp++ = *(buff+curchr);
  789.         ++curchr;
  790.       }
  791.       }
  792.     *chrp = 0;                    /* terminate */
  793.   }
  794.  
  795. /* =============================>>> INSET <<<============================= */
  796.   inset(val,set)
  797.   int val,*set;
  798.   {
  799.      /* return true if val is in set set */
  800.  
  801.     while (*set)
  802.     if (val == *set++)
  803.         return TRUE;
  804.     return FALSE;
  805.   }
  806.  
  807. /* =============================>>> ins_chr <<<============================= */
  808.   ins_chr(ival)
  809.   int ival;
  810.   {
  811.     return insert(ival,FALSE);        /* force insert */
  812.   }
  813.  
  814. /* =============================>>> INSERT <<<============================= */
  815.   insert(ival,how)
  816.   int ival,how;
  817.   { /* insert - insert a character
  818.  
  819.     if how is TRUE, then read characters from keyboard until
  820.     get an escape, otherwise insert ival */
  821.  
  822.     SLOW BUFFINDEX from,to;
  823.     SLOW BUFFINDEX curbuf,curend;
  824.     SLOW int lenins, nocins, ityp, xf;
  825.     SLOW BUFFINDEX abvchr;
  826.  
  827.     SLOW char chr;
  828.  
  829.  
  830.     static int ins_msg = TRUE;    /* own variable */
  831.  
  832.     if (ins_msg && how)
  833.     csrins();        /* change cursor */
  834.  
  835.     if (how)        /* how = 1 regular insert mode */
  836.       {
  837.     if (! grptch(&chr))    /* get char using grptch */
  838.         goto l9999;
  839.     if (chr == ESC)        /* esc means done */
  840.       {
  841.         goto l1000;
  842.       }
  843.       }
  844.     else
  845.     chr = ival;        /* use the passed value */
  846.  
  847.     if (chr==ENDLINE || chr==BEGLINE || chr==GARBAGE || (chr==ENDFILE && usecz))
  848.     goto l9998;        /* don't allow this case! */
  849.  
  850.     if (curlin < 1)
  851.       {             /* buffer empty? */
  852.     curlin=1;        /* init for initial insert */
  853.     *(lines+1)=nxtchr;
  854.     curchr=nxtchr+1;
  855.     *(buff+nxtchr) = BEGLINE;
  856.     *(buff+nxtchr+1) = ENDLINE;
  857.     nxtchr += 2;
  858.     nxtlin = 2;
  859.       }
  860.  
  861.     lenins=0;            /* remember length of insert for rmvlst */
  862.  
  863.     do
  864.       {
  865.     if (nxtsav-nxtchr < ALMOSTOUT)
  866.         if (!gbgcol())
  867.         goto l9999;    /* collect garbage if necessary */
  868.     curbuf = *(lines+curlin);  /* pick up the pointer to current line */
  869.     for (curend=curbuf; *(buff+curend) != ENDLINE; ++curend)
  870.         ;            /* get line length */
  871.     if (curend+1 < nxtchr)    /* not using last part of buffer */
  872.       {
  873.         if (curend-curbuf >= nxtsav-nxtchr)
  874.         goto l9998;    /* no more room! */
  875.         curchr = nxtchr+(curchr-curbuf);    /* where curchr will be */
  876.         *(lines+curlin) = nxtchr;    /* new line goes here */
  877.         stcopy(buff,curbuf,buff,&nxtchr); /* copy the line to the end */
  878.         curend=nxtchr++;    /* reset end pointer */
  879.         kline(curbuf);    /* kill off the line */
  880.         curbuf = *(lines+curlin);    /* update beginning pointer */
  881.       }
  882.  
  883. /*   #    to here, ready to insert the new character at the end of the line */
  884.  
  885.     if (chr==' ' && wraplm > 1 && (tvx >= wraplm || leftmg > 1))    /* auto wrap? */
  886.           chr = CR;
  887. #ifdef FILELF
  888.     if (chr == LF && how)
  889.         ;            /* don't insert lfs in CR/LF systems, echo? */
  890.     else if (chr == CR)    /* inserting a new line */
  891. #else
  892.     if (chr == CR)        /* inserting a new line */
  893. #endif
  894.       {
  895.         if (nxtlin >= mxline)    /* any room? */
  896.           {
  897.         tverrb("No more free lines for insert ");
  898.         goto l9999;
  899.           }
  900.  
  901.         for (from=curend; from >= curchr; --from)
  902.         *(buff+from+2) = *(buff+from);        /* copy chars down */
  903.         nxtchr += 2;    /* bump nxtchr to free space */
  904.  
  905.         *(buff+curchr) = ENDLINE;    /* mark as endline */
  906.         *(buff+curchr+1) = BEGLINE;    /* beginning of line */
  907.         ++lenins;
  908.  
  909.         to=nxtlin;        /* move lines down */
  910.         for (from = nxtlin-1; from > curlin; )
  911.           {         /* bump the lines down */
  912.         *(lines+to--) = *(lines+from--);
  913.           }
  914.         ++nxtlin;    /* bump to next free line */
  915.  
  916.         *(lines+curlin+1)=curchr+1;        /* remember where */
  917.  
  918.         if (ins_msg && how)
  919.         fixend();                /* fix last line */
  920.         tvelin();    /* erase stuff after cr */
  921.  
  922.         nocins = (leftmg > 1);    /* ciline no good if left marg > 1 */
  923.  
  924.         dwnlin(1);    /* go down one line */
  925.  
  926.         if (ciline[0] == 0 || nocins)
  927.           {
  928.         tvescr();        /* erase the rest of the screen */
  929.         ityp = min(tvlins-tvdlin+1,nxtlin-curlin);
  930.           }
  931.         else
  932.           {
  933.         tvinsl();     /* insert a line */
  934.         ityp = 1;
  935.           }
  936.  
  937.         tvtype(curlin,ityp);
  938.         tvhdln();
  939.         if (ins_msg && how)
  940.         csrins();            /* change cursor */
  941.  
  942.         if (autoin && curlin > 2)        /* automatic indentation! */
  943.           {
  944.         ins_msg = FALSE;        /* turn off insert message */
  945.         abvchr = *(lines+curlin-1)+1;    /* prevous line */
  946.         while (*(buff+abvchr)==' ' || *(buff+abvchr)==TAB)
  947.             if (!insert(*(buff+abvchr++),FALSE) )
  948.               {
  949.             ins_msg = TRUE;
  950.             goto l9999;
  951.               }
  952.             else if (ttymode)        /* hmm, now what? */
  953.               {
  954.             ttymode = FALSE;
  955.             ttwt(*(buff+abvchr-1));
  956. #ifdef SCR_BUF
  957.             ttflush();
  958. #endif
  959.             ttymode = TRUE;
  960.               }
  961.         ins_msg = TRUE;
  962.         fixend();
  963.         csrins();            /* change cursor */
  964.           }
  965.       }
  966.     else if (chr == delkey && how)
  967.       {
  968.         if (!delnxt(-1))    /* rubbing out last character */
  969.         goto l9999;
  970.         --lenins;
  971.       }
  972.     else            /* inserting on the current line */
  973.       {
  974.         to = nxtchr;        /* will move to nxtchr */
  975.         for (from = curend ; from >= curchr; )
  976.           {
  977.         *(buff+to--) = *(buff+from--);
  978.           }
  979.         curend = nxtchr++;    /* end is now at curchr, bump nxtchr */
  980.         *(buff+curchr) = chr; /* stick in the current character */
  981.         ++lenins;
  982.         if (tvlins < tvhardlines - 10 && how && chr >= ' ')
  983.           {
  984.         tvelin();
  985.         ctrlch(chr);
  986.         ctrlch('+');
  987.           }
  988.         else
  989.         tvtyln(curchr);    /* retype rest of the line */
  990.         ++curchr;        /* reset the curchr pointer */
  991.         xf = findx();
  992.         tvxy(xf,tvy);    /* reset the cursor */
  993. #ifdef SCR_BUF
  994.         ttflush();
  995. #endif
  996.       }
  997.  
  998. /* the character has been inserted and displayed, get another maybe */
  999.  
  1000.     if (how)
  1001.         if (!grptch(&chr))
  1002.         goto l9999;
  1003.       }
  1004.     while (how && chr != ESC);    /* end of do */
  1005.  
  1006.     if (tvlins < tvhardlines - 10 && how)    /* fix for slow baud */
  1007.       {
  1008.     tvelin();
  1009.     tvtyln(curchr);    /* retype rest of the line */
  1010.     xf = findx();
  1011.     tvxy(xf,tvy);    /* reset the cursor */
  1012.       }
  1013.  
  1014.     oldlen = lenins;
  1015.     savlen = (-1);        /* haven't saved lines */
  1016.     goto l1000;
  1017.  
  1018. l9998:
  1019.     tverrb("Can't insert that char ");
  1020. l9999:
  1021.     csrcmd();
  1022. #ifdef SCR_BUF
  1023.     ttflush();
  1024. #endif
  1025.     return FALSE;
  1026.  
  1027. l1000:
  1028.     if (ins_msg && how)
  1029.     fixend();
  1030.     csrcmd();
  1031. #ifdef SCR_BUF
  1032.     ttflush();
  1033. #endif
  1034.     return TRUE;
  1035.  }
  1036.