wampler@unmvax.UUCP (01/21/86)
#--------CUT---------CUT---------CUT---------CUT--------# ######################################################### # # # This is a shell archive file. To extract files: # # # # 1) Make a directory (like tvx) for the files. # # 2) Write a file, such as "filen.shar", containing # # this archive file into the directory. # # 3) Type "sh file.shar". Do not use csh. # # # ######################################################### # # echo Extracting tvx_1.c: sed 's/^X//' >tvx_1.c <<\SHAR_EOF X/* ------------------------ tvx_1.c ------------------------------------- */ X/* ======================================================================== X X TVX - A full screen editor in C X X Originally developed by: X X Dr. Bruce E. Wampler X University of New Mexico X Department of Computer Science X Farris Engineering Center X Albuquerque, NM 87131 X X uucp: ..{ucbvax | gatech | ihnp4!lanl}!unmvax!wampler X X Public Domain version released July 1, 1985 X Direct comments, bug reports, suggestions to X Bruce Wampler at above address. X X Converted from Ratfor to C January 1981 (note: since the editor X was originally in Ratfor, there are certain remnants of the X original structure left over. There are a lot of things that X could have been done better if written in C originally. X Note also that this editor was originally designed in X 1979 when TECO was state of the art. The influence of X TECO on this editor will be apparent to anyone who has X used TECO. X X So it goes. X X X PLEASE! If you are making additional modifications, use the X indentation scheme used here (line up {,}'s!!!) instead X of the unmaintainable indentation used by K&R!. X Also, please mark your changes with initials and date! X X Description of files required: (names lower case on unix) X X TVX_1.C - main part of code (part 1), mostly os/terminal independent X TVX_2.C - main part of code (part 2), mostly os/terminal independent X TVX_LEX.C - defaults, some os dependent stuff in here. Major X changes in defaults can be fixed by recompiling this file. X TVX_IO.C - almost all I/O, including screen, confined to this file. X TVX_LIB.C - misc library routines needed by TVX. X TVX_IBM.C - IBM-PC specific code, specifically the screen driver X (TVX_IBM.ASM - hand optimized version of TVX_IBM.C) X TVX_UNIX.C - contains unix specific code, including termcap driver X TVX_CFG.C - used to build CONFIG.TVX file for -c switch X TVX_PTCH.C - used to permanently patch tvx with config file X X TVX_DEFS.IC - #define's for version, os, terminal, defaults X TVX_GLBL.IC - global data structures X TVX_TERM.IC - definitions for various terminals and systems X X Most distributions will contain other useful files as well. X X============================================================================ */ X X#include "tvx_defs.ic" /* note tv_defs.ic will #include stdio.h */ X#include "tvx_glbl.ic" X X/* =============================>>> MAIN <<<============================= */ X main (argc,argv) X int argc; X char *argv[]; X { X X checkos(); /* check operating system version */ X force_tty = FALSE; /* won't usually force tty mode */ X X tvinit(); X ttinit(); /* initialize tt: */ X trmini(); /* init terminal if needed */ X csrcmd(); /* make cursor command cursor */ X X fopenx(argc,argv); /* open the file, maybe change switches */ X X tvidefs(); /* set defaults */ X opnbak(); /* may or may not be null routine */ X X edit(); /* edit the file */ X X clobak(); /* may be null routine */ X X file_exit(); /* clean up files */ X X ttymode = FALSE; X X if (*dest_file) X remark(dest_file); /* echo final file name */ X else X { X prompt("R/O, no changes: ") ; remark(orig_file); X } X X reset(); /* reset anything necessary */ X quit(); X } X X/* =============================>>> ASK <<<============================= */ X ask(msg,rply,rcnt) X char *msg,*rply; X int rcnt; X { /* get a reply, via tty if necessary */ X int oldtty; X X oldtty = ttymode; X ttymode = FALSE; /* force echo on */ X prompt(msg); X reply(rply,rcnt); X ttymode = oldtty; /* back how it was */ X } X X/* =============================>>> BEGLIN <<<============================= */ X beglin() X { /* beglin - move cursor to beginning of current line */ X X SLOW int xf; X X curchr = *(lines+curlin) + 1; /* point to current character */ X xf = findx(); /* this line needed to make the next */ X /* call eval order independent, if you wondered */ X tvxy(xf,tvy); /* and move cursor */ X } X X/* =============================>>> BOTPAG <<<============================= */ X botpag() X { /* botpag - move cursor to bottom of current page (buffer) */ X X curlin = nxtlin-1; /* the last real line of text */ X curchr = *(lines+curlin) + 1; /* the first char of that line */ X endlin(); /* goto end of the line */ X newscr(); /* update the screen */ X } X X/* ============================>>> CHK_RPT_NR <<<============================ */ X chk_rpt_nr(val) X int val; X { /* see if val is in valid range */ X X if (val < 0 || val > REPEATBUFS) /* out of range */ X { X tverrb("Bad rpt buff # "); X return (FALSE); X } X else X return (TRUE); X } X X/* =============================>>> CMDERR <<<============================= */ X cmderr(chr) X char chr; X { /* cmderr - invalid command entered */ X X static char badcmd[] = "Bad command: "; X X if (chr >= ' ') X { X badcmd[13] = chr; /* stick in after : */ X badcmd[14] = ' '; X } X else X { X badcmd[13] = '^'; X badcmd[14] = chr + '@'; X } X tverrb(badcmd); X } X X/* =============================>>> COMBIN <<<============================= */ X combin() X { /* combin - combine current line with next line X update screen - cursor assumed to be on curlin */ X X SLOW int to,from,xf; X SLOW BUFFINDEX newl,k1,k2; X X if (curlin+1 >= nxtlin) /* can't combine */ X return (FALSE); X if (nxtsav-nxtchr < ALMOSTOUT) /* check if need g.c. */ X if (! gbgcol()) X return (FALSE); X newl = nxtchr; /* where next char goes */ X stcopy(buff,*(lines+curlin),buff,&nxtchr); /* copy over current line */ X curchr = nxtchr; /* update the curchr */ X k1 = *(lines+curlin); /* we will kill this line */ X *(lines+curlin) = newl; /* remember where it is */ X stcopy(buff,*(lines+curlin+1)+1,buff,&nxtchr); /* append the next line */ X ++nxtchr; /* fix nxtchr */ X to = curlin+1; X k2 = *(lines+to); /* we will kill this line */ X for (from=curlin+2; from < nxtlin ; ) /* copy line to end */ X { X *(lines+to++) = *(lines+from++); X } X --nxtlin; /* update line ptr */ X kline(k1); /* kill the old lines now */ X kline(k2); X if (tvdlin <= dsplin) /* not at end of buffer */ X { X tvescr(); /* erase rest of screen */ X tvxy(1,tvy); /* fix it up */ X tvtype(curlin,min(tvlins-tvdlin+1,nxtlin-curlin)); X } X else /* at end of buffer */ X newscr(); X X xf = findx(); X tvxy(xf,tvy); /* home cursor */ X X return (TRUE); X } X X/* =============================>>> CTRLCH <<<============================= */ X ctrlch(chr) X char chr; X { /* ctrlch - echoes a control character for search and lex */ X X if (chr >= ' ') X tvcout(chr); /* echo as is */ X else if (chr == CR) /* carriage return may be special */ X { X tvcout(CR); X#ifdef USELF X tvcout(LF); /*$$$ some machines need LF */ X#endif X } X else if (chr == ESC) /* escape as $ */ X tvcout('$'); X else /* echo most chars as '^x' */ X { X tvcout('^'); X tvcout(chr+'@'); X } X } X X/* =============================>>> DELNXT <<<============================= */ X int delnxt(cnt) X int cnt; X { /* delnxt - delete next n characters */ X X char clower(); X static char chdel; X SLOW int abscnt,newx; X SLOW BUFFINDEX to; X SLOW char ans[2]; X FAST int i; X X abscnt = cnt; /* remember absolute value of cnt */ X if (cnt > 100 || cnt < -100) /* make sure about this! */ X { X tvclr(); X ask("Kill that many for sure? (y/n) ",ans,1); X verify(1); X if (clower(ans[0]) != 'y') X return (TRUE); X } X X if (cnt > 0) /* deleting forewards */ X { X chdel = *(buff+curchr); /* remember the char we are deleting */ X for (i=1; curlin < nxtlin && i <= cnt; ++i) /* don't pass end of buff */ X { X if (*(buff+curchr)==ENDLINE) /* combine when end of line */ X { X if (! combin()) X { X return (FALSE); X } X } X else /* deleting one character */ X { X to=curchr; /* overwrite current line */ X stcopy(buff,curchr+1,buff,&to); /* copy the rest of the line */ X for (++to; *(buff+to) != BEGLINE && to < nxtchr; ++to) X *(buff+to)=GARBAGE; /* mark the garbage characters */ X } X } X } X else if (cnt < 0) /* deleting backwards */ X { X abscnt=(-cnt); X chdel = *(buff+curchr-1); /* remember the char we are deleting */ X for (i=cnt; curlin >= 1 && i<0; ++i) /* don't go past start */ X { X if (*(buff+curchr-1)==BEGLINE) /* deleting line separator */ X { X if (curlin > 1) /* not past beginning */ X { X dwnlin(-1); /* go up one line */ X endlin(); /* get end of the line */ X if (!combin()) /* and combine */ X { X return (FALSE); X } X } X } X else /* killing a normal character */ X { X to=curchr-1; /* overwrite in place */ X stcopy(buff,curchr,buff,&to); /* copy the rest of the line */ X for (++to; *(buff+to)!=BEGLINE && to < nxtchr; ++to) X *(buff+to)=GARBAGE; /* mark the garbage characters */ X --curchr; X } X } X } X newx=findx(); /* where cursor will go */ X tvxy(newx,tvy); /* reposition cursor */ X if (chdel < ' ' || abscnt != 1) X tvelin(); /* erase rest of the line */ X else /* need to check for tabs following */ X { X for (i = curchr ; *(buff+i)!=ENDLINE ; ++i) X if (*(buff+i) < ' ') X { X tvelin(); /* need to erase the line */ X break; X } X } X tvtyln(curchr); /* retype the rest */ X if (chdel >= ' ' && abscnt == 1 && last_col_out < tvcols) X tvcout(' '); /* "erase" last char on line */ X tvxy(newx,tvy); /* restore the cursor */ X X return (TRUE); X } X X/* =============================>>> DWNCOL <<<============================= */ X dwncol(cnt) X int cnt; X { /* dwncol - move down in column */ X X SLOW int curcol,l,oldef,needns; X X needns = FALSE; X if (leftmg > 1) /* handle right virtual screen different */ X { X oldef=echof; X needns = TRUE; X echof = FALSE; X } X X if (oldlex==VDOWNCOL || oldlex==VUPCOL) /* several in a row? */ X curcol=oldcol; /* pick up old value */ X else X { X curcol = curchr - *(lines+curlin); /* calculate the current column */ X oldcol = curcol; X } X dwnlin(cnt); /* go down given lines */ X if (curlin>=1 && curlin<nxtlin && curcol>1) /* not at ends? */ X { X l = strlen(buff + ((*(lines+curlin)) + 1) ); X right(min(curcol-1,l)); X } X X if (needns) /* needed new screen */ X { X echof=oldef; X newscr(); X } X } X X/* =============================>>> DWNLIN <<<============================= */ X dwnlin(cnt) X int cnt; X { /* dwnlin - move dot down cnt lines */ X X SLOW int oldlin,change; X X if (curlin==nxtlin-1 && cnt > 0) /* down from last line? */ X { X endlin(); X return; X } X oldlin=curlin; /* remember where we started from */ X curlin=max(min(curlin+cnt,nxtlin-1),1); /* move down lines */ X curchr = *(lines+curlin)+1; /* point to the current character */ X change=curlin-oldlin; /* calculate how many lines changed */ X update(change); /* update the screen */ X X } X X/* =============================>>> EDIT <<<============================= */ X edit() X { /* edit - main editing routine */ X X SLOW int lexval,lexcnt,succ, lastln, itmp; X SLOW int noteloc[10], ni, lex_def; X X static int ins_set[] = X { X VINSERT, VOPENLINE, VQUIT, VABORT, VFBEGIN, VGET, VYANK, 0 X }; X X static int jump_set[] = /* commands to not reset jump memory */ X { X VJUMP, VMEMORY, VHELP, VNOTELOC, VPRINTS, 0 X }; X X static char lexchr; X X startm(); X remark("Reading file..."); X X rdpage(); /* read a page into the buffer */ X X tvclr(); /* clear the screen */ X X if (curlin >= 1) X tvtype(curlin,tvlins); /* type out lines */ X X tvxy(1,1); /* and rehome the cursor */ X waserr = FALSE; /* no errors to erase yet */ X X if (curlin<1) X tverr("Buffer empty"); X X lexval = UNKNOWN; /* so can remember 1st time through */ X useprint = FALSE; /* not to printer */ X succ=TRUE; /* assume success initially */ X X lastln = curlin; /* remember where we were */ X for (ni = 0 ; ni < 10 ; noteloc[ni++] = curlin) X ; /* init noteloc */ X do X { X oldlex = lexval; /* remember last command */ X if (! succ) X echof = TRUE; /* resume echo when error */ X lex_def = lex(&lexval,&lexcnt,&lexchr,succ); /* get command input */ X if (waserr) X fixend(); X waserr=FALSE; X succ=TRUE; X if (lexval == UNKNOWN) X { X cmderr(lexchr); X succ = FALSE; /* announce failure to lex */ X } X else X { X if (curlin < 1) /* make sure legal command for empty buffer */ X { X X if (!inset(lexval,ins_set)) X { X tverrb("Can't, buffer empty. Insert 1st "); X succ=FALSE; X continue; X } X } X if (!inset(lexval,jump_set)) X lastln=curlin; /* let user look at help w/o changing */ X X switch (lexval) X { Xcase 1: /* right */ X right(lexcnt); X break; Xcase 2: /* left */ X right(-lexcnt); X break; Xcase 3: /* down line */ X dwnlin(lexcnt); X break; Xcase 4: /* up line */ X dwnlin(-lexcnt); X break; Xcase 5: /* down in column */ X dwncol(lexcnt); X break; Xcase 6: /* up in column */ X dwncol(-lexcnt); X break; Xcase 7: /* delete last character */ X succ = delnxt(-lexcnt); X break; Xcase 8: /* delete next character */ X succ = delnxt(lexcnt); X break; Xcase 9: /* insert */ X succ = insert(lexcnt,lex_def); X break; Xcase 10: /* kill a line */ X killin(lexcnt); X break; Xcase 11: /* kill rest of line */ X krest(); X break; Xcase 12: /* kill previous part of line */ X kprev(); X break; Xcase 13: /* move to beginning of line */ X beglin(); X break; Xcase 14: /* move to end of the line */ X endlin(); X break; Xcase 15: /* search for a pattern */ X succ = search(lexcnt,TRUE); X break; Xcase 16: /* search for next part of a pattern */ X succ = snext(lexcnt,TRUE); X break; Xcase 17: /* flip screen */ X dwnlin(min(lexcnt*tvlins,nxtlin-curlin+1)); X break; Xcase 18: /* goto top of page */ X toppag(); X break; Xcase 19: /* goto to bottom of page */ X botpag(); X break; Xcase 20: /* goto real beginning of the file */ X succ = fbeg(); X break; Xcase 21: /* verify */ X verify(lexcnt); X break; Xcase 22: /* open new line */ X openln(lexcnt); X succ = insert(1,TRUE); /* go into insert mode, insert mode */ X break; Xcase 23: /* delete last thing manipulated */ X succ = rmvlst(); X break; Xcase 24: /* save lines in move buffer */ X succ = save(lexcnt,FALSE); X break; Xcase 25: /* get move buffer */ X succ = getsav(); X break; Xcase 26: /* read in next page of file */ X wtpage(lexcnt); /* write out the current page */ X succ = rdpage(); /* read in the next */ X tvclr(); X if (succ || lexcnt < 0) X verify(1); X break; Xcase 27: /* append external file to save buffer */ X succ = addfil(lexcnt); X break; Xcase 28: /* quit */ X tvclr(); X remark("Exit"); X goto lquit; Xcase 29: /* search again */ X succ = search(lexcnt,FALSE); /* FALSE => don't read search string */ X break; Xcase 30: /* execute repeat buffer again */ X if (lexcnt != 1) X echof=FALSE; /* turn off echo */ X rptcnt[rptuse] = lexcnt > 0 ? lexcnt : (-lexcnt); X break; Xcase 31: /* print memory status, etc. */ X memory(); X break; Xcase 32: /* change a parameter */ X setpar(lexcnt); X break; Xcase 33: /* remove last and enter insert mode */ X if ((succ = rmvlst())) X succ = insert(1,TRUE); X break; Xcase 34: /* unkill last line killed */ X succ = unkill(); X break; Xcase 35: /* jump over a word */ X wordr(lexcnt); X break; Xcase 36: /* neg jump over word */ X wordr(-lexcnt); X break; Xcase 37: /* append to save buffer */ X succ = save(lexcnt,TRUE); X break; Xcase 38: /* print screen */ X scrprint(); X break; Xcase 39: /* show repeat buffer + help*/ X shoset(); X break; Xcase 40: /* flip screen half page */ X dwnlin( min((lexcnt*tvlins)/2 , nxtlin-curlin+1) ); X break; Xcase 41: /* abort */ X abort(); X break; Xcase 42: /* change characters */ X if ((succ = delnxt(lexcnt))) X succ = insert(1,TRUE); X break; Xcase 43: /* jump back to last location */ X itmp = curlin; X curlin = lastln; X curchr = *(lines+curlin)+1; /* point to the current character */ X verify(1); X lastln = itmp; X break; Xcase 44: /* tidy up screen */ X succ = neaten(lexcnt); X break; Xcase 45: /* save current location */ X if (lexcnt < 1 || lexcnt > 9) X lexcnt = 0; X noteloc[lexcnt] = curlin; X break; Xcase 46: /* return to noted location */ X itmp = curlin; X if (lexcnt < 1 || lexcnt > 9) X lexcnt = 0; X if (noteloc[lexcnt] >= nxtlin) X { X tverrb("Line no longer there "); X noteloc[lexcnt] = curlin; X } X else X { X curlin = noteloc[lexcnt]; X curchr = *(lines+curlin)+1; /* point to the current character */ X verify(1); X lastln = itmp; X } X break; X Xcase 47: X opsystem(); /* call operating system */ X break; X Xcase 48: X if (lex_def) /* default 1 passed */ X lexcnt = rptuse + 1; /* use current repeat loop */ X succ = edit_rpt(lexcnt); /* edit repeat buffer */ X break; X Xcase 49: X succ = store_rpt(lexcnt); /* store repeat buffer */ X break; X Xcase 50: X succ = exec_rpt(lexcnt); /* execute repeat buffer */ X break; X Xcase 51: X succ = ins_pat(lexcnt); X break; Xcase 52: X succ = user_1(lexcnt); /* user function 1 */ X break; X Xcase 53: X succ = user_2(lexcnt); /* user function 2 */ X break; X } /* end of switch */ X continue; /* next iteration of do loop */ X } /* end of else */ X } /* end of do loop */ X while (1); X Xlquit: X for ( wtpage(1) ; rdpage() ; wtpage(1) ) /* write whole file */ X ; X tvclr(); X } X X/* =============================>>> EDIT_RPT <<<============================= */ X edit_rpt(val) X int val; X { /* copy repeat buffer val into buffer for editing */ X X SLOW char *cp; X SLOW int start_line; X X if (val == 0) X val = rptuse+1; X X if (!chk_rpt_nr(val)) X return FALSE; X X --val; /* change to relative */ X X beglin(); /* start by moving to beginning of current line */ X start_line = curlin; /* where we started */ X X X ins_chr('#'); ins_chr(val+'1'); ins_chr(':'); X /* start with number */ X ins_chr('<'); /* insert start of repeat loop */ X X for (cp = &rptbuf[val][0] ; *cp ; ++cp) X ins_chr(*cp); X ins_chr(27); ins_chr(27); /* make a way for store_rpt to find end */ X X ins_chr(CR); /* terminate line */ X curlin = start_line; X curchr = *(lines+curlin)+1; X verify(1); X X return (TRUE); X X } X X/* =============================>>> ENDLIN <<<============================= */ X endlin() X { /* endlin - move cursor to end of the line */ X X FAST int cnt; X SLOW BUFFINDEX i; X X cnt=0; X for (i=curchr; *(buff+i)!=ENDLINE; ++i) /* find end of line */ X ++cnt; X right(cnt); /* move to end of line */ X } X X/* =============================>>> EXEC_RPT <<<============================= */ X exec_rpt(knt) X int knt; X { /* this is combination of k:r,n& */ X static char chr; X static int val; X X if (! grptch(&chr)) /* get buffer # (k) to use */ X return (FALSE); X X val = chr - '0'; /* convert to 0 to 9 */ X X if (!chk_rpt_nr(val)) X return FALSE; X X if (val > 0) /* change to specific buffer */ X rptuse=val-1; /* adjust for 0 index int */ X X if (knt != 1) X echof = FALSE; /* turn off echo */ X X rptcnt[rptuse] = knt > 0 ? knt : (-knt); X X return (TRUE); X } X X/* =============================>>> FINDDL <<<============================= */ X finddl(ibeg,cnt) X int *ibeg,*cnt; X { /* finddl - find the display line X known: current line, calculate where it would go on the screen */ X X if (curlin <= dsplin) X { /* it is in first part of the display */ X *ibeg = 1; X *cnt = min(tvlins,nxtlin-1); X tvdlin = curlin; /* update the display line */ X } X else if (nxtlin-curlin <= tvlins-dsplin) /* at bottom of display */ X { X *ibeg = max(1,nxtlin-tvlins); X *cnt = min(tvlins,nxtlin-1); X tvdlin=min(curlin,tvlins-(nxtlin-curlin)+1); X } X else /* normal case: in middle */ X { X *ibeg=max(1,curlin-dsplin+1); X *cnt=min(tvlins,nxtlin-(*ibeg)); X tvdlin=dsplin; X } X } X X/* =============================>>> FINDX <<<============================= */ X int findx() X { /* findx - find the x position of the current character X handles spacing for tabs, control characters etc */ X X SLOW BUFFINDEX i; X SLOW int pos,lmold; X X pos = 0; X for (i = *(lines+curlin)+1; i<=curchr; ++i) X if (*(buff+i-1)<' ' && *(buff+i-1)>0) /* cur pos depends on last chr */ X if (*(buff+i-1)==TAB) /* handle tabs */ X for (++pos ; ((pos-1) % 8)!=0; ++pos) X ; X else /* control characters (echoed as ^X) */ X pos += 2; /* 2 spaces for other control character */ X else /* normal character */ X ++pos; X X lmold = leftmg; /* old left margin */ X for (;;) X { X if (pos < leftmg) /* won't fit on screen */ X leftmg -= 16; /* shift left */ X else if (pos >= tvcols+leftmg) X leftmg += 16; X else X break; X } X X if (leftmg != lmold) /* this handles screen shift */ X newscr(); X X return (pos-leftmg+1); X } X X/* =============================>>> FIXEND <<<============================= */ X fixend() X { /* fixend - fix the error message line */ X X SLOW int lastl; X X lastl = curlin+(tvlins-tvdlin); /* the last line on the display */ X tvxy(1,tvhardlines); /* get to last line */ X tvelin(); X if (lastl < nxtlin && tvlins == tvhardlines) /* only if really there */ X tvtype(lastl,1); /* write it out */ X if (curlin >= 1) X tvhdln(); /* restore cursor */ X else X tvxy(1,1); X } X X/* =============================>>> GBGCOL <<<============================= */ X int gbgcol() X { /* gbgcol - retrieve unused space in buff */ X X FAST int i; X SLOW int lastln; X SLOW BUFFINDEX nxtbad, nxtgud, to, from, whfrom, offset, newlin; X X tverrb("Compacting buffer "); /* let the user know, it might take a while */ X offset = curchr - *(lines+curlin); /* need to reset curchr later */ X X for (nxtbad=1 ; *(buff+nxtbad)!=GARBAGE && nxtbad < nxtchr; ++nxtbad) X ; /* find first space to free */ X nxtgud=nxtbad; X lastln = 1; /* where to start search */ X do X { X to=nxtbad; X for (from=nxtgud; *(buff+from)==GARBAGE && from<nxtchr; ++from) X ; /* find the next non-garbage character */ X X/* nxtbad pts to first junk character, X nxtgud pts to next possibly good character */ X X if (from >= nxtchr) X break; /* at the end of the buffer */ X whfrom=from; /* where it came from */ X newlin = to; /* remember start */ X do X { X *(buff+to) = *(buff+from++); /* copy good stuff up */ X } X while (*(buff+to++)!=ENDLINE); X X nxtbad=to ; nxtgud=from; X X/* now find the old line X following algorithm assumes next line is likely to X be near the previous line */ X X for (i=lastln ; i<nxtlin ; ++i) /* start where last looked */ X if (*(lines+i)==whfrom) X { X *(lines+i)=newlin; /* point to new position */ X if (curlin==i) X curchr=newlin+offset; /* fix curchr if need be */ X break; X } X X if (i >= nxtlin) /* not found in second half */ X { X for (i=1 ; i < lastln ; ++i) X if (*(lines+i)==whfrom) X { X *(lines+i)=newlin; /* point to new position */ X if (curlin==i) X curchr=newlin+offset; /* fix curchr if need be */ X break; X } X if (i >= lastln) /* make sure we really found it */ X { X tverrb("Compactor lost. Quit NOW! "); X for (i=1 ; i < 32000 ; ++i) X ; X return (FALSE); X } X } X lastln = i; /* start at next line down */ X } X while (nxtgud < nxtchr); X X for (to=nxtbad ; to<=nxtchr ; ) X *(buff+to++)=GARBAGE; X X nxtchr=nxtbad; /* update the next free character */ X tverr("Compactor done"); X return (nxtsav-nxtchr >= 50); X } X X/* =============================>>> GETSAV <<<============================= */ X int getsav() X { /* ## getsav - get text from save buffer */ X X FAST int to,from; X SLOW BUFFINDEX fromch; X SLOW int newlin; X X if (mxbuff-nxtsav+savlin >= nxtsav-nxtchr) /* g.c. */ X if (!gbgcol()) X { X tverrb("No get room "); X return (FALSE); X } X X if (nxtsav==mxbuff) /* nothing to save */ X { X return (TRUE); X } X X if (mxbuff-nxtsav+savlin >= nxtsav-nxtchr || mxline-nxtlin <= savlin) X { /* room to get save buffer? */ X tverrb("No get room "); X return (FALSE); /* no room to save */ X } X X/* check if in middle of line */ X if (curchr > lines[curlin]+1) X ins_chr(CR); X X/* # move down line to make space for new */ X from=nxtlin-1; X nxtlin=nxtlin+savlin; X to=nxtlin-1; X while (from >= curlin) /* copy line ptrs down right amnt. */ X *(lines+(to--)) = *(lines+(from--)); X X newlin=curlin; /* will insert new lines here */ X curlin=to+1; X fromch = mxbuff; /* where taking saved stuff from */ X for ( ; newlin < curlin; ++newlin) X { X *(buff+nxtchr)=BEGLINE; /* insert begline character */ X *(lines+newlin) = nxtchr++; /* update line ptrs to new line */ X do /* copy stuff from save buffer */ X { X *(buff+nxtchr++) = *(buff+fromch); X } X while (*(buff+fromch--)); X } X oldlen=0; X savlen=savlin; X newscr(); X return (TRUE); X } X X/* =============================>>> GRPTCH <<<============================= */ X int grptch(chr) X char *chr; X { /* grptch - gets a char from repeat buffer or gkbd */ X X SLOW char tmpchr; X X if (rptcnt[rptuse]>0) /* need to fetch from repeat buffer */ X if (nxtrpt[rptuse] > lstrpt[rptuse]) X { X return (FALSE); X } X else X { X *chr=rptbuf[rptuse][nxtrpt[rptuse]]; X ++nxtrpt[rptuse]; X } X else X { X gkbd(&tmpchr); /* read the character from the keyboard */ X *chr=tmpchr; X } X return (TRUE); X } X X/* =============================>>> ins_pat <<<============================= */ X ins_pat(lexcnt) X int lexcnt; X { X SLOW char *chrp; X X if (!*pat_buff) X return (FALSE); X for (chrp = pat_buff ; *chrp ; ) /* simply insert pattern buffer */ X { X if (!ins_chr(*chrp++)) /* make sure it works */ X return (FALSE); X } X X return (TRUE); X } X X/* =============================>>> save_pat <<<============================= */ X save_pat() X { /* save the find pattern, based on oldlen */ X X SLOW int i; X SLOW char *chrp; X X X if (oldlen <= 0) X { X pat_buff[0] = 0; X return; /* nothing to save */ X } X X for (i = 1 ; i <= oldlen ; ++i) /* first, move left */ X { X --curchr; X if (*(buff+curchr) == BEGLINE) X { X if (curlin > 1) X { X --curlin; X for (curchr = *(lines+curlin) ; *(buff+curchr)!=ENDLINE ; X ++curchr) X ; /* bump curchr to end of the line */ X } X else X { X ++curchr; X break; X } X } X } X X /* now save, go back right */ X X chrp = pat_buff; /* put in pattern buffer */ X X for (i = 1 ; i <= oldlen ; ++i) X { X if (*(buff+curchr)==ENDLINE) X { X if (curlin+1 >= nxtlin) X break; /* don't go beyond end! */ X ++curlin; X curchr = *(lines+curlin)+1; X *chrp++ = CR; /* make a cr */ X } X else X { X if ((chrp - 100) < pat_buff) /* make sure enough room */ X *chrp++ = *(buff+curchr); X ++curchr; X } X } X *chrp = 0; /* terminate */ X } X X/* =============================>>> INSET <<<============================= */ X inset(val,set) X int val,*set; X { X /* return true if val is in set set */ X X while (*set) X if (val == *set++) X return TRUE; X return FALSE; X } X X/* =============================>>> ins_chr <<<============================= */ X ins_chr(ival) X int ival; X { X return insert(ival,FALSE); /* force insert */ X } X X/* =============================>>> INSERT <<<============================= */ X insert(ival,how) X int ival,how; X { /* insert - insert a character X X if how is TRUE, then read characters from keyboard until X get an escape, otherwise insert ival */ X X SLOW BUFFINDEX from,to; X SLOW BUFFINDEX curbuf,curend; X SLOW int lenins, nocins, ityp, xf; X SLOW BUFFINDEX abvchr; X X SLOW char chr; X X X static int ins_msg = TRUE; /* own variable */ X X if (ins_msg) X csrins(); /* change cursor */ X X if (how) /* how = 1 regular insert mode */ X { X if (! grptch(&chr)) /* get char using grptch */ X goto l9999; X if (chr == ESC) /* esc means done */ X { X goto l1000; X } X } X else X chr = ival; /* use the passed value */ X X if (chr==ENDLINE || chr==BEGLINE || chr==GARBAGE || (chr==ENDFILE && usecz)) X goto l9998; /* don't allow this case! */ X X if (curlin < 1) X { /* buffer empty? */ X curlin=1; /* init for initial insert */ X *(lines+1)=nxtchr; X curchr=nxtchr+1; X *(buff+nxtchr)=BEGLINE; X *(buff+nxtchr+1)=ENDLINE; X nxtchr += 2; X nxtlin = 2; X } X X lenins=0; /* remember length of insert for rmvlst */ X X do X { X if (nxtsav-nxtchr < ALMOSTOUT) X if (!gbgcol()) X goto l9999; /* collect garbage if necessary */ X curbuf = *(lines+curlin); /* pick up the pointer to current line */ X for (curend=curbuf; *(buff+curend)!=ENDLINE; ++curend) X ; /* get line length */ X if (curend+1 < nxtchr) /* not using last part of buffer */ X { X if (curend-curbuf >= nxtsav-nxtchr) X goto l9998; /* no more room! */ X curchr=nxtchr+(curchr-curbuf); /* where curchr will be */ X *(lines+curlin)=nxtchr; /* new line goes here */ X stcopy(buff,curbuf,buff,&nxtchr); /* copy the line to the end */ X curend=nxtchr++; /* reset end pointer */ X kline(curbuf); /* kill off the line */ X curbuf = *(lines+curlin); /* update beginning pointer */ X } X X/* # to here, ready to insert the new character at the end of the line */ X X if (chr==' ' && wraplm > 1 && (tvx >= wraplm || leftmg > 1)) /* auto wrap? */ X chr = CR; X#ifdef FILELF X if (chr == LF && how) X ; /* don't insert lfs in CR/LF systems, echo? */ X else if (chr == CR) /* inserting a new line */ X#else X if (chr == CR) /* inserting a new line */ X#endif X { X if (nxtlin >= mxline) /* any room? */ X { X tverrb("No more free lines for insert "); X goto l9999; X } X X for (from=curend; from >= curchr; --from) X *(buff+from+2) = *(buff+from); /* copy chars down */ X nxtchr += 2; /* bump nxtchr to free space */ X X *(buff+curchr) = ENDLINE; /* mark as endline */ X *(buff+curchr+1) = BEGLINE; /* beginning of line */ X ++lenins; X X to=nxtlin; /* move lines down */ X for (from = nxtlin-1; from > curlin; ) X { /* bump the lines down */ X *(lines+to--) = *(lines+from--); X } X ++nxtlin; /* bump to next free line */ X X *(lines+curlin+1)=curchr+1; /* remember where */ X X if (ins_msg) X fixend(); /* fix last line */ X tvelin(); /* erase stuff after cr */ X X nocins = (leftmg > 1); /* ciline no good if left marg > 1 */ X X dwnlin(1); /* go down one line */ X X if (ciline[0] == 0 || nocins) X { X tvescr(); /* erase the rest of the screen */ X ityp = min(tvlins-tvdlin+1,nxtlin-curlin); X } X else X { X tvinsl(); /* insert a line */ X ityp = 1; X } X X tvtype(curlin,ityp); X tvhdln(); X if (ins_msg) X csrins(); /* change cursor */ X X if (autoin && curlin > 2) /* automatic indentation! */ X { X ins_msg = FALSE; /* turn off insert message */ X abvchr = *(lines+curlin-1)+1; /* prevous line */ X while (*(buff+abvchr)==' ' || *(buff+abvchr)==TAB) X if (!insert(*(buff+abvchr++),FALSE) ) X { X ins_msg = TRUE; X goto l9999; X } X else if (ttymode) /* hmm, now what? */ X { X ttymode = FALSE; X ttwt(*(buff+abvchr-1)); X ttymode = TRUE; X } X ins_msg = TRUE; X fixend(); X csrins(); /* change cursor */ X } X } X else if (chr == delkey && how) X { X if (!delnxt(-1)) /* rubbing out last character */ X goto l9999; X --lenins; X } X else /* inserting on the current line */ X { X to = nxtchr; /* will move to nxtchr */ X for (from = curend ; from >= curchr; ) X { X *(buff+to--) = *(buff+from--); X } X curend=nxtchr++; /* end is now at curchr, bump nxtchr */ X *(buff+curchr)=chr; /* stick in the current character */ X ++lenins; X if (tvlins < tvhardlines - 10) X { X tvelin(); X ctrlch(chr); X ctrlch('+'); X } X else X tvtyln(curchr); /* retype rest of the line */ X ++curchr; /* reset the curchr pointer */ X xf = findx(); X tvxy(xf,tvy); /* reset the cursor */ X } X X/* the character has been inserted and displayed, get another maybe */ X X if (how) X if (!grptch(&chr)) X goto l9999; X } X while (how && chr != ESC); /* end of do */ X X if (tvlins < tvhardlines - 10) /* fix for slow baud */ X { X tvelin(); X tvtyln(curchr); /* retype rest of the line */ X xf = findx(); X tvxy(xf,tvy); /* reset the cursor */ X } X X oldlen = lenins; X savlen = (-1); /* haven't saved lines */ X goto l1000; X Xl9998: X tverrb("Can't insert that char "); Xl9999: X csrcmd(); X return FALSE; Xl1000: X X if (ins_msg) X fixend(); X csrcmd(); X return TRUE; X } X/* ------------------------ tvx_1.c ------------------------------------- */ SHAR_EOF echo ALL DONE! exit 0