TVX: Part 2a of 7, repost
wampler at unmvax.UUCP
wampler at unmvax.UUCP
Wed Jan 22 03:00:08 AEST 1986
#--------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
More information about the Comp.sources.unix
mailing list