Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!rutgers!ames!ucbcad!ucbvax!decvax!decwrl!cookie.dec.com!wecker From: wecker@cookie.dec.com.UUCP Newsgroups: comp.sys.amiga Subject: uEMACS (V1.0 DBW 870220) my own version Part 2/4 Message-ID: <8186@decwrl.DEC.COM> Date: Fri, 20-Feb-87 20:07:15 EST Article-I.D.: decwrl.8186 Posted: Fri Feb 20 20:07:15 1987 Date-Received: Sat, 21-Feb-87 16:26:53 EST Sender: daemon@decwrl.DEC.COM Organization: Digital Equipment Corporation Lines: 3354 # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # ansi.c # basic.c # bind.c # buffer.c # display.c # file.c # This archive created: Fri Feb 20 17:44:29 1987 echo shar: extracting ansi.c sed 's/^XX//' << \SHAR_EOF > ansi.c XX/* XX * The routines in this file provide support for ANSI style terminals XX * over a serial line. The serial I/O services are provided by routines in XX * "termio.c". It compiles into nothing if not an ANSI device. XX */ XX XX#define termdef 1 /* don't define "term" external */ XX XX#include XX#include "estruct.h" XX#include "edef.h" XX XX#if ANSI XX XX#define NROW 23 /* Screen size. */ XX#define NCOL 77 /* Edit if you want to. */ XX#define MARGIN 8 /* size of minimim margin and */ XX#define SCRSIZ 64 /* scroll size for extended lines */ XX#define BEL 0x07 /* BEL character. */ XX#define ESC 0x1B /* ESC character. */ XX XXextern int ttopen(); /* Forward references. */ XXextern int ttgetc(); XXextern int ttputc(); XXextern int ttflush(); XXextern int ttclose(); XXextern int ansimove(); XXextern int ansieeol(); XXextern int ansieeop(); XXextern int ansibeep(); XXextern int ansiopen(); XXextern int ansiinsert(); XXextern int ansidelete(); XX XX/* XX * Standard terminal interface dispatch table. Most of the fields point into XX * "termio" code. XX */ XXTERM term = { XX NROW-1, XX NCOL, XX MARGIN, XX SCRSIZ, XX ansiopen, XX ttclose, XX ttgetc, XX ttputc, XX ttflush, XX ansimove, XX ansieeol, XX ansieeop, XX ansibeep, XX ansiinsert, XX ansidelete XX }; XX XXansimove(row, col) XX { XX if (batchmode) return(TRUE); XX ttputc(ESC); XX ttputc('['); XX ansiparm(row+1); XX ttputc(';'); XX ansiparm(col+1); XX ttputc('H'); XX } XX XXansieeol() XX { XX if (batchmode) return(TRUE); XX ttputc(ESC); XX ttputc('['); XX ttputc('K'); XX } XX XXansieeop() XX { XX if (batchmode) return(TRUE); XX ttputc(ESC); XX ttputc('['); XX ttputc('J'); XX } XX XXansibeep() XX { XX if (batchmode) return(TRUE); XX ttputc(BEL); XX ttflush(); XX } XX XXansiparm(n) XXregister int n; XX { XX register int q; XX XX if (batchmode) return(TRUE); XX q = n/10; XX if (q != 0) ansiparm(q); XX ttputc((n%10) + '0'); XX } XX XXansiinsert(row,n) XX { XX if (batchmode) return(TRUE); XX ansimove(row,0); XX ttputc(ESC); XX ttputc('['); XX ansiparm(n); XX ttputc('L'); XX mlerase(); XX } XX XXansidelete(row,n) XX { XX if (batchmode) return(TRUE); XX mlerase(); XX ansimove(row,0); XX ttputc(ESC); XX ttputc('['); XX ansiparm(n); XX ttputc('M'); XX } XX XX#endif XX XXansiopen() XX { XX#if ULTRIX XX register char *cp; XX char *getenv(); XX XX if (batchmode) return(TRUE); XX if ((cp = getenv("TERM")) == NULL) { XX puts("Shell variable TERM not defined!"); XX exit(1); XX } XX if (strcmp(cp, "vt100") != 0) { XX puts("Terminal type not 'vt100'!"); XX exit(1); XX } XX#endif XX if (batchmode) return(TRUE); XX ttopen(); XX } SHAR_EOF if test 2731 -ne "`wc -c ansi.c`" then echo shar: error transmitting ansi.c '(should have been 2731 characters)' fi echo shar: extracting basic.c sed 's/^XX//' << \SHAR_EOF > basic.c XX/* XX * The routines in this file move the cursor around on the screen. They XX * compute a new value for the cursor, then adjust ".". The display code XX * always updates the cursor location, so only moves between lines, or XX * functions that adjust the top line in the window and invalidate the XX * framing, are hard. XX */ XX#include XX#include "estruct.h" XX#include "edef.h" XX XX/* XX * Move the cursor to the XX * beginning of the current line. XX * Trivial. XX */ XXgotobol(f, n) XX { XX curwp->w_doto = 0; XX return (TRUE); XX } XX XX/* XX * Move the cursor backwards by "n" characters. If "n" is less than zero call XX * "forwchar" to actually do the move. Otherwise compute the new cursor XX * location. Error if you try and move out of the buffer. Set the flag if the XX * line pointer for dot changes. XX */ XXbackchar(f, n) XXregister int n; XX { XX register LINE *lp; XX XX if (n < 0) return (forwchar(f, -n)); XX while (n--) { XX if (curwp->w_doto == 0) { XX if ((lp=lback(curwp->w_dotp)) == curbp->b_linep) return (FALSE); XX curwp->w_dotp = lp; XX curwp->w_doto = llength(lp); XX curwp->w_flag |= WFMOVE; XX } XX else XX curwp->w_doto--; XX } XX return (TRUE); XX } XX XX/* XX * Move the cursor to the end of the current line. Trivial. No errors. XX */ XXgotoeol(f, n) XX { XX curwp->w_doto = llength(curwp->w_dotp); XX return (TRUE); XX } XX XX/* XX * Move the cursor forwwards by "n" characters. If "n" is less than zero call XX * "backchar" to actually do the move. Otherwise compute the new cursor XX * location, and move ".". Error if you try and move off the end of the XX * buffer. Set the flag if the line pointer for dot changes. XX */ XXforwchar(f, n) XXregister int n; XX { XX if (n < 0) return (backchar(f, -n)); XX while (n--) { XX if (curwp->w_doto == llength(curwp->w_dotp)) { XX if (curwp->w_dotp == curbp->b_linep) return (FALSE); XX curwp->w_dotp = lforw(curwp->w_dotp); XX curwp->w_doto = 0; XX curwp->w_flag |= WFMOVE; XX } XX else XX curwp->w_doto++; XX } XX return (TRUE); XX } XX XXgotoline(f, n) /* move to a particular line. XX argument (n) must be a positive integer for XX this to actually do anything */ XX XX { XX if (n < 1) /* if a bogus argument...then leave */ XX return(FALSE); XX XX /* first, we go to the start of the buffer */ XX curwp->w_dotp = lforw(curbp->b_linep); XX curwp->w_doto = 0; XX return(forwline(f, n-1)); XX } XX XX/* XX * Goto the beginning of the buffer. Massive adjustment of dot. This is XX * considered to be hard motion; it really isn't if the original value of dot XX * is the same as the new value of dot. Normally bound to "M-<". XX * arg 0 = do not set mark XX */ XXgotobob(f, n) { XX curwp->w_dotp = lforw(curbp->b_linep); XX curwp->w_doto = 0; XX curwp->w_flag |= WFHARD; XX return (TRUE); XX } XX XX/* XX * Move to the end of the buffer. Dot is always put at the end of the file XX * (ZJ). The standard screen code does most of the hard parts of update. XX * Bound to "M->". arg 0 = don't set mark. XX */ XXgotoeob(f, n) { XX curwp->w_dotp = lback(curbp->b_linep); XX curwp->w_doto = curwp->w_dotp->l_used; XX curwp->w_flag |= WFHARD; XX return (TRUE); XX } XX XX/* XX * Move forward by full lines. If the number of lines to move is less than XX * zero, call the backward line function to actually do it. The last command XX * controls how the goal column is set. Bound to "C-N". No errors are XX * possible. XX */ XXforwline(f, n) XX { XX register LINE *dlp; XX XX if (n < 0) return (backline(f, -n)); XX if ((lastflag&CFCPCN) == 0) /* Reset goal if last */ XX curgoal = curcol; /* not C-P or C-N */ XX thisflag |= CFCPCN; XX dlp = curwp->w_dotp; XX while (n-- && dlp!=curbp->b_linep) dlp = lforw(dlp); XX curwp->w_dotp = dlp; XX curwp->w_doto = getgoal(dlp); XX curwp->w_flag |= WFMOVE; XX return (TRUE); XX } XX XX/* XX * This function is like "forwline", but goes backwards. The scheme is exactly XX * the same. Check for arguments that are less than zero and call your XX * alternate. Figure out the new line and call "movedot" to perform the XX * motion. No errors are possible. Bound to "C-P". XX */ XXbackline(f, n) XX { XX register LINE *dlp; XX XX if (n < 0) return (forwline(f, -n)); XX if ((lastflag&CFCPCN) == 0) /* Reset goal if the */ XX curgoal = curcol; /* last isn't C-P, C-N */ XX thisflag |= CFCPCN; XX dlp = curwp->w_dotp; XX while (n-- && lback(dlp)!=curbp->b_linep) dlp = lback(dlp); XX curwp->w_dotp = dlp; XX curwp->w_doto = getgoal(dlp); XX curwp->w_flag |= WFMOVE; XX return (TRUE); XX } XX XXgotobop(f, n) /* go back to the begining of the current paragraph XXhere we look for a or or XXcombination to delimit the begining of a paragraph */ XX XXint f, n; /* default Flag & Numeric argument */ XX XX { XX register int suc; /* success of last backchar */ XX XX if (n < 0) /* the other way...*/ XX return(gotoeop(f, -n)); XX XX while (n-- > 0) { /* for each one asked for */ XX /* first scan back until we are in a word */ XX suc = backchar(FALSE, 1); XX while (!inword() && suc) suc = backchar(FALSE, 1); XX curwp->w_doto = 0; /* and go to the B-O-Line */ XX XX /* and scan back until we hit a or XX or a */ XX while (lback(curwp->w_dotp) != curbp->b_linep) if (llength(curwp->w_dotp) != 0 && lgetc(curwp->w_dotp, curwp->w_doto) != TAB && XX lgetc(curwp->w_dotp, curwp->w_doto) != ' ') XX curwp->w_dotp = lback(curwp->w_dotp); XX else XX break; XX XX /* and then forward until we are in a word */ XX suc = forwchar(FALSE, 1); XX while (suc && !inword()) suc = forwchar(FALSE, 1); XX } XX curwp->w_flag |= WFMOVE; /* force screen update */ XX } XX XXgotoeop(f, n) /* go forword to the end of the current paragraph XXhere we look for a or or XXcombination to delimit the begining of a paragraph */ XX XXint f, n; /* default Flag & Numeric argument */ XX XX { XX register int suc; /* success of last backchar */ XX XX if (n < 0) /* the other way...*/ XX return(gotobop(f, -n)); XX XX while (n-- > 0) { /* for each one asked for */ XX /* first scan forward until we are in a word */ XX suc = forwchar(FALSE, 1); XX while (!inword() && suc) suc = forwchar(FALSE, 1); XX curwp->w_doto = 0; /* and go to the B-O-Line */ XX if (suc) /* of next line if not at EOF */ XX curwp->w_dotp = lforw(curwp->w_dotp); XX XX /* and scan forword until we hit a or XX or a */ XX while (curwp->w_dotp != curbp->b_linep) { XX if (llength(curwp->w_dotp) != 0 && lgetc(curwp->w_dotp, curwp->w_doto) != TAB && XX lgetc(curwp->w_dotp, curwp->w_doto) != ' ') XX curwp->w_dotp = lforw(curwp->w_dotp); XX else XX break; XX } XX XX /* and then backward until we are in a word */ XX suc = backchar(FALSE, 1); XX while (suc && !inword()) { XX suc = backchar(FALSE, 1); XX } XX curwp->w_doto = llength(curwp->w_dotp); /* and to the EOL */ XX } XX curwp->w_flag |= WFMOVE; /* force screen update */ XX } XX XX/* XX * This routine, given a pointer to a LINE, and the current cursor goal XX * column, return the best choice for the offset. The offset is returned. XX * Used by "C-N" and "C-P". XX */ XXgetgoal(dlp) XXregister LINE *dlp; XX { XX register int c; XX register int col; XX register int newcol; XX register int dbo; XX XX col = 0; XX dbo = 0; XX while (dbo != llength(dlp)) { XX c = lgetc(dlp, dbo); XX newcol = col; XX if (c == '\t') newcol |= 0x07; XX else if (c<0x20 || c==0x7F) XX ++newcol; XX ++newcol; XX if (newcol > curgoal) break; XX col = newcol; XX ++dbo; XX } XX return (dbo); XX } XX XX/* XX * Scroll forward by a specified number of lines, or by a full page if no XX * argument. Bound to "C-V". The "2" in the arithmetic on the window size is XX * the overlap; this value is the default overlap value in ITS EMACS. Because XX * this zaps the top line in the display window, we have to do a hard update. XX */ XXforwpage(f, n) XXregister int n; XX { XX register LINE *lp; XX XX if (f == FALSE) { XX n = curwp->w_ntrows - 2; /* Default scroll. */ XX if (n <= 0) /* Forget the overlap */ XX n = 1; /* if tiny window. */ XX } XX else if (n < 0) XX return (backpage(f, -n)); XX#if CVMVAS XX else /* Convert from pages */ XX n *= curwp->w_ntrows; /* to lines. */ XX#endif XX lp = curwp->w_linep; XX while (n-- && lp!=curbp->b_linep) lp = lforw(lp); XX curwp->w_linep = lp; XX curwp->w_dotp = lp; XX curwp->w_doto = 0; XX curwp->w_flag |= WFHARD; XX return (TRUE); XX } XX XX/* XX * This command is like "forwpage", but it goes backwards. The "2", like XX * above, is the overlap between the two windows. The value is from the ITS XX * EMACS manual. Bound to "M-V". We do a hard update for exactly the same XX * reason. XX */ XXbackpage(f, n) XXregister int n; XX { XX register LINE *lp; XX XX if (f == FALSE) { XX n = curwp->w_ntrows - 2; /* Default scroll. */ XX if (n <= 0) /* Don't blow up if the */ XX n = 1; /* window is tiny. */ XX } XX else if (n < 0) XX return (forwpage(f, -n)); XX#if CVMVAS XX else /* Convert from pages */ XX n *= curwp->w_ntrows; /* to lines. */ XX#endif XX lp = curwp->w_linep; XX while (n-- && lback(lp)!=curbp->b_linep) lp = lback(lp); XX curwp->w_linep = lp; XX curwp->w_dotp = lp; XX curwp->w_doto = 0; XX curwp->w_flag |= WFHARD; XX return (TRUE); XX } XX XX/* XX * Set the mark in the current window to the value of "." in the window. No XX * errors are possible. Bound to "M-.". arg 0 = do not report mark setting XX */ XXsetmark(f, n) XX { XX curwp->w_markp = curwp->w_dotp; XX curwp->w_marko = curwp->w_doto; XX if (f == FALSE || n != 0) mlwrite("[Mark set]"); XX return (TRUE); XX } XX XX/* XX * Swap the values of "." and "mark" in the current window. This is pretty XX * easy, bacause all of the hard work gets done by the standard routine XX * that moves the mark about. The only possible error is "no mark". Bound to XX * "C-X C-X". XX */ XXswapmark(f, n) XX { XX register LINE *odotp; XX register int odoto; XX XX if (curwp->w_markp == NULL) { XX mlwrite("No mark in this window"); XX return (FALSE); XX } XX odotp = curwp->w_dotp; XX odoto = curwp->w_doto; XX curwp->w_dotp = curwp->w_markp; XX curwp->w_doto = curwp->w_marko; XX curwp->w_markp = odotp; XX curwp->w_marko = odoto; XX curwp->w_flag |= WFMOVE; XX return (TRUE); XX } XX XX SHAR_EOF if test 10190 -ne "`wc -c basic.c`" then echo shar: error transmitting basic.c '(should have been 10190 characters)' fi echo shar: extracting bind.c sed 's/^XX//' << \SHAR_EOF > bind.c XX/* This file is for functions having to do with key bindings, XX * descriptions, help commands, and command line execution. XX */ XX XX#include XX#include "estruct.h" XX#include "edef.h" XX XX#define INBIND TRUE XX#include "epath.h" XX XXextern short doflashing; XX XXdeskey(f, n) /* describe the command for a certain key */ XX { XX register int c; /* command character to describe */ XX register char *ptr; /* string pointer to scan output strings */ XX register KEYTAB *ktp; /* pointer into the command table */ XX register int found; /* matched command flag */ XX register NBIND *nptr; /* pointer into the name binding table */ XX char outseq[80]; /* output buffer for command sequence */ XX XX /* prompt the user to type us a key to describe */ XX mlwrite(": describe-key "); XX XX /* get the command sequence to describe */ XX c = getckey(); /* get a command sequence */ XX XX /* change it to something we can print as well */ XX cmdstr(c, &outseq[0]); XX XX /* and dump it out */ XX ptr = &outseq[0]; XX while (*ptr) (*term.t_putchar)(*ptr++); XX (*term.t_putchar)(' '); /* space it out */ XX XX /* find the right ->function */ XX ktp = &keytab[0]; XX found = FALSE; XX while (ktp->k_fp != NULL) { XX if (ktp->k_code == c) { XX found = TRUE; XX break; XX } XX ++ktp; XX } XX XX if (!found) strcpy(outseq,"Not Bound"); XX else { XX /* match it against the name binding table */ XX nptr = &names[0]; XX strcpy(outseq,"[Bad binding]"); XX while (nptr->n_func != NULL) { XX if (nptr->n_func == ktp->k_fp) { XX strcpy(outseq, nptr->n_name); XX break; XX } XX ++nptr; XX } XX } XX XX /* output the command sequence */ XX ptr = &outseq[0]; XX while (*ptr) (*term.t_putchar)(*ptr++); XX } XX XXcmdstr(c, seq) /* change a key command to a string we can print out */ XX XXint c; /* sequence to translate */ XXchar *seq; /* destination string for sequence */ XX XX { XX char *ptr; /* pointer into current position in sequence */ XX XX ptr = seq; XX XX /* apply GOLD sequence if needed */ XX if (c & GOLD) { XX *ptr++ = 'G'; XX *ptr++ = '-'; XX } XX XX /* apply SPEC sequence if needed */ XX if (c & SPEC) { XX *ptr++ = 'K'; XX *ptr++ = '-'; XX } XX XX /* apply meta sequence if needed */ XX if (c & META) { XX *ptr++ = 'M'; XX *ptr++ = '-'; XX } XX XX /* apply ^X sequence if needed */ XX if (c & CTLX) { XX *ptr++ = '^'; XX *ptr++ = 'X'; XX } XX XX /* apply control sequence if needed */ XX if (c & CTRL) { XX *ptr++ = '^'; XX } XX XX c = c & 255; /* strip the prefixes */ XX XX /* and output the final sequence */ XX XX *ptr++ = c; XX *ptr = 0; /* terminate the string */ XX } XX XXhelp(f, n) /* give me some help!!!! XX bring up a fake buffer and read the help file XX into it with view mode */ XX { XX register int status; /* status of I/O operations */ XX register WINDOW *wp; /* scnaning pointer to windows */ XX register int i; /* index into help file names */ XX char fname[NSTRING]; /* buffer to construct file name in */ XX XX /* search through the list of help files */ XX for (i=2; i < NPNAMES; i++) { XX strcpy(fname, pathname[i]); XX strcat(fname, pathname[1]); XX status = ffropen(fname); XX if (status == FIOSUC) break; XX } XX XX if (status == FIOFNF) { XX mlwrite("[Help file is not online]"); XX return(FALSE); XX } XX ffclose(); /* close the file to prepare for to read it in */ XX XX /* split the current window to make room for the help stuff */ XX if (splitwind(FALSE, 1) == FALSE) return(FALSE); XX XX /* and read the stuff in */ XX if (getfile(fname, FALSE) == FALSE) return(FALSE); XX XX /* make this window in VIEW mode, update all mode lines */ XX curwp->w_bufp->b_mode |= MDVIEW; XX wp = wheadp; XX while (wp != NULL) { XX wp->w_flag |= WFMODE; XX wp = wp->w_wndp; XX } XX return(TRUE); XX } XX XXint (*fncmatch(fname))() /* match fname to a function in the names table XXand return any match or NULL if none */ XX XXchar *fname; /* name to attempt to match */ XX XX { XX register NBIND *ffp; /* pointer to entry in name binding table */ XX XX /* scan through the table, returning any match */ XX ffp = &names[0]; XX while (ffp->n_func != NULL) { XX if (strcmp(fname, ffp->n_name) == 0) return(ffp->n_func); XX ++ffp; XX } XX return(NULL); XX } XX XX/* bindtokey: add a new key to the key binding table XX */ XX XXbindtokey(f, n) XX XXint f, n; /* command arguments [IGNORED] */ XX XX { XX register int c; /* command key to bind */ XX register (*kfunc)(); /* ptr to the requexted function to bind to */ XX register char *ptr; /* ptr to dump out input key string */ XX register KEYTAB *ktp; /* pointer into the command table */ XX register int found; /* matched command flag */ XX char outseq[80]; /* output buffer for keystroke sequence */ XX int (*getcname())(); XX XX /* prompt the user to type in a key to bind */ XX mlwrite(": bind-to-key "); XX XX /* get the function name to bind it to */ XX kfunc = getcname(); XX if (kfunc == NULL) { XX mlwrite("[No such function]"); XX return(FALSE); XX } XX (*term.t_putchar)(' '); /* space it out */ XX XX /* get the command sequence to bind */ XX c = getckey(); /* get a command sequence */ XX XX /* change it to something we can print as well */ XX cmdstr(c, &outseq[0]); XX XX /* and dump it out */ XX ptr = &outseq[0]; XX while (*ptr) (*term.t_putchar)(*ptr++); XX XX /* search the table to see if it exists */ XX ktp = &keytab[0]; XX found = FALSE; XX while (ktp->k_fp != NULL) { XX if (ktp->k_code == c) { XX found = TRUE; XX break; XX } XX ++ktp; XX } XX XX if (found) { /* it exists, just change it then */ XX ktp->k_fp = kfunc; XX } XX else { /* otherwise we need to add it to the end */ XX /* if we run out of binding room, bitch */ XX if (ktp >= &keytab[NBINDS]) { XX mlwrite("Binding table FULL!"); XX return(FALSE); XX } XX XX ktp->k_code = c; /* add keycode */ XX ktp->k_fp = kfunc; /* and the function pointer */ XX ++ktp; /* and make sure the next is null */ XX ktp->k_code = 0; XX ktp->k_fp = NULL; XX } XX XX return(TRUE); XX } XX XX XX/* unbindkey: delete a key from the key binding table XX */ XX XXunbindkey(f, n) XX XXint f, n; /* command arguments [IGNORED] */ XX XX { XX register int c; /* command key to unbind */ XX register char *ptr; /* ptr to dump out input key string */ XX register KEYTAB *ktp; /* pointer into the command table */ XX register KEYTAB *sktp; /* saved pointer into the command table */ XX register int found; /* matched command flag */ XX char outseq[80]; /* output buffer for keystroke sequence */ XX XX /* prompt the user to type in a key to unbind */ XX mlwrite(": unbind-key "); XX XX /* get the command sequence to unbind */ XX c = getckey(); /* get a command sequence */ XX XX /* change it to something we can print as well */ XX cmdstr(c, &outseq[0]); XX XX /* and dump it out */ XX ptr = &outseq[0]; XX while (*ptr) (*term.t_putchar)(*ptr++); XX XX /* search the table to see if the key exists */ XX ktp = &keytab[0]; XX found = FALSE; XX while (ktp->k_fp != NULL) { XX if (ktp->k_code == c) { XX found = TRUE; XX break; XX } XX ++ktp; XX } XX XX /* if it isn't bound, bitch */ XX if (!found) { XX mlwrite("[Key not bound]"); XX return(FALSE); XX } XX XX /* save the pointer and scan to the end of the table */ XX sktp = ktp; XX while (ktp->k_fp != NULL) ++ktp; XX --ktp; /* backup to the last legit entry */ XX XX /* copy the last entry to the current one */ XX sktp->k_code = ktp->k_code; XX sktp->k_fp = ktp->k_fp; XX XX /* null out the last one */ XX ktp->k_code = 0; XX ktp->k_fp = NULL; XX return(TRUE); XX } XX XX/* namedcmd: execute a named command even if it is not bound XX */ XX XXnamedcmd(f, n) XX XXint f, n; /* command arguments [passed through to command executed] */ XX XX { XX register int c; /* command key to bind */ XX register (*kfunc)(); /* ptr to the requexted function to bind to */ XX register int found; /* matched command flag */ XX int (*getcname())(); XX XX /* prompt the user to type a named command */ XX mlwrite(": "); XX XX /* and now get the function name to execute */ XX kfunc = getcname(); XX if (kfunc == NULL) { XX mlwrite("[No such function]"); XX return(FALSE); XX } XX XX /* and then execute the command */ XX return((*kfunc)(f, n)); XX } XX XXdesbind(f, n) /* describe bindings XXbring up a fake buffer and list the key bindings XXinto it with view mode */ XX { XX register WINDOW *wp; /* scnaning pointer to windows */ XX register KEYTAB *ktp; /* pointer into the command table */ XX register NBIND *nptr; /* pointer into the name binding table */ XX register BUFFER *bp; /* buffer to put binding list into */ XX register char *strp; /* pointer int string to send */ XX register int cpos; /* current position to use in outseq */ XX char outseq[80]; /* output buffer for keystroke sequence */ XX XX /* split the current window to make room for the binding list */ XX if (splitwind(FALSE, 1) == FALSE) return(FALSE); XX XX /* and get a buffer for it */ XX bp = bfind("Binding list", TRUE, 0); XX if (bp == NULL || bclear(bp) == FALSE) { XX mlwrite("Can not display binding list"); XX return(FALSE); XX } XX XX /* let us know this is in progress */ XX mlwrite("[Building buffer list]"); XX XX /* disconect the current buffer */ XX if (--curbp->b_nwnd == 0) { /* Last use. */ XX curbp->b_dotp = curwp->w_dotp; XX curbp->b_doto = curwp->w_doto; XX curbp->b_markp = curwp->w_markp; XX curbp->b_marko = curwp->w_marko; XX } XX XX /* connect the current window to this buffer */ XX curbp = bp; /* make this buffer current in current window */ XX bp->b_mode = 0; /* no modes active in binding list */ XX bp->b_nwnd++; /* mark us as more in use */ XX wp = curwp; XX wp->w_bufp = bp; XX wp->w_linep = bp->b_linep; XX wp->w_flag = WFHARD|WFFORCE|WFHARD; XX wp->w_dotp = bp->b_dotp; XX wp->w_doto = bp->b_doto; XX wp->w_markp = NULL; XX wp->w_marko = 0; XX XX /* build the contents of this window, inserting it line by line */ XX nptr = &names[0]; XX while (nptr->n_func != NULL) { XX XX /* add in the command name */ XX strcpy(outseq, nptr->n_name); XX cpos = strlen(outseq); XX XX /* search down any keys bound to this */ XX ktp = &keytab[0]; XX while (ktp->k_fp != NULL) { XX if (ktp->k_fp == nptr->n_func) { XX /* padd out some spaces */ XX while (cpos < 25) outseq[cpos++] = ' '; XX XX /* add in the command sequence */ XX cmdstr(ktp->k_code, &outseq[cpos]); XX while (outseq[cpos] != 0) ++cpos; XX XX /* and add it as a line into the buffer */ XX strp = &outseq[0]; XX while (*strp != 0) linsert(1, *strp++); XX lnewline(); XX XX cpos = 0; /* and clear the line */ XX } XX ++ktp; XX } XX XX /* if no key was bound, we need to dump it anyway */ XX if (cpos > 0) { XX outseq[cpos] = 0; XX strp = &outseq[0]; XX while (*strp != 0) linsert(1, *strp++); XX lnewline(); XX } XX XX /* and on to the next name */ XX ++nptr; XX } XX XX curwp->w_bufp->b_mode |= MDVIEW;/* put this buffer view mode */ XX curbp->b_flag &= ~BFCHG; /* don't flag this as a change */ XX wp->w_dotp = lforw(bp->b_linep);/* back to the begining */ XX wp->w_doto = 0; XX wp = wheadp; /* and update ALL mode lines */ XX while (wp != NULL) { XX wp->w_flag |= WFMODE; XX wp = wp->w_wndp; XX } XX mlwrite(""); /* clear the mode line */ XX return(TRUE); XX } XX XXgetckey() /* get a command key sequence from the keyboard */ XX XX { XX register int c; /* character fetched */ XX register char *tp; /* pointer into the token */ XX char tok[NSTRING]; /* command incoming */ XX XX /* check to see if we are executing a command line */ XX if (clexec) { XX nxtarg(tok); /* get the next token */ XX XX /* parse it up */ XX tp = &tok[0]; XX c = 0; XX XX /* first the GOLD prefix */ XX if (*tp == 'G' && *(tp+1) == '-') { XX c |= GOLD; XX tp += 2; XX } XX XX /* next the function prefix */ XX if (*tp == 'K' && *(tp+1) == '-') { XX c |= SPEC; XX tp += 2; XX } XX XX /* next the META prefix */ XX if (*tp == 'M' && *(tp+1) == '-') { XX c = META; XX tp += 2; XX } XX XX /* control-x as well... */ XX if (*tp == '^' && *(tp+1) == 'X') { XX c |= CTLX; XX tp += 2; XX } XX XX /* a control char? */ XX if (*tp == '^' & *(tp+1) != 0) { XX c |= CTRL; XX ++tp; XX } XX XX /* make sure we are not lower case */ XX if (c >= 'a' && c <= 'z') c -= 32; XX XX /* the final sequence... */ XX c |= *tp; XX XX return(c); XX } XX XX /* or the normal way */ XX c = getkey(); /* get a command sequence */ XX if (c == (CTRL|'X')) /* get control-x sequence */ XX c = CTLX | getctl(); XX return(c); XX } XX XX SHAR_EOF if test 12210 -ne "`wc -c bind.c`" then echo shar: error transmitting bind.c '(should have been 12210 characters)' fi echo shar: extracting buffer.c sed 's/^XX//' << \SHAR_EOF > buffer.c XX/* XX * Buffer management. XX * Some of the functions are internal, XX * and some are actually attached to user XX * keys. Like everyone else, they set hints XX XX * for the display system. XX */ XX#include XX#include "estruct.h" XX#include "edef.h" XX XX/* XX * Attach a buffer to a window. The XX * values of dot and mark come from the buffer XX * if the use count is 0. Otherwise, they come XX * from some other window. XX */ XXusebuffer(f, n) XX { XX register BUFFER *bp; XX register int s; XX char bufn[NBUFN]; XX XX if ((s=mlreply("Use buffer: ", bufn, NBUFN)) != TRUE) return (s); XX if ((bp=bfind(bufn, TRUE, 0)) == NULL) return (FALSE); XX return(swbuffer(bp)); XX } XX XXswbuffer(bp) /* make buffer BP current */ XX XXBUFFER *bp; XX XX { XX register WINDOW *wp; XX XX if (--curbp->b_nwnd == 0) { /* Last use. */ XX curbp->b_dotp = curwp->w_dotp; XX curbp->b_doto = curwp->w_doto; XX curbp->b_markp = curwp->w_markp; XX curbp->b_marko = curwp->w_marko; XX } XX curbp = bp; /* Switch. */ XX if (curbp->b_active != TRUE) { /* buffer not active yet*/ XX /* read it in and activate it */ XX readin(curbp->b_fname, TRUE); XX curbp->b_dotp = lforw(curbp->b_linep); XX curbp->b_doto = 0; XX curbp->b_active = TRUE; XX } XX curwp->w_bufp = bp; XX curwp->w_linep = bp->b_linep; /* For macros, ignored. */ XX curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty. */ XX if (bp->b_nwnd++ == 0) { /* First use. */ XX curwp->w_dotp = bp->b_dotp; XX curwp->w_doto = bp->b_doto; XX curwp->w_markp = bp->b_markp; XX curwp->w_marko = bp->b_marko; XX return (TRUE); XX } XX wp = wheadp; /* Look for old. */ XX while (wp != NULL) { XX if (wp!=curwp && wp->w_bufp==bp) { XX curwp->w_dotp = wp->w_dotp; XX curwp->w_doto = wp->w_doto; XX curwp->w_markp = wp->w_markp; XX curwp->w_marko = wp->w_marko; XX break; XX } XX wp = wp->w_wndp; XX } XX return (TRUE); XX } XX XX/* XX * Dispose of a buffer, by name. XX * Ask for the name. Look it up (don't get too XX * upset if it isn't there at all!). Get quite upset XX * if the buffer is being displayed. Clear the buffer (ask XX * if the buffer has been changed). Then free the header XX * line and the buffer header. Bound to "C-X K". XX */ XXkillbuffer(f, n) XX XX { XX register BUFFER *bp; XX register int s; XX char bufn[NBUFN]; XX XX if ((s=mlreply("Kill buffer: ", bufn, NBUFN)) != TRUE) return(s); XX if ((bp=bfind(bufn, FALSE, 0)) == NULL) /* Easy if unknown. */ XX return (TRUE); XX return(zotbuf(bp)); XX } XX XXzotbuf(bp) /* kill the buffer pointed to by bp */ XX XXregister BUFFER *bp; XX XX { XX register BUFFER *bp1; XX register BUFFER *bp2; XX register int s; XX XX if (bp->b_nwnd != 0) { /* Error if on screen. */ XX mlwrite("Buffer is being displayed"); XX return (FALSE); XX } XX XX#if ULTRIX XX if (bp == procbuf) { XX kill(pid,9); /* kill the sub process */ XX inchannel = outchannel = pid = 0; XX procbuf = NULL; XX } XX#endif XX XX if ((s=bclear(bp)) != TRUE) /* Blow text away. */ XX return (s); XX free((char *) bp->b_linep); /* Release header line. */ XX bp1 = NULL; /* Find the header. */ XX bp2 = bheadp; XX while (bp2 != bp) { XX bp1 = bp2; XX bp2 = bp2->b_bufp; XX } XX bp2 = bp2->b_bufp; /* Next one in chain. */ XX if (bp1 == NULL) /* Unlink it. */ XX bheadp = bp2; XX else XX bp1->b_bufp = bp2; XX free((char *) bp); /* Release buffer block */ XX return (TRUE); XX } XX XXnamebuffer(f,n) /* Rename the current buffer */ XX XXint f, n; /* default Flag & Numeric arg */ XX XX { XX register BUFFER *bp; /* pointer to scan through all buffers */ XX char bufn[NBUFN]; /* buffer to hold buffer name */ XX XX /* prompt for and get the new buffer name */ XX ask: if (mlreply("Change buffer name to: ", bufn, NBUFN) != TRUE) XX return(FALSE); XX XX /* and check for duplicates */ XX bp = bheadp; XX while (bp != NULL) { XX if (bp != curbp) { XX /* if the names the same */ XX if (strcmp(bufn, bp->b_bname) == 0) goto ask; /* try again */ XX } XX bp = bp->b_bufp; /* onward */ XX } XX XX strcpy(curbp->b_bname, bufn); /* copy buffer name to structure */ XX curwp->w_flag |= WFMODE; /* make mode line replot */ XX mlerase(); XX } XX XX/* XX * List all of the active XX * buffers. First update the special XX * buffer that holds the list. Next make XX * sure at least 1 window is displaying the XX * buffer list, splitting the screen if this XX * is what it takes. Lastly, repaint all of XX * the windows that are displaying the XX * list. Bound to "C-X C-B". XX XX */ XXlistbuffers(f, n) XX { XX register WINDOW *wp; XX register BUFFER *bp; XX register int s; XX XX if ((s=makelist()) != TRUE) return (s); XX if (blistp->b_nwnd == 0) { /* Not on screen yet. */ XX if ((wp=wpopup()) == NULL) XX return (FALSE); XX bp = wp->w_bufp; XX if (--bp->b_nwnd == 0) { XX bp->b_dotp = wp->w_dotp; XX bp->b_doto = wp->w_doto; XX bp->b_markp = wp->w_markp; XX bp->b_marko = wp->w_marko; XX } XX wp->w_bufp = blistp; XX ++blistp->b_nwnd; XX } XX wp = wheadp; XX while (wp != NULL) { XX if (wp->w_bufp == blistp) { XX wp->w_linep = lforw(blistp->b_linep); XX wp->w_dotp = lforw(blistp->b_linep); XX wp->w_doto = 0; XX wp->w_markp = NULL; XX wp->w_marko = 0; XX wp->w_flag |= WFMODE|WFHARD; XX } XX wp = wp->w_wndp; XX } XX return (TRUE); XX } XX XX/* XX * This routine rebuilds the XX * text in the special secret buffer XX * that holds the buffer list. It is called XX * by the list buffers command. Return TRUE XX * if everything works. Return FALSE if there XX * is an error (if there is no memory). XX */ XXmakelist() XX { XX register char *cp1; XX register char *cp2; XX register int c; XX register BUFFER *bp; XX register LINE *lp; XX register int nbytes; XX register int s; XX register int i; XX register int type; XX char b[6+1]; XX char line[128]; XX XX blistp->b_flag &= ~BFCHG; /* Don't complain! */ XX if ((s=bclear(blistp)) != TRUE) /* Blow old text away */ XX return (s); XX strcpy(blistp->b_fname, ""); XX if (addline("AC MODES Size Buffer File") == FALSE || XX addline("-- ------ ---- ------ ----") == FALSE) XX return (FALSE); XX bp = bheadp; /* For all buffers */ XX while (bp != NULL) { XX if ((bp->b_flag&BFTEMP) != 0) { /* Skip magic ones. */ XX bp = bp->b_bufp; XX continue; XX } XX cp1 = &line[0]; /* Start at left edge */ XX XX /* output status of ACTIVE flag (has the file been read in? */ XX if (bp->b_active == TRUE) /* "@" if activated */ XX *cp1++ = '@'; XX else XX *cp1++ = ' '; XX XX /* output status of changed flag */ XX if ((bp->b_flag&BFCHG) != 0) /* "*" if changed */ XX *cp1++ = '*'; XX else XX *cp1++ = ' '; XX *cp1++ = ' '; /* Gap. */ XX XX /* output the mode codes */ XX for (i = 0; i < NUMMODES; i++) { XX if (bp->b_mode & (1 << i)) *cp1++ = modecode[i]; XX else XX *cp1++ = '.'; XX } XX *cp1++ = ' '; /* Gap. */ XX nbytes = 0; /* Count bytes in buf. */ XX lp = lforw(bp->b_linep); XX while (lp != bp->b_linep) { XX nbytes += llength(lp)+1; XX lp = lforw(lp); XX } XX itoa(b, 6, nbytes); /* 6 digit buffer size. */ XX cp2 = &b[0]; XX while ((c = *cp2++) != 0) *cp1++ = c; XX *cp1++ = ' '; /* Gap. */ XX cp2 = &bp->b_bname[0]; /* Buffer name */ XX while ((c = *cp2++) != 0) *cp1++ = c; XX cp2 = &bp->b_fname[0]; /* File name */ XX if (*cp2 != 0) { XX while (cp1 < &line[2+1+5+1+6+1+NBUFN]) *cp1++ = ' '; XX while ((c = *cp2++) != 0) { XX if (cp1 < &line[128-1]) *cp1++ = c; XX } XX } XX *cp1 = 0; /* Add to the buffer. */ XX if (addline(line) == FALSE) return (FALSE); XX bp = bp->b_bufp; XX } XX return (TRUE); /* All done */ XX } XX XXitoa(buf, width, num) XXregister char buf[]; XXregister int width; XXregister int num; XX { XX buf[width] = 0; /* End of string. */ XX while (num >= 10) { /* Conditional digits. */ XX buf[--width] = (num%10) + '0'; XX num /= 10; XX } XX buf[--width] = num + '0'; /* Always 1 digit. */ XX while (width != 0) /* Pad with blanks. */ XX buf[--width] = ' '; XX } XX XX/* XX * The argument "text" points to XX * a string. Append this line to the XX * buffer list buffer. Handcraft the EOL XX * on the end. Return TRUE if it worked and XX * FALSE if you ran out of room. XX */ XXaddline(text) XXchar *text; XX { XX register LINE *lp; XX register int i; XX register int ntext; XX XX ntext = strlen(text); XX if ((lp=lalloc(ntext)) == NULL) return (FALSE); XX for (i=0; ib_linep->l_bp->l_fp = lp; /* Hook onto the end */ XX lp->l_bp = blistp->b_linep->l_bp; XX blistp->b_linep->l_bp = lp; XX lp->l_fp = blistp->b_linep; XX if (blistp->b_dotp == blistp->b_linep) /* If "." is at the end */ XX blistp->b_dotp = lp; /* move it to new line */ XX return (TRUE); XX } XX XX/* XX * Look through the list of XX * buffers. Return TRUE if there XX * are any changed buffers. Buffers XX * that hold magic internal stuff are XX * not considered; who cares if the XX * list of buffer names is hacked. XX * Return FALSE if no buffers XX * have been changed. XX */ XXanycb() XX { XX register BUFFER *bp; XX XX bp = bheadp; XX while (bp != NULL) { XX if ( bp != procbuf && XX (bp->b_flag&BFTEMP) == 0 && XX (bp->b_flag&BFCHG) !=0 ) return (TRUE); XX bp = bp->b_bufp; XX } XX return (FALSE); XX } XX XX/* XX * Find a buffer, by name. Return a pointer XX * to the BUFFER structure associated with it. If XX * the named buffer is found, but is a TEMP buffer (like XX * the buffer list) complain. If the buffer is not found XX * and the "cflag" is TRUE, create it. The "bflag" is XX * the settings for the flags in the buffer. XX */ XXBUFFER * XXbfind(bname, cflag, bflag) XXregister char *bname; XX { XX register BUFFER *bp; XX register BUFFER *sb; /* buffer to insert after */ XX register LINE *lp; XX char *malloc(); XX XX bp = bheadp; XX while (bp != NULL) { XX if (strcmp(bname, bp->b_bname) == 0) { XX if ((bp->b_flag&BFTEMP) != 0) { XX mlwrite("Cannot select builtin buffer"); XX return (NULL); XX } XX return (bp); XX } XX bp = bp->b_bufp; XX } XX if (cflag != FALSE) { XX if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL) return (NULL); XX if ((lp=lalloc(0)) == NULL) { XX free((char *) bp); XX return (NULL); XX } XX /* find the place in the list to insert this buffer */ XX if (bheadp == NULL || strcmp(bheadp->b_bname, bname) > 0) { XX /* insert at the begining */ XX bp->b_bufp = bheadp; XX bheadp = bp; XX } XX else { XX sb = bheadp; XX while (sb->b_bufp != NULL) { XX if (strcmp(sb->b_bufp->b_bname, bname) > 0) break; XX sb = sb->b_bufp; XX } XX XX /* and insert it */ XX bp->b_bufp = sb->b_bufp; XX XX sb->b_bufp = bp; XX } XX XX /* and set up the other buffer fields */ XX bp->b_active = TRUE; XX bp->b_dotp = lp; XX bp->b_doto = 0; XX bp->b_markp = NULL; XX bp->b_marko = 0; XX bp->b_flag = bflag; XX bp->b_mode = 0; XX bp->b_nwnd = 0; XX bp->b_linep = lp; XX strcpy(bp->b_fname, ""); XX strcpy(bp->b_bname, bname); XX lp->l_fp = lp; XX lp->l_bp = lp; XX } XX return (bp); XX } XX XX/* XX * This routine blows away all of the text XX * in a buffer. If the buffer is marked as changed XX * then we ask if it is ok to blow it away; this is XX * to save the user the grief of losing text. The XX * window chain is nearly always wrong if this gets XX * called; the caller must arrange for the updates XX * that are required. Return TRUE if everything XX * looks good. XX */ XXbclear(bp) XXregister BUFFER *bp; XX { XX register LINE *lp; XX register int s; XX XX if ((bp->b_flag&BFTEMP) == 0 /* Not scratch buffer. */ XX && (bp->b_flag&BFCHG) != 0 /* Something changed */ XX && (s=mlyesno("Discard changes")) != TRUE) XX return (s); XX bp->b_flag &= ~BFCHG; /* Not changed */ XX while ((lp=lforw(bp->b_linep)) != bp->b_linep) lfree(lp); XX bp->b_dotp = bp->b_linep; /* Fix "." */ XX bp->b_doto = 0; XX bp->b_markp = NULL; /* Invalidate "mark" */ XX bp->b_marko = 0; XX return (TRUE); XX } XX XX SHAR_EOF if test 12143 -ne "`wc -c buffer.c`" then echo shar: error transmitting buffer.c '(should have been 12143 characters)' fi echo shar: extracting display.c sed 's/^XX//' << \SHAR_EOF > display.c XX/* XX * The functions in this file handle redisplay. There are two halves, the XX * ones that update the virtual display screen, and the ones that make the XX * physical display screen the same as the virtual display screen. These XX * functions use hints that are left in the windows by the commands. XX * XX */ XX XX#include XX#include "estruct.h" XX#include "edef.h" XX XX#define WFDEBUG 0 /* Window flag debug. */ XXtypedef struct VIDEO { XX short v_flag; /* Flags */ XX char v_text[1]; /* Screen data. */ XX } XXVIDEO; XX XX#define VFCHG 0x0001 /* Changed. */ XX#define VFEXT 0x0002 /* extended (beyond column 80) */ XX#define VFMOD 0x0004 /* change in mode line occurred*/ XX XXint vtrow = 0; /* Row location of SW cursor */ XXint vtcol = 0; /* Column location of SW cursor */ XXint ttrow = HUGE; /* Row location of HW cursor */ XXint ttcol = HUGE; /* Column location of HW cursor */ XXint lbound = 0; /* leftmost column of current line XXbeing displayed */ XX XXVIDEO **vscreen; /* Virtual screen. */ XXVIDEO **pscreen; /* Physical screen. */ XX XX/* XX * Initialize the data structures used by the display code. The edge vectors XX * used to access the screens are set up. The operating system's terminal I/O XX * channel is set up. All the other things get initialized at compile time. XX * The original window has "WFCHG" set, so that it will get completely XX * redrawn on the first call to "update". XX */ XX XXvtinit() XX { XX register int i; XX register VIDEO *vp; XX char *malloc(); XX XX (*term.t_open)(); XX vscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *)); XX XX if (vscreen == NULL) exit(1); XX XX pscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *)); XX XX if (pscreen == NULL) exit(1); XX XX for (i = 0; i < term.t_nrow; ++i) { XX vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol); XX XX if (vp == NULL) exit(1); XX XX vp->v_flag = 0; XX vscreen[i] = vp; XX vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol); XX XX if (vp == NULL) exit(1); XX XX vp->v_flag = 0; XX pscreen[i] = vp; XX } XX } XX XX/* XX * Clean up the virtual terminal system, in anticipation for a return to the XX * operating system. Move down to the last line and clear it out (the next XX * system prompt will be written in the line). Shut down the channel to the XX * terminal. XX */ XXvttidy() XX { XX mlerase(); XX movecursor(term.t_nrow, 0); XX (*term.t_close)(); XX } XX XX/* XX * Set the virtual cursor to the specified row and column on the virtual XX * screen. There is no checking for nonsense values; this might be a good XX * idea during the early stages. XX */ XXvtmove(row, col) XX { XX vtrow = row; XX vtcol = col; XX } XX XX/* XX * Write a character to the virtual screen. The virtual row and column are XX * updated. If the line is too long put a "$" in the last column. This routine XX * only puts printing characters into the virtual terminal buffers. Only XX * column overflow is checked. XX */ XXvtputc(c) XXint c; XX { XX register VIDEO *vp; XX XX vp = vscreen[vtrow]; XX XX if (vtcol >= term.t_ncol) vp->v_text[term.t_ncol - 1] = '$'; XX else if (c == '\t') XX { XX do XX { XX vtputc(' '); XX } XX while ((vtcol&0x07) != 0 && vtcol < term.t_ncol); XX } XX else if (c < 0x20 || c == 0x7F) XX { XX vtputc('^'); XX vtputc(c ^ 0x40); XX } XX else XX vp->v_text[vtcol++] = c; XX } XX XX/* put a character to the virtual screen in an extended line. If we are XXnot yet on left edge, don't print it yet. check for overflow on XXthe right margin */ XX XXvtpute(c) XX XXint c; XX XX { XX register VIDEO *vp; XX XX vp = vscreen[vtrow]; XX XX if (vtcol >= term.t_ncol) vp->v_text[term.t_ncol - 1] = '$'; XX else if (c == '\t') XX { XX do XX { XX vtpute(' '); XX } XX while (((vtcol + lbound)&0x07) != 0 && vtcol < term.t_ncol); XX } XX else if (c < 0x20 || c == 0x7F) XX { XX vtpute('^'); XX vtpute(c ^ 0x40); XX } XX else { XX if (vtcol >= 0) vp->v_text[vtcol] = c; XX ++vtcol; XX } XX } XX XX/* XX * Erase from the end of the software cursor to the end of the line on which XX * the software cursor is located. XX */ XXvteeol() XX { XX register VIDEO *vp; XX XX vp = vscreen[vtrow]; XX while (vtcol < term.t_ncol) vp->v_text[vtcol++] = ' '; XX } XX XX/* XX * Make sure that the display is right. This is a three part process. First, XX * scan through all of the windows looking for dirty ones. Check the framing, XX * and refresh the screen. Second, make sure that "currow" and "curcol" are XX * correct for the current window. Third, make the virtual and physical XX * screens the same. XX */ XXupdate() XX { XX register LINE *lp; XX register WINDOW *wp; XX register VIDEO *vp1; XX register VIDEO *vp2; XX register int i,j,k; XX register int c; XX int row_p,row_v,n,tryblock; XX XX#ifdef TYPEAH XX if (typahead()) return; XX#endif XX tryblock = 0; XX wp = wheadp; XX XX while (wp != NULL) { XX /* Look at any window with update flags set on. */ XX XX if (wp->w_flag != 0) { XX /* If not force reframe, check the framing. */ XX XX if ((wp->w_flag & WFFORCE) == 0) { XX lp = wp->w_linep; XX XX for (i = 0; i < wp->w_ntrows; ++i) { XX if (lp == wp->w_dotp) goto out; XX XX if (lp == wp->w_bufp->b_linep) break; XX XX lp = lforw(lp); XX } XX } XX XX /* Not acceptable, better compute a new value for the line at the XX * top of the window. Then set the "WFHARD" flag to force full XX * redraw. XX */ XX i = wp->w_force; XX XX if (i > 0) { XX --i; XX if (i >= wp->w_ntrows) i = wp->w_ntrows-1; XX } XX else if (i < 0) XX { XX i += wp->w_ntrows; XX XX if (i < 0) i = 0; XX } XX else XX i = wp->w_ntrows/2; XX XX lp = wp->w_dotp; XX XX while (i != 0 && lback(lp) != wp->w_bufp->b_linep) { XX --i; XX lp = lback(lp); XX } XX XX wp->w_linep = lp; XX wp->w_flag |= WFHARD; /* Force full. */ XX XX out: XX /* Try to use reduced update. Mode line update has its own special XX * flag. The fast update is used if the only thing to do is within XX * the line editing. */ XX lp = wp->w_linep; XX i = wp->w_toprow; XX XX if ((wp->w_flag & ~WFMODE) == WFEDIT) { XX while (lp != wp->w_dotp) { XX ++i; XX lp = lforw(lp); XX } XX XX vscreen[i]->v_flag |= VFCHG; XX vtmove(i, 0); XX XX for (j = 0; j < llength(lp); ++j) vtputc(lgetc(lp, j)); XX XX vteeol(); XX } XX else if ((wp->w_flag & (WFEDIT | WFHARD)) != 0) XX { XX tryblock = 1; XX while (i < wp->w_toprow+wp->w_ntrows) { XX vscreen[i]->v_flag |= VFCHG; XX vtmove(i, 0); XX XX /* if line has been changed */ XX if (lp != wp->w_bufp->b_linep) { XX for (j = 0; j < llength(lp); ++j) vtputc(lgetc(lp, j)); XX lp = lforw(lp); XX } XX vteeol(); XX ++i; XX } XX } XX#if ~WFDEBUG XX if ((wp->w_flag&WFMODE) != 0) modeline(wp); XX XX wp->w_flag = 0; XX wp->w_force = 0; XX#endif XX } XX#if WFDEBUG XX modeline(wp); XX wp->w_flag = 0; XX wp->w_force = 0; XX#endif XX XX /* and onward to the next window */ XX wp = wp->w_wndp; XX } XX XX /* Always recompute the row and column number of the hardware cursor. This XX * is the only update for simple moves. XX */ XX lp = curwp->w_linep; XX currow = curwp->w_toprow; XX XX while (lp != curwp->w_dotp) { XX ++currow; XX lp = lforw(lp); XX } XX XX curcol = 0; XX i = 0; XX XX while (i < curwp->w_doto) { XX c = lgetc(lp, i++); XX XX if (c == '\t') curcol |= 0x07; XX else if (c < 0x20 || c == 0x7F) XX ++curcol; XX XX ++curcol; XX } XX XX if (curcol >= term.t_ncol - 1) { /* extended line. */ XX /* flag we are extended and changed */ XX vscreen[currow]->v_flag |= VFEXT | VFCHG; XX updext(); /* and output extended line */ XX } XX else XX lbound = 0; /* not extended line */ XX XX /* make sure no lines need to be de-extended because the cursor is XX no longer on them */ XX XX wp = wheadp; XX XX while (wp != NULL) { XX lp = wp->w_linep; XX i = wp->w_toprow; XX XX while (i < wp->w_toprow + wp->w_ntrows) { XX if (vscreen[i]->v_flag & VFEXT) { XX /* always flag extended lines as changed */ XX vscreen[i]->v_flag |= VFCHG; XX if ((wp != curwp) || (lp != wp->w_dotp) || (curcol < term.t_ncol - 1)) { XX vtmove(i, 0); XX for (j = 0; j < llength(lp); ++j) vtputc(lgetc(lp, j)); XX vteeol(); XX XX /* this line no longer is extended */ XX vscreen[i]->v_flag &= ~VFEXT; XX } XX } XX lp = lforw(lp); XX ++i; XX } XX /* if garbaged then fix up mode lines */ XX if (sgarbf != FALSE) vscreen[i]->v_flag |= VFMOD|VFCHG; XX XX /* and onward to the next window */ XX wp = wp->w_wndp; XX } XX XX /* Special hacking if the screen is garbage. Clear the hardware screen, XX * and update your copy to agree with it. Set all the virtual screen XX * change bits, to force a full update. XX */ XX if (sgarbf != FALSE) { XX for (i = 0; i < term.t_nrow; ++i) { XX vscreen[i]->v_flag |= VFCHG; XX vp1 = pscreen[i]; XX for (j = 0; j < term.t_ncol; ++j) vp1->v_text[j] = ' '; XX } XX XX (*term.t_putchar)('\033'); /* as good a place as any to force */ XX (*term.t_putchar)('='); /* application mode on the terminal */ XX XX movecursor(0, 0); /* Erase the screen. */ XX (*term.t_eeop)(); XX sgarbf = FALSE; XX mpresf = FALSE; /* the message area. */ XX tryblock = 0; XX } XX XX /* If we're going to try a block transfer, make sure at least 1/4 XX * of the lines DON'T agree XX */ XX if (tryblock) { XX n = 0; XX j = term.t_ncol >> 2; XX k = term.t_ncol >> 1; XX for (i = 0; i < term.t_nrow; i++) { XX vp1 = vscreen[i]; XX vp2 = pscreen[i]; XX if (vp1->v_text[0] != vp2->v_text[0] || XX vp1->v_text[j] != vp2->v_text[j] || XX vp1->v_text[k] != vp2->v_text[k]) n++; XX } XX if (n <= (term.t_nrow >> 2)) tryblock = 0; XX } XX XX /* First see if we can do a massive "block move" of data... */ XX if (tryblock) { XX row_p = row_v = n = -1; XX for (i = currow >= 4 ? currow - 4 : 0; XX i <= currow+4 && i <= term.t_nrow-4; i++) { XX for (j = 0; j < term.t_nrow; j++) { XX for (k = 0; k < term.t_nrow-i && k < term.t_nrow-j; k++) { XX vp1 = pscreen[i+k]; XX vp2 = vscreen[j+k]; XX if (strncmp(vp1->v_text,vp2->v_text,term.t_ncol) XX != 0) break; XX } XX if (k > n) { XX n = k; XX row_p = i; XX row_v = j; XX } XX } XX } XX XX /* Make sure we got at least 1/4 lines to shift and XX at most 1/4 of the screen to redo */ XX if (row_p != row_v && n >= (term.t_nrow >> 2) && XX (term.t_nrow-row_v)-n <= (term.t_nrow >> 2)) { XX if (row_p < row_v) { XX (*term.t_insert)(row_p,(row_v-row_p)); XX j = (term.t_nrow-1) - (row_v-row_p); XX for (i=term.t_nrow-1; i >= row_v; i--) { XX vscreen[i]->v_flag |= VFCHG; XX vp1 = pscreen[j--]; XX vp2 = pscreen[i]; XX strncpy(vp2->v_text,vp1->v_text,term.t_ncol); XX } XX for (i=row_p; i < row_v; i++) { XX vscreen[i]->v_flag |= VFCHG; XX vp1 = pscreen[i]; XX for(j=0; j < term.t_ncol; j++) vp1->v_text[j] = ' '; XX } XX } XX else { XX (*term.t_delete)(row_v,(row_p-row_v)); XX j = row_v; XX for (i=row_p; i < term.t_nrow; i++) { XX vscreen[j]->v_flag |= VFCHG; XX vp1 = pscreen[j++]; XX vp2 = pscreen[i]; XX strncpy(vp1->v_text,vp2->v_text,term.t_ncol); XX } XX for (i=j; i < term.t_nrow; i++) { XX vscreen[i]->v_flag |= VFCHG; XX vp1 = pscreen[i]; XX for(j=0; j < term.t_ncol; j++) vp1->v_text[j] = ' '; XX } XX } XX wp = wheadp; XX while (wp != NULL) { XX i = wp->w_toprow+wp->w_ntrows; XX if (i >= row_p || i >= row_v) XX vscreen[i]->v_flag |= VFMOD|VFCHG; XX wp = wp->w_wndp; XX } XX } XX else tryblock = 0; XX } XX XX /* Make sure that the physical and virtual displays agree. Unlike before, XX * the "updateline" code is only called with a line that has been updated XX * for sure. XX */ XX for (i = 0; i < term.t_nrow; ++i) { XX vp1 = vscreen[i]; XX XX if ((vp1->v_flag&VFCHG) != 0) { XX#ifdef TYPEAH XX if (!tryblock && typahead()) return; XX#endif XX vp1->v_flag &= ~VFCHG; XX vp2 = pscreen[i]; XX XX if ((vp1->v_flag&VFMOD) != 0) { XX updateline(i, &vp1->v_text[0], &vp2->v_text[0],1); XX vp1->v_flag &= ~VFMOD; XX } XX else updateline(i, &vp1->v_text[0], &vp2->v_text[0],0); XX XX } XX } XX XX /* Finally, update the hardware cursor and flush out buffers. */ XX movecursor(currow, curcol - lbound); XX (*term.t_flush)(); XX } XX XX/* updext: update the extended line which the cursor is currently XXon at a column greater than the terminal width. The line XXwill be scrolled right or left to let the user see where XXthe cursor is XX */ XX XXupdext() XX XX { XX register int rcursor; /* real cursor location */ XX register LINE *lp; /* pointer to current line */ XX register int j; /* index into line */ XX XX /* calculate what column the real cursor will end up in */ XX rcursor = ((curcol - term.t_ncol) % term.t_scrsiz) + term.t_margin; XX lbound = curcol - rcursor + 1; XX XX /* scan through the line outputing characters to the virtual screen */ XX /* once we reach the left edge */ XX vtmove(currow, -lbound); /* start scanning offscreen */ XX lp = curwp->w_dotp; /* line to output */ XX for (j=0; jv_text[0] = '$'; XX } XX XX/* XX * Update a single line. This does not know how to use insert or delete XX * character sequences; we are using VT52 functionality. Update the physical XX * row and column variables. It does try an exploit erase to end of line. The XX * RAINBOW version of this routine uses fast video. XX */ XXupdateline(row, vline, pline, ismode) XXchar vline[]; XXchar pline[]; XX { XX register char *cp1; XX register char *cp2; XX register char *cp3; XX register char *cp4; XX register char *cp5; XX register int nbflag; XX XX cp1 = &vline[0]; /* Compute left match. */ XX cp2 = &pline[0]; XX XX while (cp1!=&vline[term.t_ncol] && cp1[0]==cp2[0]) { XX ++cp1; XX ++cp2; XX } XX XX /* This can still happen, even though we only call this routine on changed XX * lines. A hard update is always done when a line splits, a massive XX * change is done, or a buffer is displayed twice. This optimizes out most XX * of the excess updating. A lot of computes are used, but these tend to XX * be hard operations that do a lot of update, so I don't really care. XX */ XX if (cp1 == &vline[term.t_ncol]) /* All equal. */ XX return; XX XX nbflag = FALSE; XX cp3 = &vline[term.t_ncol]; /* Compute right match. */ XX cp4 = &pline[term.t_ncol]; XX XX while (cp3[-1] == cp4[-1]) { XX --cp3; XX --cp4; XX if (cp3[0] != ' ') /* Note if any nonblank */ XX nbflag = TRUE; /* in right match. */ XX } XX XX cp5 = cp3; XX XX if (nbflag == FALSE && eolexist == TRUE) /* Erase to EOL ? */ XX { XX while (cp5!=cp1 && cp5[-1]==' ') --cp5; XX XX if (cp3-cp5 <= 3) /* Use only if erase is */ XX cp5 = cp3; /* fewer characters. */ XX } XX XX movecursor(row, cp1-&vline[0]); /* Go to start of line. */ XX XX if (ismode) { XX (*term.t_putchar)('\033'); XX (*term.t_putchar)('['); XX (*term.t_putchar)('7'); XX (*term.t_putchar)('m'); XX } XX XX while (cp1 != cp5) /* Ordinary. */ XX { XX (*term.t_putchar)(*cp1); XX ++ttcol; XX *cp2++ = *cp1++; XX } XX XX if (cp5 != cp3) /* Erase. */ XX { XX (*term.t_eeol)(); XX while (cp1 != cp3) *cp2++ = *cp1++; XX } XX XX if (ismode) { XX (*term.t_putchar)('\033'); XX (*term.t_putchar)('['); XX (*term.t_putchar)('0'); XX (*term.t_putchar)('m'); XX } XX XX } XX XX/* XX * Redisplay the mode line for the window pointed to by the "wp". This is the XX * only routine that has any idea of how the modeline is formatted. You can XX * change the modeline format by hacking at this routine. Called by "update" XX * any time there is a dirty window. Also fixes up tabbing. XX */ XXmodeline(wp) XXWINDOW *wp; XX { XX register char *cp; XX register int c; XX register int n; /* cursor position count */ XX register BUFFER *bp; XX register i; /* loop index */ XX register lchar; /* character to draw line in buffer with */ XX register firstm; /* is this the first mode? */ XX char tline[NLINE]; /* buffer for part of mode line */ XX XX XX n = wp->w_toprow+wp->w_ntrows; /* Location. */ XX XX vscreen[n]->v_flag |= VFCHG|VFMOD; /* Redraw next time. */ XX XX vtmove(n, 0); /* Seek to right line. */ XX bp = wp->w_bufp; XX if (wp == curwp) { /* mark the current buffer */ XX lchar = '='; XX if ((bp->b_mode & (MDCMOD|MDMMOD)) != 0) tab(FALSE,4); XX else if ((bp->b_mode & MDLISP) != 0) tab(FALSE,2); XX else tab(FALSE,0); XX } XX else XX lchar = '-'; XX XX vtputc(lchar); XX XX if ((bp->b_flag&BFCHG) != 0) /* "*" if changed. */ XX vtputc('*'); XX else vtputc(' '); XX XX n = 2; XX XX strcpy(tline, " uEMACS ("); /* Buffer name. */ XX XX /* display the modes */ XX XX firstm = TRUE; XX for (i = 0; i < NUMMODES; i++) /* add in the mode flags */ XX if (wp->w_bufp->b_mode & (1 << i)) { XX if (firstm != TRUE) strcat(tline, " "); XX firstm = FALSE; XX strcat(tline, modename[i]); XX } XX strcat(tline,") "); XX XX cp = &tline[0]; XX while ((c = *cp++) != 0) { XX vtputc(c); XX ++n; XX } XX XX vtputc('-'); XX vtputc('-'); XX vtputc(' '); XX n += 3; XX cp = &bp->b_bname[0]; XX XX while ((c = *cp++) != 0) { XX vtputc(c); XX ++n; XX } XX XX vtputc(' '); XX vtputc('-'); XX vtputc('-'); XX n += 3; XX XX if (bp->b_fname[0] != 0) /* File name. */ XX { XX vtputc(' '); XX ++n; XX cp = "File: "; XX XX while ((c = *cp++) != 0) { XX vtputc(c); XX ++n; XX } XX XX cp = &bp->b_fname[0]; XX XX while ((c = *cp++) != 0) { XX vtputc(c); XX ++n; XX } XX XX vtputc(' '); XX ++n; XX } XX XX#if WFDEBUG XX vtputc(lchar); XX vtputc((wp->w_flag&WFMODE)!=0 ? 'M' : lchar); XX vtputc((wp->w_flag&WFHARD)!=0 ? 'H' : lchar); XX vtputc((wp->w_flag&WFEDIT)!=0 ? 'E' : lchar); XX vtputc((wp->w_flag&WFMOVE)!=0 ? 'V' : lchar); XX vtputc((wp->w_flag&WFFORCE)!=0 ? 'F' : lchar); XX n += 6; XX#endif XX XX while (n < term.t_ncol) /* Pad to full width. */ XX { XX vtputc('-'); XX ++n; XX } XX } XX XXupmode() /* update all the mode lines */ XX XX { XX register WINDOW *wp; XX XX wp = wheadp; XX while (wp != NULL) { XX wp->w_flag |= WFMODE; XX wp = wp->w_wndp; XX } XX } XX XX/* XX * Send a command to the terminal to move the hardware cursor to row "row" XX * and column "col". The row and column arguments are origin 0. Optimize out XX * random calls. Update "ttrow" and "ttcol". XX */ XXmovecursor(row, col) XX { XX if (row!=ttrow || col!=ttcol) { XX ttrow = row; XX ttcol = col; XX (*term.t_move)(row, col); XX } XX } XX XX/* XX * Erase the message line. This is a special routine because the message line XX * is not considered to be part of the virtual screen. It always works XX * immediately; the terminal buffer is flushed via a call to the flusher. XX */ XXmlerase() XX { XX int i; XX XX movecursor(term.t_nrow, 0); XX if (eolexist == TRUE) (*term.t_eeol)(); XX else { XX for (i == 0; i < term.t_ncol - 1; i++) (*term.t_putchar)(' '); XX movecursor(term.t_nrow, 1); /* force the move! */ XX movecursor(term.t_nrow, 0); XX } XX (*term.t_flush)(); XX mpresf = FALSE; XX } XX XX/* XX * Ask a yes or no question in the message line. Return either TRUE, FALSE, or XX * ABORT. The ABORT status is returned if the user bumps out of the question XX * with a ^G. Used any time a confirmation is required. XX */ XX XXmlyesno(prompt) XX XXchar *prompt; XX XX { XX register int s; XX int c; /* input character */ XX char buf[NPAT]; /* prompt to user */ XX XX for (;;) { XX /* build and prompt the user */ XX strcpy(buf, prompt); XX strcat(buf, " [y/n]? "); XX mlwrite(buf); XX XX /* get the responce */ XX c = getkey(); XX if (c & CTRL) c -= (CTRL|'@'); XX c &= 0x7F; XX XX if (c == BELL) /* Bail out! */ XX return(ABORT); XX XX XX if (c=='y' || c=='Y') return(TRUE); XX XX if (c=='n' || c=='N') return(FALSE); XX } XX } XX XX/* XX * Write a prompt into the message line, then read back a response. Keep XX * track of the physical position of the cursor. If we are in a keyboard XX * macro throw the prompt away, and return the remembered response. This XX * lets macros run at full speed. The reply is always terminated by a carriage XX * return. Handle erase, kill, and abort keys. XX */ XX XXmlreply(prompt, buf, nbuf) XXchar *prompt; XXchar *buf; XX { XX return(mlreplyt(prompt,buf,nbuf,'\n')); XX } XX XX/* A more generalized prompt/reply function allowing the caller XXto specify the proper terminator. If the terminator is not XXa return ('\n') it will echo as "" XX */ XXmlreplyt(prompt, buf, nbuf, eolchar) XX XXchar *prompt; XXchar *buf; XXchar eolchar; XX XX { XX register int cpos; XX register int i; XX register int c; XX int anytyped; XX XX cpos = 0; XX XX if (kbdmop != NULL) { XX while ((c = *kbdmop++) != '\0') buf[cpos++] = c; XX buf[cpos] = 0; XX if (buf[0] == 0) return(FALSE); XX return(TRUE); XX } XX XX /* check to see if we are executing a command line */ XX if (clexec) { XX nxtarg(buf); XX return(TRUE); XX } XX XX mlwrite(prompt); XX XX anytyped = FALSE; XX for (;;) { XX /* get a character from the user. if it is a , change it XX to a */ XX c = getkey(); XX if (c & CTRL) c -= (CTRL|'@'); XX c &= 0x7F; XX XX if (c == '\r') c = '\n'; XX XX if (c == eolchar) { XX buf[cpos++] = 0; XX XX if (kbdmip != NULL) { XX if (kbdmip+cpos > &kbdm[NKBDM-3]) { XX ctrlg(FALSE, 0); XX (*term.t_flush)(); XX return(ABORT); XX } XX for (i=0; i for */ XX (*term.t_putchar)('<'); XX (*term.t_putchar)('N'); XX (*term.t_putchar)('L'); XX (*term.t_putchar)('>'); XX ttcol += 3; XX } XX ++ttcol; XX anytyped = TRUE; XX (*term.t_flush)(); XX } XX } XX } XX } XX XX/* XX * Write a message into the message line. Keep track of the physical cursor XX * position. A small class of printf like format items is handled. Assumes the XX * stack grows down; this assumption is made by the "++" in the argument scan XX * loop. Set the "message line" flag TRUE. XX */ XX XXmlwrite(fmt, arg) XXchar *fmt; XX { XX register int c; XX register char *ap; XX XX if (eolexist == FALSE) { XX mlerase(); XX (*term.t_flush)(); XX } XX XX movecursor(term.t_nrow, 0); XX ap = (char *) &arg; XX while ((c = *fmt++) != 0) { XX if (c != '%') { XX (*term.t_putchar)(c); XX ++ttcol; XX } XX else XX { XX c = *fmt++; XX switch (c) { XX case 'd': XX mlputi(*(int *)ap, 10); XX ap += sizeof(int); XX break; XX XX case 'o': XX mlputi(*(int *)ap, 8); XX ap += sizeof(int); XX break; XX XX case 'x': XX mlputi(*(int *)ap, 16); XX ap += sizeof(int); XX break; XX XX case 'D': XX mlputli(*(long *)ap, 10); XX ap += sizeof(long); XX break; XX XX case 's': XX mlputs(*(char **)ap); XX ap += sizeof(char *); XX break; XX XX default: XX (*term.t_putchar)(c); XX ++ttcol; XX } XX } XX } XX if (eolexist == TRUE) (*term.t_eeol)(); XX (*term.t_flush)(); XX mpresf = TRUE; XX } XX XX/* XX * Write out a string. Update the physical cursor position. This assumes that XX * the characters in the string all have width "1"; if this is not the case XX * things will get screwed up a little. XX */ XXmlputs(s) XXchar *s; XX { XX register int c; XX XX while ((c = *s++) != 0) { XX (*term.t_putchar)(c); XX ++ttcol; XX } XX } XX XX/* XX * Write out an integer, in the specified radix. Update the physical cursor XX * position. This will not handle any negative numbers; maybe it should. XX */ XXmlputi(i, r) XX { XX register int q; XX static char hexdigits[] = "0123456789ABCDEF"; XX XX if (i < 0) { XX i = -i; XX (*term.t_putchar)('-'); XX } XX XX q = i/r; XX XX if (q != 0) mlputi(q, r); XX XX (*term.t_putchar)(hexdigits[i%r]); XX ++ttcol; XX } XX XX/* XX * do the same except as a long integer. XX */ XXmlputli(l, r) XXlong l; XX { XX register long q; XX XX if (l < 0) { XX l = -l; XX (*term.t_putchar)('-'); XX } XX XX q = l/r; XX XX if (q != 0) mlputli(q, r); XX XX (*term.t_putchar)((int)(l%r)+'0'); XX ++ttcol; XX } XX XX/* get a command name from the command line. Command completion means XXthat pressing a will attempt to complete an unfinished command XXname if it is unique. XX */ XX XXint (*getcname())() XX XX { XX register int cpos; /* current column on screen output */ XX register int i; XX register int c; XX register char *sp; /* pointer to string for output */ XX register NBIND *ffp; /* first ptr to entry in name binding table */ XX register NBIND *cffp; /* current ptr to entry in name binding table */ XX register NBIND *lffp; /* last ptr to entry in name binding table */ XX char buf[NSTRING]; /* buffer to hold tentative command name */ XX int (*fncmatch())(); XX XX /* starting at the begining of the string buffer */ XX cpos = 0; XX XX /* if we are executing a keyboard macro, fill our buffer from there, XX and attempt a straight match */ XX if (kbdmop != NULL && *kbdmop != ' ' && *kbdmop != '\t') { XX while ((c = *kbdmop++) != '\0') buf[cpos++] = c; XX XX buf[cpos] = 0; XX XX /* return the result of a match */ XX return(fncmatch(&buf[0])); XX } XX XX /* if we are executing a command line get the next arg and match it */ XX if (clexec) { XX nxtarg(buf); XX return(fncmatch(&buf[0])); XX } XX XX /* build a name string from the keyboard */ XX while (TRUE) { XX c = getkey(); XX if (c & CTRL) c -= (CTRL|'@'); XX c &= 0x7F; XX XX /* if we are at the end, just match it */ XX if (c == 0x0d) { XX buf[cpos] = 0; XX XX /* save keyboard macro string if needed */ XX if (kbdtext(&buf[0]) == ABORT) return(NULL); XX XX /* and match it off */ XX return(fncmatch(&buf[0])); XX XX } XX else if (c == 0x07) { /* Bell, abort */ XX (*term.t_putchar)('^'); XX (*term.t_putchar)('G'); XX ttcol += 2; XX ctrlg(FALSE, 0); XX (*term.t_flush)(); XX return(NULL); XX XX } XX else if (c == 0x7F || c == 0x08) { /* rubout/erase */ XX if (cpos != 0) { XX (*term.t_putchar)('\b'); XX (*term.t_putchar)(' '); XX (*term.t_putchar)('\b'); XX --ttcol; XX --cpos; XX (*term.t_flush)(); XX } XX XX } XX else if (c == 0x15) { /* C-U, kill */ XX while (cpos != 0) { XX (*term.t_putchar)('\b'); XX (*term.t_putchar)(' '); XX (*term.t_putchar)('\b'); XX --cpos; XX --ttcol; XX } XX XX (*term.t_flush)(); XX XX } XX else if (c == ' ') { XX /* attempt a completion */ XX buf[cpos] = 0; /* terminate it for us */ XX ffp = &names[0]; /* scan for matches */ XX while (ffp->n_func != NULL) { XX if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) { XX /* a possible match! More than one? */ XX if ((ffp + 1)->n_func == NULL || XX (strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) { XX /* no...we match, print it */ XX sp = ffp->n_name + cpos; XX while (*sp) (*term.t_putchar)(*sp++); XX return(ffp->n_func); XX } XX else { XX /* try for a partial match against the list */ XX XX /* first scan down until we no longer match the XX current input */ XX lffp = (ffp + 1); XX while ((lffp+1)->n_func != NULL) { XX if (strncmp(buf, (lffp+1)->n_name, strlen(buf)) XX != 0) break; XX ++lffp; XX } XX XX /* and now, attempt to partial complete the string, XX char at a time */ XX while (TRUE) { XX /* add the next char in */ XX buf[cpos] = ffp->n_name[cpos]; XX XX /* scan through the candidates */ XX cffp = ffp + 1; XX while (cffp <= lffp) { XX if (cffp->n_name[cpos] != buf[cpos]) goto onward; XX ++cffp; XX } XX XX /* add the character */ XX (*term.t_putchar)(buf[cpos++]); XX } XX } XX } XX ++ffp; XX } XX XX /* no match.....beep and onward */ XX (*term.t_beep)(); XX onward:; XX } XX else { XX if (cpos < NSTRING-1 && c > ' ') { XX buf[cpos++] = c; XX (*term.t_putchar)(c); XX } XX XX ++ttcol; XX (*term.t_flush)(); XX } XX } XX } XX XXkbdtext(buf) /* add this text string to the current keyboard macro XXdefinition */ XX XXchar *buf; /* text to add to keyboard macro */ XX XX { XX /* if we are defining a keyboard macro, save it */ XX if (kbdmip != NULL) { XX if (kbdmip+strlen(buf) > &kbdm[NKBDM-4]) { XX ctrlg(FALSE, 0); XX (*term.t_flush)(); XX return(ABORT); XX } XX XX /* copy string in and null terminate it */ XX while (*buf) *kbdmip++ = *buf++; XX *kbdmip++ = 0; XX } XX return(TRUE); XX } SHAR_EOF if test 28840 -ne "`wc -c display.c`" then echo shar: error transmitting display.c '(should have been 28840 characters)' fi echo shar: extracting file.c sed 's/^XX//' << \SHAR_EOF > file.c XX/* XX * The routines in this file XX * handle the reading and writing of XX * disk files. All of details about the XX * reading and writing of the disk are XX * in "fileio.c". XX */ XX#include XX#include "estruct.h" XX#include "edef.h" XX XX#if ULTRIX XX#include XX#endif XX XX#if AMIGA XXextern char *strcat(),*strncat(),*strcpy(),*strncpy(), XX *index(),*rindex(); XX#endif XX XX#if VMS XX#define index(str,chr) strchr(str,chr) XX#define rindex(str,chr) strrchr(str,chr) XX#endif XX XX/* XX * Read a file into the current XX * buffer. This is really easy; all you do it XX * find the name of the file, and call the standard XX * "read a file into the current buffer" code. XX * Bound to "C-X C-R". XX */ XXfileread(f, n) XX { XX register int s; XX char fname[NFILEN]; XX XX if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE) return(s); XX return(readin(fname, TRUE)); XX } XX XX/* XX * Insert a file into the current XX * buffer. This is really easy; all you do it XX * find the name of the file, and call the standard XX * "insert a file into the current buffer" code. XX * Bound to "C-X C-I". XX */ XXinsfile(f, n) XX { XX register int s; XX char fname[NFILEN]; XX XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */ XX return(rdonly()); /* we are in read only mode */ XX if ((s=mlreply("Insert file: ", fname, NFILEN)) != TRUE) return(s); XX return(ifile(fname)); XX } XX XX/* XX * Select a file for editing. XX * Look around to see if you can find the XX * fine in another buffer; if you can find it XX * just switch to the buffer. If you cannot find XX * the file, create a new buffer, read in the XX * text, and switch to the new buffer. XX * Bound to C-X C-F. XX */ XXfilefind(f, n) XX { XX char fname[NFILEN]; /* file user wishes to find */ XX register int s; /* status return */ XX XX if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE) return(s); XX return(getfile(fname, TRUE)); XX } XX XXvisitfile(f, n) /* visit a file */ XX { XX char fname[NFILEN]; /* file user wishes to find */ XX register int s; /* status return */ XX register WINDOW *wp; /* scan for windows that need updating */ XX XX if ((s=mlreply("Visit file: ", fname, NFILEN)) != TRUE) return (s); XX if ((wp = wpopup()) != NULL) { XX curwp = wp; XX curbp = wp->w_bufp; XX } XX XX s = getfile(fname, FALSE); XX if (s) { /* see if we succeed */ XX /* scan through and update mode lines of all windows */ XX wp = wheadp; XX while (wp != NULL) { XX wp->w_flag |= WFMODE; XX wp = wp->w_wndp; XX } XX } XX return(s); XX } XX XXvisittag(f, n) /* visit a file (via a sorted tag file) */ XX { XX FILE *fp; XX char fname[NFILEN]; /* file that the user wishes to open */ XX char tname[40]; /* tag name to search for */ XX char sstr[128]; /* search string */ XX char istr[128],*ptr; /* input string */ XX register WINDOW *wp; /* scan for windows that need updating */ XX register LINE *dotp; XX register int doto,i; XX XX /* save the current position */ XX dotp = curwp->w_dotp; XX doto = curwp->w_doto; XX XX /* now get the name of the tag */ XX while (inword() == FALSE) XX if (forwchar(FALSE,1) == FALSE) return(FALSE); XX i = 0; XX while (inword() == TRUE || lgetc(curwp->w_dotp,curwp->w_doto) == '-') { XX tname[i++] = lgetc(curwp->w_dotp,curwp->w_doto); XX if (forwchar(FALSE,1) == FALSE) return(FALSE); XX } XX tname[i] = '\000'; XX /* restore the buffer position */ XX curwp->w_dotp = dotp; XX curwp->w_doto = doto; XX if (i == 0) return(FALSE); XX XX /* now open the tags file */ XX if ((fp = fopen("tags","r")) == NULL) { XX mlwrite("No tags file found"); XX return(FALSE); XX } XX XX /* now search for the tag in the file */ XX fname[0] = '\000'; XX ptr = &istr[0]; XX while (fgets(ptr,127,fp) != NULL) { XX if (*ptr == tname[0] && strncmp(ptr,tname,i) == 0) { XX ptr += i; XX sscanf(ptr," %s %127c",fname,sstr); XX break; XX } XX } XX fclose(fp); XX if (fname[0] == '\000') { XX mlwrite("Tag not found in tag file"); XX return(FALSE); XX } XX XX /* put the window up */ XX if ((wp = wpopup()) != NULL) { XX curwp = wp; XX curbp = wp->w_bufp; XX } XX XX /* read the file in */ XX if (! getfile(fname, FALSE)) return(FALSE); XX XX /* scan through and update mode lines of all windows */ XX wp = wheadp; XX while (wp != NULL) { XX wp->w_flag |= WFMODE; XX wp = wp->w_wndp; XX } XX XX /* get rid of delimeters */ XX ptr = sstr + strlen(sstr); XX while (ptr != sstr && *ptr != '/') ptr--; XX if (*ptr == '/') *ptr = '\000'; XX while ((ptr = index(sstr,'*')) != NULL) *ptr = '.'; XX while ((ptr = index(sstr,'+')) != NULL) *ptr = '.'; XX while ((ptr = index(sstr,'[')) != NULL) *ptr = '.'; XX while ((ptr = index(sstr,']')) != NULL) *ptr = '.'; XX if ((ptr=index(sstr,'/')) != NULL) ptr++; XX else ptr = sstr; XX XX /* do the scan (leave pointer at beginning of string) */ XX strcpy(pat,ptr); XX gotobob(FALSE,1); XX compile_bcode(); XX return(dosearch(TRUE,1,FALSE)); XX } XX XXgetfile(fname, lockfl) XX XXchar fname[]; /* file name to find */ XXint lockfl; /* check the file for locks? */ XX XX { XX register BUFFER *bp; XX register WINDOW *wp; XX register LINE *lp; XX register int i; XX register int s; XX char bname[NBUFN]; /* buffer name to put file */ XX XX for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) { XX if ((bp->b_flag&BFTEMP)==0 && strcmp(bp->b_fname, fname)==0) { XX swbuffer(bp); XX lp = curwp->w_dotp; XX i = curwp->w_ntrows/2; XX while (i-- && lback(lp)!=curbp->b_linep) lp = lback(lp); XX curwp->w_linep = lp; XX curwp->w_flag |= WFMODE|WFHARD; XX mlwrite("[Old buffer]"); XX return (TRUE); XX } XX } XX makename(bname, fname); /* New buffer name. */ XX while ((bp=bfind(bname, FALSE, 0)) != NULL) { XX s = mlreply("Buffer name: ", bname, NBUFN); XX if (s == ABORT) /* ^G to just quit */ XX return (s); XX if (s == FALSE) { /* CR to clobber it */ XX makename(bname, fname); XX break; XX } XX } XX if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) { XX mlwrite("Cannot create buffer"); XX return (FALSE); XX } XX if (--curbp->b_nwnd == 0) { /* Undisplay. */ XX curbp->b_dotp = curwp->w_dotp; XX curbp->b_doto = curwp->w_doto; XX curbp->b_markp = curwp->w_markp; XX curbp->b_marko = curwp->w_marko; XX } XX curbp = bp; /* Switch to it. */ XX curwp->w_bufp = bp; XX curbp->b_nwnd++; XX return(readin(fname, lockfl)); /* Read it in. */ XX } XX XX/* XX * Read file "fname" into the current XX * buffer, blowing away any text found there. Called XX * by both the read and find commands. Return the final XX * status of the read. Also called by the mainline, XX * to read in a file specified on the command line as XX * an argument. If the filename ends in a ".c", CMODE is XX * set for the current buffer. XX */ XXreadin(fname, lockfl) XX XXchar fname[]; /* name of file to read */ XXint lockfl; /* check for file locks? */ XX XX { XX register LINE *lp1; XX register LINE *lp2; XX register int i; XX register WINDOW *wp; XX register BUFFER *bp; XX register int s; XX register int nbytes; XX register int nline; XX register char *sptr; /* pointer into filename string */ XX int lflag; /* any lines longer than allowed? */ XX char line[NLINE]; XX XX#if FILOCK XX if (lockfl && lockchk(fname) == ABORT) return(ABORT); XX#endif XX bp = curbp; /* Cheap. */ XX if ((s=bclear(bp)) != TRUE) /* Might be old. */ XX return (s); XX bp->b_flag &= ~(BFTEMP|BFCHG); XX bp->b_mode |= MDEXACT; /*default to exact */ XX if (slowterm) bp->b_mode |= MDSLOW; XX XX sptr = fname + strlen(fname) - 4; XX if (strlen(fname) > 1 && XX *(sptr+2) == '.' && XX *(sptr+3) == 'c' || *(sptr+3) == 'h') { XX tab(FALSE,4); XX bp->b_mode |= MDCMOD; XX } XX else if (strlen(fname) > 3 && XX (*sptr=='.' && *(sptr+1)=='m' && *(sptr+2)=='o' && *(sptr+3)=='d') XX || (*sptr=='.' && *(sptr+1)=='d' && *(sptr+2)=='e' && *(sptr+3)=='f') XX || (*sptr=='.' && *(sptr+1)=='m' && *(sptr+2)=='m' && *(sptr+3)=='4') XX || (*(sptr+1)=='.' && *(sptr+2)=='m' && *(sptr+3)=='4')) { XX tab(FALSE,4); XX bp->b_mode |= MDMMOD; XX } XX else if (strlen(fname) > 3 && XX (*sptr=='.' && *(sptr+1)=='l' && *(sptr+2)=='s' && *(sptr+3)=='p') XX || (*(sptr+2)=='.' && *(sptr+3)=='l') XX || (*(sptr+1)=='.' && *(sptr+2)=='e' && *(sptr+3)=='l') XX || (*(sptr+1)=='.' && *(sptr+2)=='e' && *(sptr+3)=='m')) { XX tab(FALSE,2); XX bp->b_mode |= MDLISP; XX } XX else { XX tab(FALSE,0); XX bp->b_mode |= MDWRAP; XX } XX XX strcpy(bp->b_fname, fname); XX if ((s=ffropen(fname)) == FIOERR) /* Hard file open. */ XX goto out; XX if (s == FIOFNF) { /* File not found. */ XX mlwrite("[New file]"); XX goto out; XX } XX mlwrite("[Reading file]"); XX nline = 0; XX lflag = FALSE; XX while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG) { XX if (s == FIOLNG) lflag = TRUE; XX nbytes = strlen(line); XX if ((lp1=lalloc(nbytes)) == NULL) { XX s = FIOERR; /* Keep message on the */ XX break; /* display. */ XX } XX lp2 = lback(curbp->b_linep); XX lp2->l_fp = lp1; XX lp1->l_fp = curbp->b_linep; XX lp1->l_bp = lp2; XX curbp->b_linep->l_bp = lp1; XX for (i=0; iw_wndp) { XX if (wp->w_bufp == curbp) { XX wp->w_linep = lforw(curbp->b_linep); XX wp->w_dotp = lforw(curbp->b_linep); XX wp->w_doto = 0; XX wp->w_markp = NULL; XX wp->w_marko = 0; XX wp->w_flag |= WFMODE|WFHARD; XX } XX } XX if (s == FIOERR || s == FIOFNF) /* False if error. */ XX return(FALSE); XX return (TRUE); XX } XX XX/* XX * Take a file name, and from it XX * fabricate a buffer name. This routine knows XX * about the syntax of file names on the target system. XX * I suppose that this information could be put in XX * a better place than a line of code. XX */ XXmakename(bname, fname) XXchar bname[]; XXchar fname[]; XX { XX register char *cp1; XX register char *cp2; XX XX cp1 = &fname[0]; XX while (*cp1 != 0) ++cp1; XX XX#if AMIGA XX while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/') --cp1; XX#endif XX#if VMS XX while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']') --cp1; XX#endif XX#if ULTRIX XX while (cp1!=&fname[0] && cp1[-1]!='/') --cp1; XX#endif XX cp2 = &bname[0]; XX while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';') *cp2++ = *cp1++; XX *cp2 = 0; XX } XX XX/* XX * Ask for a file name, and write the XX * contents of the current buffer to that file. XX * Update the remembered file name and clear the XX * buffer changed flag. This handling of file names XX * is different from the earlier versions, and XX * is more compatable with Gosling EMACS than XX * with ITS EMACS. Bound to "C-X C-W". XX */ XXfilewrite(f, n) XX { XX register WINDOW *wp; XX register int s; XX char fname[NFILEN]; XX XX if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE) return (s); XX if ((s=writeout(fname)) == TRUE) { XX strcpy(curbp->b_fname, fname); XX curbp->b_flag &= ~BFCHG; XX wp = wheadp; /* Update mode lines. */ XX while (wp != NULL) { XX if (wp->w_bufp == curbp) wp->w_flag |= WFMODE; XX wp = wp->w_wndp; XX } XX } XX return (s); XX } XX XX/* XX * Save the contents of the current XX * buffer in its associatd file. No nothing XX * if nothing has changed (this may be a bug, not a XX * feature). Error if there is no remembered file XX * name for the buffer. Bound to "C-X C-S". May XX * get called by "C-Z". XX */ XXfilesave(f, n) XX { XX register WINDOW *wp; XX register int s; XX XX if (curbp->b_mode&MDVIEW) /* don't allow this command if */ XX return(rdonly()); /* we are in read only mode */ XX if ((curbp->b_flag&BFCHG) == 0) /* Return, no changes. */ XX return (TRUE); XX if (curbp->b_fname[0] == 0) { /* Must have a name. */ XX mlwrite("No file name"); XX return (FALSE); XX } XX if ((s=writeout(curbp->b_fname)) == TRUE) { XX curbp->b_flag &= ~BFCHG; XX wp = wheadp; /* Update mode lines. */ XX while (wp != NULL) { XX if (wp->w_bufp == curbp) wp->w_flag |= WFMODE; XX wp = wp->w_wndp; XX } XX } XX return (s); XX } XX XX/* XX * This function performs the details of file XX * writing. Uses the file management routines in the XX * "fileio.c" package. The number of lines written is XX * displayed. Sadly, it looks inside a LINE; provide XX * a macro for this. Most of the grief is error XX * checking of some sort. XX */ XXwriteout(fn) XXchar *fn; XX { XX register int s; XX register LINE *lp; XX register int nline; XX XX if ((s=ffwopen(fn)) != FIOSUC) /* Open writes message. */ XX return (FALSE); XX mlwrite("[Writing..]"); /* tell us were writing */ XX lp = lforw(curbp->b_linep); /* First line. */ XX nline = 0; /* Number of lines. */ XX while (lp != curbp->b_linep) { XX if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC) break; XX ++nline; XX lp = lforw(lp); XX } XX if (s == FIOSUC) { /* No write error. */ XX s = ffclose(); XX if (s == FIOSUC) { /* No close error. */ XX if (nline == 1) XX mlwrite("[Wrote 1 line]"); XX else XX mlwrite("[Wrote %d lines]", nline); XX } XX } XX else /* Ignore close error */ XX ffclose(); /* if a write error. */ XX if (s != FIOSUC) /* Some sort of error. */ XX return (FALSE); XX return (TRUE); XX } XX XX/* XX * The command allows the user XX * to modify the file name associated with XX * the current buffer. It is like the "f" command XX * in UNIX "ed". The operation is simple; just zap XX * the name in the BUFFER structure, and mark the windows XX * as needing an update. You can type a blank line at the XX * prompt if you wish. XX */ XXfilename(f, n) XX { XX register WINDOW *wp; XX register int s; XX char fname[NFILEN]; XX XX if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT) return (s); XX if (s == FALSE) strcpy(curbp->b_fname, ""); XX else XX strcpy(curbp->b_fname, fname); XX wp = wheadp; /* Update mode lines. */ XX while (wp != NULL) { XX if (wp->w_bufp == curbp) wp->w_flag |= WFMODE; XX wp = wp->w_wndp; XX } XX curbp->b_mode &= ~MDVIEW; /* no longer read only mode */ XX return (TRUE); XX } XX XX/* XX * Insert file "fname" into the current XX * buffer, Called by insert file command. Return the final XX * status of the read. XX */ XXifile(fname) XXchar fname[]; XX { XX register LINE *lp0; XX register LINE *lp1; XX register LINE *lp2; XX register int i; XX register WINDOW *wp; XX register BUFFER *bp; XX register int s; XX register int nbytes; XX register int nline; XX int lflag; /* any lines longer than allowed? */ XX char line[NLINE]; XX XX bp = curbp; /* Cheap. */ XX bp->b_flag |= BFCHG; /* we have changed */ XX bp->b_flag &= ~BFTEMP; /* and are not temporary*/ XX if ((s=ffropen(fname)) == FIOERR) /* Hard file open. */ XX goto out; XX if (s == FIOFNF) { /* File not found. */ XX mlwrite("[No such file]"); XX return(FALSE); XX } XX mlwrite("[Inserting file]"); XX XX /* back up a line and save the mark here */ XX curwp->w_dotp = lback(curwp->w_dotp); XX curwp->w_doto = 0; XX curwp->w_markp = curwp->w_dotp; XX curwp->w_marko = 0; XX XX nline = 0; XX lflag = FALSE; XX while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG) { XX if (s == FIOLNG) lflag = TRUE; XX nbytes = strlen(line); XX if ((lp1=lalloc(nbytes)) == NULL) { XX s = FIOERR; /* Keep message on the */ XX break; /* display. */ XX } XX lp0 = curwp->w_dotp; /* line previous to insert */ XX lp2 = lp0->l_fp; /* line after insert */ XX XX /* re-link new line between lp0 and lp2 */ XX lp2->l_bp = lp1; XX lp0->l_fp = lp1; XX lp1->l_bp = lp0; XX lp1->l_fp = lp2; XX XX /* and advance and write out the current line */ XX curwp->w_dotp = lp1; XX for (i=0; iw_markp = lforw(curwp->w_markp); XX if (s == FIOEOF) { /* Don't zap message! */ XX if (nline == 1) XX mlwrite("[Inserted 1 line]"); XX else XX mlwrite("[Inserted %d lines]", nline); XX } XX if (lflag) mlwrite("[Inserted %d line(s), Long lines wrapped]",nline); XX out: XX /* advance to the next line and mark the window for changes */ XX curwp->w_dotp = lforw(curwp->w_dotp); XX curwp->w_flag |= WFHARD; XX XX /* copy window parameters back to the buffer structure */ XX curbp->b_dotp = curwp->w_dotp; XX curbp->b_doto = curwp->w_doto; XX curbp->b_markp = curwp->w_markp; XX curbp->b_marko = curwp->w_marko; XX XX if (s == FIOERR) /* False if error. */ XX return (FALSE); XX return (TRUE); XX } XX SHAR_EOF if test 16669 -ne "`wc -c file.c`" then echo shar: error transmitting file.c '(should have been 16669 characters)' fi # End of shell archive exit 0