Path: utzoo!utgpu!cs.utexas.edu!swrinde!zaphod.mps.ohio-state.edu!think.com!cayman!pgf From: pgf@cayman.COM (Paul Fox) Newsgroups: alt.sources Subject: Vile 01/17 - vi feel-alike (multi-window) Message-ID: <4520@cayman.COM> Date: 7 Jun 91 22:09:05 GMT Organization: Cayman Systems Inc., Cambridge Ma Lines: 2334 Submitted-by: pgf@cayman.com Archive-name: Vile/part01 #!/bin/sh # This is Vile, a shell archive (shar 3.47) # made 06/07/1991 22:01 UTC by pgf@cayman.com # Source directory /tmp_mnt/home/carl/pgf/vile # # existing files WILL be overwritten # # This is part 1 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # # This shar contains: # length mode name # ------ ---------- ------------------------------------------ # 3835 -r--r--r-- README # 6488 -r--r--r-- ansi.c # 4175 -r--r--r-- at386.c # 20335 -r--r--r-- basic.c # 21479 -r--r--r-- bind.c # 20200 -r--r--r-- buffer.c # 6009 -r--r--r-- buglist # 17753 -r--r--r-- cmdtbl # 6989 -r--r--r-- crypt.c # 2171 -r--r--r-- csrch.c # 3333 -r--r--r-- dg10.c # 40087 -r--r--r-- display.c # 4340 -r--r--r-- dolock.c # 14722 -r--r--r-- ebind.h # 9852 -r--r--r-- edef.h # 27465 -r--r--r-- efunc.h # 956 -r--r--r-- epath.h # 30449 -r--r--r-- estruct.h # 18430 -r--r--r-- eval.c # 5247 -r--r--r-- evar.h # 32572 -r--r--r-- exec.c # 28527 -r--r--r-- file.c # 7384 -r--r--r-- fileio.c # 3373 -r--r--r-- finderr.c # 2834 -r--r--r-- globals.c # 3750 -r--r--r-- hp110.c # 9245 -r--r--r-- hp150.c # 10074 -r--r--r-- ibmpc.c # 10225 -r--r--r-- input.c # 18075 -r--r--r-- isearch.c # 20714 -r--r--r-- line.c # 3557 -r--r--r-- lock.c # 23507 -r--r--r-- main.c # 1438 -r--r--r-- make.ini # 9302 -r--r--r-- makefile # 7809 -r--r--r-- mktbls.c # 5332 -rw-rw-r-- nebind.h # 19211 -rw-rw-r-- nefunc.h # 17247 -rw-rw-r-- nename.h # 5376 -r--r--r-- news.c # 19928 -r--r--r-- news.cps # 2848 -r--r--r-- npopen.c # 4253 -r--r--r-- oneliner.c # 4699 -r--r--r-- opers.c # 34147 -r--r--r-- random.c # 7014 -r--r--r-- readme.news # 9127 -r--r--r-- region.c # 35047 -r--r--r-- search.c # 7910 -r--r--r-- shorten/COPYING # 178 -r--r--r-- shorten/defines.c # 857 -r--r--r-- shorten/dups.c # 674 -r--r--r-- shorten/header.h # 1637 -r--r--r-- shorten/names.c # 220 -r--r--r-- shorten/reserved # 0 -r--r--r-- shorten/special # 20300 -r--r--r-- spawn.c # 19931 -r--r--r-- st520.c # 57909 -r--r--r-- tags # 7806 -r--r--r-- tags.c # 6065 -r--r--r-- tcap.c # 16097 -r--r--r-- termio.c # 5308 -r--r--r-- tipc.c # 11158 -r--r--r-- undo.c # 24385 -r--r--r-- vile.hlp # 6798 -r--r--r-- vmalloc.c # 9271 -r--r--r-- vmsvt.c # 3386 -r--r--r-- vt52.c # 20419 -r--r--r-- window.c # 10449 -r--r--r-- word.c # 6094 -r--r--r-- wordmov.c # 652 -r--r--r-- z100bios.asm # 7806 -r--r--r-- z309.c # if test -r _shar_seq_.tmp; then echo 'Must unpack archives in sequence!' echo Please unpack part `cat _shar_seq_.tmp` next exit 1 fi # ============= README ============== echo 'x - extracting README (Text)' sed 's/^X//' << 'SHAR_EOF' > 'README' && X X X VILE -- VI Like Emacs: a vi workalike put together from Micro-Emacs by Paul Fox ------------------------------------------------------------------------------- X X This editor grew out of a frustration that although lots of X eager programmers have tackled rewrites of Emacs, with new and X better features (not to mention free source), I've not seen X anything similar done with the Second True Editor. (The X First, of course, being /bin/ed) X X So I took a copy of MicroEmacs 3.9 (which I've since X discovered was out of date, unfortunately) and bashed and X badgered it into a vi "feel-alike". It retains the multiple X buffer/multiple window features of uemacs, but the X "finger-feel", if you will, is very much that of vi. It is X definitely not a clone, in that some substantial stuff is X missing, and the screen doesn't look quite the same. But what X matters most is that one's "muscle memory" does the right thing X to the text in front of you, and that is what vile tries to do X for vi users. THIS IS NOT A "CLONE"! X X This is the first really public version of vile. It is X version three. Users of previous versions will hopefully find X the additions of ":" command line ranges and the ! filter X operator helpful. X X The collective developers of Micro-Emacs should be X complimented that the changes were as easy as they were. The X code was pretty clean and well designed before I started on X it. I'm not sure that the same can be said anymore... X X The benefits over standard vi include: X - multiple files open at once X - multiple windows on the screen X - a larger set of operator commands X - the possibility of porting to your favorite micro. X (mind you, I haven't even tried this on a small X UNIX machine, let alone DOS etc...) X - more uniform undo/yank register treatment X - using tags doesn't lose your last search pattern X - "next error" cursor positioning after compilation X Of course, it _may_ lack some of vi's reliability. :-) X X ( Although I can't imagine the emacs folks wanting to buy much X of this stuff back (insert mode, anyone? :-), they might X want to look at: X - full global undo X - tags support X - better (maybe?) UNIX terminal handling X - better UNIX shell escapes X - terminal scroll support X - multiple yank registers (formerly called kill buffers) X - multiple marks (actually kind of messy) X - improved aesthetics of window splitting and deleting X - "next error" cursor positioning X - list mode ) X X Take a look at vile.hlp for more information about features X and differences. X X In general, I suspect that the quality of the code is roughly X on a par with MicroEmacs. I've been using vile regularly under X both SunOS and 386 UNIX for about a year, with no major problems X (that havn't been fixed). Another dedicated user has been X running it on various flavors of 386 UNIX (Bell, Open DeskTop, X Xenix) and Ultrix, also with no problems. X X I have not tried this on a small system, or even _any_ X non-UNIX system. I'm sure work will be required to make X it work on DOS again, for instance -- especially for spawning X sub-shells, etc. X X I ifdef'ed out the language features (user-defined procs, X etc.) a long time ago -- I don't know if they still work, X though I didn't actively try to break them. X X If anyone is interested in doing major work on this thing, let me X know -- I have some ideas on how to make a full ex mode work, for X instance, and on how to add the ":map" command. Also, take a look X at the buglist... X X Hope you enjoy -- X X Paul G. Fox June 3, 1991 X pgf@cayman.com X p.s. The code distributed with vile in the "shortnames" subdirectory X is covered by GNU Public License. The vile code itself in the X upper level directory is _not_ covered by the GNU public license. X p.p.s By the way, I'm _not_ the same Paul Fox who wrote Crisp, the Brief X work-alike. SHAR_EOF chmod 0444 README || echo 'restore of README failed' Wc_c="`wc -c < 'README'`" test 3835 -eq "$Wc_c" || echo 'README: original size 3835, current size' "$Wc_c" # ============= ansi.c ============== echo 'x - extracting ansi.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'ansi.c' && /* X * The routines in this file provide support for ANSI style terminals X * over a serial line. The serial I/O services are provided by routines in X * "termio.c". It compiles into nothing if not an ANSI device. X */ X #define termdef 1 /* don't define "term" external */ X #include #include "estruct.h" #include "edef.h" X #if ANSI X #if AMIGA #define NROW 23 /* Screen size. */ #define NCOL 77 /* Edit if you want to. */ #else #define NROW 24 /* Screen size. */ #define NCOL 80 /* Edit if you want to. */ #endif #define NPAUSE 100 /* # times thru update to pause */ #define MARGIN 8 /* size of minimim margin and */ #define SCRSIZ 64 /* scroll size for extended lines */ #define BEL 0x07 /* BEL character. */ #define ESC 0x1B /* ESC character. */ X extern int ttopen(); /* Forward references. */ extern int ttgetc(); extern int ttputc(); extern int ttflush(); extern int ttclose(); extern int ansimove(); extern int ansieeol(); extern int ansieeop(); extern int ansibeep(); extern int ansiopen(); extern int ansirev(); extern int ansiclose(); extern int ansikopen(); extern int ansikclose(); extern int ansicres(); #if SCROLLCODE extern int ansiscroll(); #endif X #if COLOR extern int ansifcol(); extern int ansibcol(); X int cfcolor = -1; /* current forground color */ int cbcolor = -1; /* current background color */ X #if AMIGA /* apperently the AMIGA does not follow the ANSI standards as X regards to colors....maybe because of the default pallette X settings? */ X int coltran[8] = {2, 3, 5, 7, 0, 4, 6, 1}; /* color translation table */ #endif #endif X /* X * Standard terminal interface dispatch table. Most of the fields point into X * "termio" code. X */ TERM term = { X NROW-1, X NROW-1, X NCOL, X NCOL, X MARGIN, X SCRSIZ, X NPAUSE, X ansiopen, X ansiclose, X ansikopen, X ansikclose, X ttgetc, X ttputc, X ttflush, X ansimove, X ansieeol, X ansieeop, X ansibeep, X ansirev, X ansicres #if COLOR X , ansifcol, X ansibcol #endif #if SCROLLCODE X , ansiscroll #endif }; X csi() { X ttputc(ESC); X ttputc('['); } X #if COLOR ansifcol(color) /* set the current output color */ X int color; /* color to set */ X { X if (color == cfcolor) X return; X csi(); #if AMIGA X ansiparm(coltran[color]+30); #else X ansiparm(color+30); #endif X ttputc('m'); X cfcolor = color; } X ansibcol(color) /* set the current background color */ X int color; /* color to set */ X { X if (color == cbcolor) X return; X csi(); #if AMIGA X ansiparm(coltran[color]+40); #else X ansiparm(color+40); #endif X ttputc('m'); X cbcolor = color; } #endif X ansimove(row, col) { X csi(); X if (row) ansiparm(row+1); X ttputc(';'); X if (col) ansiparm(col+1); X ttputc('H'); } X ansieeol() { X csi(); X ttputc('K'); } X ansieeop() { #if COLOR X ansifcol(gfcolor); X ansibcol(gbcolor); #endif X csi(); X ttputc('J'); } X X ansirev(state) /* change reverse video state */ X int state; /* TRUE = reverse, FALSE = normal */ X { #if COLOR X int ftmp, btmp; /* temporaries for colors */ #else X static int revstate = -1; X if (state == revstate) X return; X revstate = state; #endif X X csi(); X if (state) ttputc('7'); X ttputc('m'); #if COLOR X if (state == FALSE) { X ftmp = cfcolor; X btmp = cbcolor; X cfcolor = -1; X cbcolor = -1; X ansifcol(ftmp); X ansibcol(btmp); X } #endif } X ansicres() /* change screen resolution */ { X return(TRUE); } X spal(dummy) /* change pallette settings */ { X /* none for now */ } X ansibeep() { X ttputc(BEL); X ttflush(); } X #if SCROLLCODE X /* if your ansi terminal can scroll regions, like the vt100, then define X SCROLL_REG. If not, you can use delete/insert line code, which X is prettier but slower if you do it a line at a time instead of X all at once. */ X #define SCROLL_REG 1 X /* move howmany lines starting at from to to */ ansiscroll(from,to,howmany) { X int i; X if (to == from) return; #if SCROLL_REG X if (to < from) { X ansiscrollregion(to, from + howmany - 1); X ansimove(from + howmany - 1,0); X for (i = from - to; i > 0; i--) X ttputc('\n'); X } else { /* from < to */ X ansiscrollregion(from, to + howmany - 1); X ansimove(from); X for (i = to - from; i > 0; i--) { X ttputc(ESC); X ttputc('M'); X } X } X ansiscrollregion(0, term.t_mrow); X #else /* use insert and delete line */ #if PRETTIER_SCROLL X if (abs(from-to) > 1) { X ansiscroll(from, (from 1) ansiparm(from - to); X ttputc('M'); /* delete */ X ansimove(to+howmany,0); X csi(); X if (from - to > 1) ansiparm(from - to); X ttputc('L'); /* insert */ X } else { X ansimove(from+howmany,0); X csi(); X if (to - from > 1) ansiparm(to - from); X ttputc('M'); /* delete */ X ansimove(from,0); X csi(); X if (to - from > 1) ansiparm(to - from); X ttputc('L'); /* insert */ X } #endif } X #if SCROLL_REG ansiscrollregion(top,bot) { X csi(); X if (top) ansiparm(top + 1); X ttputc(';'); X if (bot != term.t_nrow) ansiparm(bot + 1); X ttputc('r'); } #endif X #endif X ansiparm(n) register int n; { X register int q,r; X X q = n/10; X if (q != 0) { X r = q/10; X if (r != 0) { X ttputc((r%10)+'0'); X } X ttputc((q%10) + '0'); X } X ttputc((n%10) + '0'); } X ansiopen() { #if V7 | USG | BSD #if 0 X register char *cp; X char *getenv(); X X if ((cp = getenv("TERM")) == NULL) { X puts("Shell variable TERM not defined!"); X exit(1); X } X if (strcmp(cp, "vt100") != 0 && strcmp(cp, "ansi") != 0) { X puts("Terminal type not 'vt100' or 'ansi'!"); X exit(1); X } #endif #endif X strcpy(sres, "NORMAL"); X revexist = TRUE; X ttopen(); } X ansiclose() { #if COLOR X ansifcol(7); X ansibcol(0); #endif X ttclose(); } X ansikopen() /* open the keyboard (a noop here) */ { } X ansikclose() /* close the keyboard (a noop here) */ { } X #if FLABEL fnclabel(f, n) /* label a function key */ int f,n; /* default flag, numeric argument [unused] */ { X /* on machines with no function keys...don't bother */ X return(TRUE); } #endif #else ansihello() { } #endif SHAR_EOF chmod 0444 ansi.c || echo 'restore of ansi.c failed' Wc_c="`wc -c < 'ansi.c'`" test 6488 -eq "$Wc_c" || echo 'ansi.c: original size 6488, current size' "$Wc_c" # ============= at386.c ============== echo 'x - extracting at386.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'at386.c' && /* AT386: hacked tcap.c for the 386 console, when you don't X have libtermcap. grrr. */ X #define termdef 1 /* don't define "term" external */ X #include #include "estruct.h" #include "edef.h" X #if AT386 X #define NROW 25 /* Screen size. */ #define NCOL 80 /* Edit if you want to. */ #define MARGIN 8 #define SCRSIZ 64 #define NPAUSE 10 /* # times thru update to pause */ #define BEL 0x07 #define ESC 0x1B X extern int ttopen(); extern int ttgetc(); extern int ttputc(); extern int tgetnum(); extern int ttflush(); extern int ttclose(); extern int at386kopen(); extern int at386kclose(); extern int at386move(); extern int at386eeol(); extern int at386eeop(); extern int at386beep(); extern int at386rev(); extern int at386cres(); extern int at386open(); extern int tput(); extern char *tgoto(); #if COLOR extern int at386fcol(); extern int at386bcol(); #endif #if SCROLLCODE extern int at386scroll_delins(); #endif X #define TCAPSLEN 315 char at386buf[TCAPSLEN]; char *UP, PC, *CM, *CE, *CL, *SO, *SE; X #if SCROLLCODE char *DL, *AL, *SF, *SR; #endif X TERM term = { X NROW-1, X NROW-1, X NCOL, X NCOL, X MARGIN, X SCRSIZ, X NPAUSE, X at386open, X ttclose, X at386kopen, X at386kclose, X ttgetc, X ttputc, X ttflush, X at386move, X at386eeol, X at386eeop, X at386beep, X at386rev, X at386cres #if COLOR X , at386fcol, X at386bcol #endif #if SCROLLCODE X , NULL /* set dynamically at open time */ #endif }; X at386open() { X char *getenv(); X char *t, *p, *tgetstr(); X char tcbuf[1024]; X char *tv_stype; X char err_str[72]; X X CL = "\033[2J\033[H"; X CE = "\033[K"; X UP = "\033[A"; X SE = "\033[m"; X SO = "\033[7m"; X revexist = TRUE; X X #if SCROLLCODE X DL = "\033[1M"; X AL = "\033[1L"; X term.t_scroll = at386scroll_delins; #endif X ttopen(); } X at386kopen() { X strcpy(sres, "NORMAL"); } X at386kclose() { } X csi() { X ttputc(ESC); X ttputc('['); } X ansiparm(n) register int n; { X register int q,r; X X q = n/10; X if (q != 0) { X r = q/10; X if (r != 0) { X ttputc((r%10)+'0'); X } X ttputc((q%10) + '0'); X } X ttputc((n%10) + '0'); } X at386move(row, col) register int row, col; { X csi(); X if (row) ansiparm(row+1); X ttputc(';'); X if (col) ansiparm(col+1); X ttputc('H'); } X at386eeol() { X fputs(CE,stdout); } X at386eeop() { X fputs(CL,stdout); } X at386rev(state) /* change reverse video status */ int state; /* FALSE = normal video, TRUE = reverse video */ { X static int revstate = -1; X if (state == revstate) X return; X revstate = state; X if (state) { X if (SO != NULL) X fputs(SO,stdout); X } else { X if (SE != NULL) X fputs(SE,stdout); X } } X at386cres() /* change screen resolution */ { X return(TRUE); } X #if SCROLLCODE X /* PRETTIER_SCROLL is prettier but slower -- it scrolls X a line at a time instead of all at once. */ X /* move howmany lines starting at from to to */ at386scroll_delins(from,to,howmany) { X int i; X if (to == from) return; #if PRETTIER_SCROLL X if (abs(from-to) > 1) { X at386scroll_delins(from, (from 0; i--) X fputs(DL,stdout); X at386move(to+howmany,0); X for (i = from - to; i > 0; i--) X fputs(AL,stdout); X } else { X at386move(from+howmany,0); X for (i = to - from; i > 0; i--) X fputs(DL,stdout); X at386move(from,0); X for (i = to - from; i > 0; i--) X fputs(AL,stdout); X } } X #endif X spal(dummy) /* change palette string */ { X /* Does nothing here */ } X X #if COLOR at386fcol() /* no colors here, ignore this */ { } X at386bcol() /* no colors here, ignore this */ { } #endif X at386beep() { X ttputc(BEL); } X X #if FLABEL fnclabel(f, n) /* label a function key */ int f,n; /* default flag, numeric argument [unused] */ { X /* on machines with no function keys...don't bother */ X return(TRUE); } #endif #else X hello() { } X #endif SHAR_EOF chmod 0444 at386.c || echo 'restore of at386.c failed' Wc_c="`wc -c < 'at386.c'`" test 4175 -eq "$Wc_c" || echo 'at386.c: original size 4175, current size' "$Wc_c" # ============= basic.c ============== echo 'x - extracting basic.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'basic.c' && /* X * The routines in this file move the cursor around on the screen. They X * compute a new value for the cursor, then adjust ".". The display code X * always updates the cursor location, so only moves between lines, or X * functions that adjust the top line in the window and invalidate the X * framing, are hard. X */ #include #include "estruct.h" #include "edef.h" X /* X * Move the cursor to the X * beginning of the current line. X * Trivial. X */ gotobol(f, n) { X curwp->w_doto = 0; X return (TRUE); } X /* X * Move the cursor backwards by "n" characters. If "n" is less than zero call X * "forwchar" to actually do the move. Otherwise compute the new cursor X * location. Error if you try and move out of the buffer. Set the flag if the X * line pointer for dot changes. X */ backchar(f, n) register int n; { X register LINE *lp; X X if (f == FALSE) n = 1; X if (n < 0) X return (forwchar(f, -n)); X while (n--) { X if (curwp->w_doto == 0) { X if ((lp=lback(curwp->w_dotp)) == curbp->b_linep) X return (FALSE); X curwp->w_dotp = lp; X curwp->w_doto = llength(lp); X curwp->w_flag |= WFMOVE; X } else X curwp->w_doto--; X } X return (TRUE); } X /* X * Move the cursor to the end of the current line. Trivial. No errors. X */ gotoeol(f, n) { X if (f == TRUE) { X if (n > 0) X --n; X else if (n < 0) X ++n; X forwline(f,n); X } X curwp->w_doto = llength(curwp->w_dotp); X curgoal = HUGE; X return (TRUE); } X /* X * Move the cursor forwards by "n" characters. If "n" is less than zero call X * "backchar" to actually do the move. Otherwise compute the new cursor X * location, and move ".". Error if you try and move off the end of the X * buffer. Set the flag if the line pointer for dot changes. X */ forwchar(f, n) register int n; { X if (f == FALSE) n = 1; X if (n < 0) X return (backchar(f, -n)); X while (n--) { X if (curwp->w_doto == llength(curwp->w_dotp)) { X if (curwp->w_dotp == curbp->b_linep || X lforw(curwp->w_dotp) == curbp->b_linep) X return (FALSE); X curwp->w_dotp = lforw(curwp->w_dotp); X curwp->w_doto = 0; X curwp->w_flag |= WFMOVE; X } else X curwp->w_doto++; X } X return (TRUE); } X gotoline(f, n) /* move to a particular line. X argument (n) must be a positive integer for X this to actually do anything */ { X register int status; /* status return */ X X /* get an argument if one doesnt exist */ X if (f == FALSE) { X return(gotoeob(f,n)); X } X X if (n < 1) /* if a bogus argument...then leave */ X return(FALSE); X X /* first, we go to the start of the buffer */ X curwp->w_dotp = lforw(curbp->b_linep); X curwp->w_doto = 0; X status = forwline(f, n-1); X if (status == TRUE) X firstnonwhite(f,n); X return(status); } X /* X * Goto the beginning of the buffer. Massive adjustment of dot. This is X * considered to be hard motion; it really isn't if the original value of dot X * is the same as the new value of dot. X */ gotobob(f, n) { X curwp->w_dotp = lforw(curbp->b_linep); X curwp->w_doto = 0; X curwp->w_flag |= WFMOVE; X return (TRUE); } X /* X * Move to the end of the buffer. Dot is always put at the end of the file X * (ZJ). The standard screen code does most of the hard parts of update. X */ gotoeob(f, n) { X curwp->w_dotp = lback(curbp->b_linep); X firstnonwhite(FALSE,1); X curwp->w_flag |= WFMOVE; X return (TRUE); } X gotobos(f,n) { X int s = TRUE; X if (f == FALSE || n <= 0) n = 1; X curwp->w_dotp = curwp->w_linep; X while (--n) { X if ((s = forwline(FALSE,1)) != TRUE) X break; X } X firstnonwhite(f,n); X return (s); } X gotomos(f,n) { X return gotobos(TRUE,curwp->w_ntrows/2); } X gotoeos(f,n) { X return gotobos(TRUE,curwp->w_ntrows-(f==TRUE? n-1:0)); } X /* X * Move forward by full lines. If the number of lines to move is less than X * zero, call the backward line function to actually do it. The last command X * controls how the goal column is set. No errors are X * possible. X */ forwline(f, n) { X register LINE *dlp; X X if (f == FALSE) n = 1; X if (n < 0) X return (backline(f, -n)); X X /* if we are on the last line as we start....fail the command */ X if (curwp->w_dotp == curbp->b_linep) X return(FALSE); X X /* if the last command was not a line move, X reset the goal column */ X if (curgoal < 0) X curgoal = getccol(FALSE); X X /* and move the point down */ X dlp = curwp->w_dotp; X while (n-- && dlp!=curbp->b_linep) X dlp = lforw(dlp); X X /* resetting the current position */ X curwp->w_dotp = (dlp == curbp->b_linep) ? lback(dlp) : dlp; X curwp->w_doto = getgoal(dlp); X curwp->w_flag |= WFMOVE; X return (TRUE); } X firstnonwhite(f,n) { X int c; X curwp->w_doto = 0; X while ( curwp->w_doto != llength(curwp->w_dotp) && X isspace(lgetc(curwp->w_dotp, curwp->w_doto)) ) X curwp->w_doto++; X return (TRUE); } X lastnonwhite(f,n) { X int c; X curwp->w_doto = llength(curwp->w_dotp)-1; X while ( curwp->w_doto != 0 && X ((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || c == '\t')) X curwp->w_doto--; X return (TRUE); X } X /* like forwline, but got to first non-white char position */ forwbline(f,n) { X int s; X X if (f == FALSE) n = 1; X if ((s = forwline(f,n)) != TRUE) X return (s); X firstnonwhite(f,n); X return(TRUE); } X /* like backline, but got to first non-white char position */ backbline(f,n) { X int s; X X if (f == FALSE) n = 1; X if ((s = backline(f,n)) != TRUE) X return (s); X firstnonwhite(f,n); X return(TRUE); } X /* X * This function is like "forwline", but goes backwards. The scheme is exactly X * the same. Check for arguments that are less than zero and call your X * alternate. Figure out the new line and call "movedot" to perform the X * motion. No errors are possible. X */ backline(f, n) { X register LINE *dlp; X X if (f == FALSE) n = 1; X if (n < 0) X return (forwline(f, -n)); X X X /* if we are on the last line as we start....fail the command */ X if (lback(curwp->w_dotp) == curbp->b_linep) X return(FALSE); X X /* if the last command was not note a line move, X reset the goal column */ X if (curgoal < 0) X curgoal = getccol(FALSE); X X /* and move the point up */ X dlp = curwp->w_dotp; X while (n-- && lback(dlp)!=curbp->b_linep) X dlp = lback(dlp); X X /* reseting the current position */ X curwp->w_dotp = dlp; X curwp->w_doto = getgoal(dlp); X curwp->w_flag |= WFMOVE; X return (TRUE); } X #if WORDPRO X gotobop(f,n) { X return(backlinebeg(f,n,"\n.","ILPQb")); } gotoeop(f,n) { X return(forwlinebeg(f,n,"\n.","ILPQb")); } gotobosec(f,n) { #if STUTTER_SEC_CMD X int this1key; X if (!clexec) { X this1key = last1key; X kbd_seq(); X if (this1key != last1key) { X TTbeep(); X return(FALSE); X } X } #endif X return(backlinebeg(f,n,"{\f.","SHN")); } gotoeosec(f,n) { #if STUTTER_SEC_CMD X int this1key; X if (!clexec) { X this1key = last1key; X kbd_seq(); X if (this1key != last1key) { X TTbeep(); X return(FALSE); X } X } #endif X return(forwlinebeg(f,n,"{\f.","SHN")); } X backlinebeg(f, n, s1, s2) char *s1, *s2; { X register int suc; /* success of last backchar */ X LINE *odotp; X X if (f == FALSE) n = 1; X if (n < 0) /* the other way...*/ X return(gotoeop(f, -n)); X X odotp = curwp->w_dotp; X while (n-- > 0) { /* for each one asked for */ X X /* first scan back until we are in a word */ X suc = backchar(FALSE, 1); X while (!inword() && suc) X suc = backchar(FALSE, 1); X X while (lback(curwp->w_dotp) != curbp->b_linep) { X if (issecbeg(s1,s2) == TRUE) X break; X curwp->w_dotp = lback(curwp->w_dotp); X } X } X /* if doing an operation and we moved */ X if (doingopcmd && odotp != curwp->w_dotp) { X curwp->w_dotp = lforw(curwp->w_dotp); X curwp->w_doto = 0; X } else { X firstnonwhite(f,n); X } X curwp->w_flag |= WFMOVE; /* force screen update */ X return(TRUE); } X forwlinebeg(f, n, s1, s2) char *s1, *s2; { X register int suc; /* success of last backchar */ X LINE *odotp; X X if (f == FALSE) n = 1; X if (n < 0) /* the other way...*/ X return(gotobop(f, -n)); X X odotp = curwp->w_dotp; X while (n-- > 0) { /* for each one asked for */ X X /* first scan forward until we are in a word */ X suc = forwchar(FALSE, 1); X while (!inword() && suc) X suc = forwchar(FALSE, 1); X curwp->w_doto = 0; /* and go to the B-O-Line */ X if (suc) /* of next line if not at EOF */ X curwp->w_dotp = lforw(curwp->w_dotp); X X while (curwp->w_dotp != curbp->b_linep) { X if (issecbeg(s1,s2) == TRUE) X break; X curwp->w_dotp = lforw(curwp->w_dotp); X } X } X /* if doing an operation and we moved */ X if (doingopcmd && odotp != curwp->w_dotp) { X curwp->w_dotp = lback(curwp->w_dotp); X curwp->w_doto = llength(curwp->w_dotp)-1; X } else { X firstnonwhite(f,n); X } X curwp->w_flag |= WFMOVE; /* force screen update */ X return(TRUE); } X /* a new "section" of some sort starts at the beginning of the line, X with either a character from s1 or a "." followed by a character X from s2 */ issecbeg(s1,s2) char *s1,*s2; { X register char *cp1, *cp2; X register int l, c1, c2; X X l = llength(curwp->w_dotp); X for(cp1 = s1; *cp1 != 0; cp1++) { X if ( l == 0) { X if (*cp1 == '\n') X return TRUE; X else X continue; X } X c1 = lgetc(curwp->w_dotp, 0); X if (c1 == '.' && *cp1 == '.' && s2) { X for(cp2 = s2; *cp2 != 0; cp2++) { X if ( l <= 1) { X if (*cp2 == '\n') X return TRUE; X else X continue; X } X c2 = lgetc(curwp->w_dotp, 1); X if ( *cp2 == c2 ) X return TRUE; X } X X } else if ( *cp1 == c1 ) { X return TRUE; X } X } X return FALSE; } #endif X /* X * This routine, given a pointer to a LINE, and the current cursor goal X * column, return the best choice for the offset. The offset is returned. X * Used by "C-N" and "C-P". X */ getgoal(dlp) register LINE *dlp; { X register int c; X register int col; X register int newcol; X register int dbo; X X col = 0; X dbo = 0; X while (dbo != llength(dlp)) { X c = lgetc(dlp, dbo); X newcol = col; X if (((curwp->w_bufp->b_mode&MDLIST) == 0) && c == '\t') X newcol |= TABMASK; X else if (!isprint(c)) X ++newcol; X ++newcol; X if (newcol > curgoal) X break; X col = newcol; X ++dbo; X } X return (dbo); } X /* X * Scroll forward by a specified number of lines, or by a full page if no X * argument. The "2" in the arithmetic on the window size is X * the overlap; this value is the default overlap value in ITS EMACS. Because X * this zaps the top line in the display window, we have to do a hard update. X */ forwpage(f, n) register int n; { X register LINE *lp; X X if (f == FALSE) { X n = curwp->w_ntrows - 2; /* Default scroll. */ X if (n <= 0) /* Forget the overlap */ X n = 1; /* if tiny window. */ X } else if (n < 0) X return (backpage(f, -n)); #if CVMVAS X else /* Convert from pages */ X n *= curwp->w_ntrows; /* to lines. */ #endif X lp = curwp->w_linep; X while (n-- && lp!=curbp->b_linep) X lp = lforw(lp); X curwp->w_linep = lp; X curwp->w_dotp = lp; X curwp->w_doto = 0; X curwp->w_flag |= WFHARD; X return (TRUE); } X /* X * This command is like "forwpage", but it goes backwards. The "2", like X * above, is the overlap between the two windows. The value is from the ITS X * EMACS manual. We do a hard update for exactly the same X * reason. X */ backpage(f, n) register int n; { X register LINE *lp; X X if (f == FALSE) { X n = curwp->w_ntrows - 2; /* Default scroll. */ X if (n <= 0) /* Don't blow up if the */ X n = 1; /* window is tiny. */ X } else if (n < 0) X return (forwpage(f, -n)); #if CVMVAS X else /* Convert from pages */ X n *= curwp->w_ntrows; /* to lines. */ #endif X lp = curwp->w_linep; X while (n-- && lback(lp)!=curbp->b_linep) X lp = lback(lp); X curwp->w_linep = lp; X curwp->w_dotp = lp; X curwp->w_doto = 0; X curwp->w_flag |= WFHARD; X return (TRUE); } X /* X * Scroll forward by a specified number of lines, or by a full page if no X * argument. The "2" in the arithmetic on the window size is X * the overlap; this value is the default overlap value in ITS EMACS. Because X * this zaps the top line in the display window, we have to do a hard update. X */ forwhpage(f, n) register int n; { X register LINE *llp, *dlp; X X if (f == FALSE) { X n = curwp->w_ntrows / 2; /* Default scroll. */ X if (n <= 0) /* Forget the overlap */ X n = 1; /* if tiny window. */ X } else if (n < 0) X return (backhpage(f, -n)); #if CVMVAS X else /* Convert from pages */ X n *= curwp->w_ntrows/2; /* to lines. */ #endif X llp = curwp->w_linep; X dlp = curwp->w_dotp; X while (n-- && lforw(dlp) != curbp->b_linep) { X llp = lforw(llp); X dlp = lforw(dlp); X } X curwp->w_linep = llp; X curwp->w_dotp = dlp; X firstnonwhite(f,n); X curwp->w_flag |= WFHARD|WFKILLS; X return (TRUE); } X /* X * This command is like "forwpage", but it goes backwards. The "2", like X * above, is the overlap between the two windows. The value is from the ITS X * EMACS manual. We do a hard update for exactly the same X * reason. X */ backhpage(f, n) register int n; { X register LINE *llp, *dlp; X X if (f == FALSE) { X n = curwp->w_ntrows / 2; /* Default scroll. */ X if (n <= 0) /* Don't blow up if the */ X n = 1; /* window is tiny. */ X } else if (n < 0) X return (forwhpage(f, -n)); #if CVMVAS X else /* Convert from pages */ X n *= curwp->w_ntrows/2; /* to lines. */ #endif X llp = curwp->w_linep; X dlp = curwp->w_dotp; X while (n-- && lback(dlp)!=curbp->b_linep) { X llp = lback(llp); X dlp = lback(dlp); X } X curwp->w_linep = llp; X curwp->w_dotp = dlp; X firstnonwhite(f,n); X curwp->w_flag |= WFHARD|WFINS; X return (TRUE); } X X X /* X * Set the named mark in the current window to the value of "." in the window. X * No errors are possible. X */ setnmmark(f,n) { X char *s; X int c,i; X X if (clexec || isnamedcmd) { X int stat; X static char cbuf[2]; X if ((stat=mlreply("Set mark: ", cbuf, 2)) != TRUE) X return stat; X c = cbuf[0]; X } else { X c = kbd_key(); X } X if (c < 'a' || c > 'z') { X TTbeep(); X mlwrite("[Invalid mark name]"); X return FALSE; X } X X if (curbp->b_nmmarks == NULL) { X curbp->b_nmmarks = X (struct MARK *)malloc(26*sizeof(struct MARK)); X if (curbp->b_nmmarks == NULL) { X mlwrite("[OUT OF MEMORY]"); X return FALSE; X } X for (i = 0; i < 26; i++) { X curbp->b_nmmarks[i].markp = NULL; X curbp->b_nmmarks[i].marko = 0; X } X } X X curbp->b_nmmarks[c-'a'].markp = curwp->w_dotp; X curbp->b_nmmarks[c-'a'].marko = curwp->w_doto; X s = "[Mark X set]"; X s[6] = c; X mlwrite(s); X return TRUE; } X golinenmmark(f,n) { X int status; X status = goexactnmmark(f,n); X if (status != TRUE) X return(status); X firstnonwhite(f,n); X return(TRUE); } X goexactnmmark(f,n) { X int c; X int this1key; X int useldmark; X X this1key = last1key; X c = kbd_seq(); X useldmark = (last1key == this1key); /* '' or `` */ X c = kcod2key(c); X X if (useldmark) X c = '\''; X X return gonmmark(c); } X gonmmark(c) { X register LINE **markpp; X register int *markop; X LINE *tmarkp; X int tmarko; X int found; X X if (!islower(c) && c != '\'') { X TTbeep(); X mlwrite("[Invalid mark name]"); X return FALSE; X } X X markpp = NULL; X X if (c == '\'') { /* use the 'last dot' mark */ X markpp = &(curwp->w_ldmkp); X markop = &(curwp->w_ldmko); X } else if (curbp->b_nmmarks != NULL) { X markpp = &(curbp->b_nmmarks[c-'a'].markp); X markop = &(curbp->b_nmmarks[c-'a'].marko); X } X X found = FALSE; X if (markpp != NULL && *markpp != NULL) { X register LINE *lp; X for (lp = lforw(curbp->b_linep); X lp != curbp->b_linep; lp = lforw(lp)) { X if (*markpp == lp) { X found = TRUE; X break; X } X } X } X if (!found) { X TTbeep(); X mlwrite("[Mark not set]"); X return (FALSE); X } X X /* save current dot */ X tmarkp = curwp->w_dotp; X tmarko = curwp->w_doto; X X /* move to the selected mark */ X curwp->w_dotp = *markpp; X curwp->w_doto = *markop; X X /* reset last-dot-mark to old dot */ X curwp->w_ldmkp = tmarkp; X curwp->w_ldmko = tmarko; X X curwp->w_flag |= WFMOVE; X return (TRUE); } X /* X * Set the mark in the current window to the value of "." in the window. No X * errors are possible. X */ setmark() { X curwp->w_mkp = curwp->w_dotp; X curwp->w_mko = curwp->w_doto; X return (TRUE); } X gomark(f,n) { X curwp->w_dotp = curwp->w_mkp; X curwp->w_doto = curwp->w_mko; X curwp->w_flag |= WFMOVE; X return (TRUE); } X /* this odd routine puts us at the internal mark, plus an offset of lines */ /* n == 1 leaves us at mark, n == 2 one line down, etc. */ /* this is for the use of stuttered commands, and line oriented regions */ godotplus(f,n) { X int s; X if (!f || n == 1) X return (TRUE); X if (n < 1) X return (FALSE); X s = forwline(TRUE,n-1); X if (s && curwp->w_dotp == curbp->b_linep) X s = backline(FALSE,1); X return s; } X atmark() { X return ((curwp->w_dotp == curwp->w_mkp) && X (curwp->w_doto == curwp->w_mko)); } X /* X * Swap the values of "." and "mark" in the current window. This is pretty X * easy, bacause all of the hard work gets done by the standard routine X * that moves the mark about. The only possible error is "no mark". X */ swapmark() { X register LINE *odotp; X register int odoto; X X if (curwp->w_mkp == NULL) { X mlwrite("No mark in this window"); X return (FALSE); X } X odotp = curwp->w_dotp; X odoto = curwp->w_doto; X curwp->w_dotp = curwp->w_mkp; X curwp->w_doto = curwp->w_mko; X curwp->w_mkp = odotp; X curwp->w_mko = odoto; X curwp->w_flag |= WFMOVE; X return (TRUE); } X X X #if NeWS /* SETCURSOR X * X * Mouse support function. Put the cursor to the requested location. X * The cursor will be put just after the last character of the line if X * requested past the line. The coordinates are expected in the command X * stream. X * In the case of multiple windows, the window indicated by the mouse X * is located and made the current window. X */ setcursor() { int row, col, pasteol ; register LINE *dlp; WINDOW *wp0 ; /* current window on entry */ X X row = tgetc() ; X col = tgetc() ; X /* find the window we are pointing to */ X wp0 = curwp ; X while ( row < curwp->w_toprow || X row > curwp->w_ntrows + curwp->w_toprow ) { X nextwind(FALSE,0) ; X if ( curwp == wp0 ) break ; /* full circle */ X } X /* move to the right row */ X row -= curwp->w_toprow ; X dlp = curwp->w_linep ; /* get pointer to 1st line */ X while ( row-- && (dlp != curbp->b_linep) ) dlp = lforw(dlp) ; X curwp->w_dotp = dlp ; /* set dot line pointer */ X X /* now move the dot over until near the requested column */ X curgoal = col ; /* a global for this ?? */ X curwp->w_doto = getgoal(dlp) ; X curwp->w_flag |= WFMOVE; X return (TRUE); } #endif SHAR_EOF chmod 0444 basic.c || echo 'restore of basic.c failed' Wc_c="`wc -c < 'basic.c'`" test 20335 -eq "$Wc_c" || echo 'basic.c: original size 20335, current size' "$Wc_c" # ============= bind.c ============== echo 'x - extracting bind.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'bind.c' && /* This file is for functions having to do with key bindings, X descriptions, help commands and startup file. X X written 11-feb-86 by Daniel Lawrence X */ X #include #include "estruct.h" #include "edef.h" #include "epath.h" X /* dummy prefix binding functions */ extern CMDFUNC f_cntl_af, f_cntl_xf, f_unarg, f_esc; X /* give me some help!!!! bring up a buffer and read the help file into it */ help(f, n) { X register WINDOW *wp; /* scaning pointer to windows */ X register BUFFER *bp; /* buffer pointer to help */ X char *fname; /* ptr to file returned by flook() */ X X /* first check if we are already here */ X bp = bfind("[Help]", OK_CREAT, BFSCRTCH); X if (bp == NULL) X return FALSE; X X if (bp->b_active == FALSE) { /* never been used */ X fname = flook(pathname[1], FL_ANYWHERE); X if (fname == NULL) { X mlwrite("[Sorry, can't find the help information]"); X zotbuf(bp); X return(FALSE); X } X /* and read the stuff in */ X if (readin(fname, 0, bp, TRUE) == FALSE || X popupbuff(bp) == FALSE) { X zotbuf(bp); X return(FALSE); X } X strcpy(bp->b_bname,"[Help]"); X sprintf(bp->b_fname, " %s %s",prognam,version); X bp->b_mode |= MDVIEW; X bp->b_mode &= ~MDEXACT; X bp->b_flag |= BFSCRTCH; X } X return swbuffer(bp); } X #if REBIND X deskey(f, n) /* describe the command for a certain key */ { X register int c; /* key to describe */ X register char *ptr; /* string pointer to scan output strings */ X char outseq[NSTRING]; /* output buffer for command sequence */ X char *kcod2prc(); X X /* prompt the user to type us a key to describe */ X mlwrite(": describe-key "); X X /* get the command sequence to describe X change it to something we can print as well */ X X /* check to see if we are executing a command line */ X if (clexec) { X char tok[NSTRING]; X macarg(tok); /* get the next token */ X c = prc2kcod(tok); X } else { X c = kbd_seq(); X } X kcod2prc(c, &outseq[0]); X X /* and dump it out */ X ostring(outseq); X ostring(" "); X X /* find the right ->function */ X if ((ptr = fnc2engl(kcod2fnc(c))) == NULL) X ptr = "Not Bound"; X X /* output the command sequence */ X ostring(ptr); } X /* bindkey: add a new key to the key binding table */ X bindkey(f, n) int f, n; /* command arguments [IGNORED] */ { X register int c; /* command key to bind */ X register CMDFUNC *kcmd; /* ptr to the requested function to bind to */ X register KBIND *kbp; /* pointer into a binding table */ X register int found; /* matched command flag */ X char outseq[80]; /* output buffer for keystroke sequence */ X char *fnp; X char *kbd_engl(); X char *kcod2prc(); X X /* prompt the user to type in a key to bind */ X mlwrite(": bind-to-key "); X X /* get the function name to bind it to */ #if NeWS X newsimmediateon() ; #endif X fnp = kbd_engl(); #if NeWS X newsimmediateoff() ; #endif X X if (fnp == NULL || (kcmd = engl2fnc(fnp)) == NULL) { X mlwrite("[No such function]"); X return(FALSE); X } X ostring(" "); X TTflush(); X X /* get the command sequence to bind */ X if (clexec) { X char tok[NSTRING]; X macarg(tok); /* get the next token */ X c = prc2kcod(tok); X } else { X /* perhaps we only want a single key, not a sequence */ X /* (see more comments below) */ X if ((kcmd == &f_cntl_af) || (kcmd == &f_cntl_xf) || X (kcmd == &f_unarg) || (kcmd == &f_esc)) X c = kbd_key(); X else X c = kbd_seq(); X } X X /* change it to something we can print as well */ X kcod2prc(c, &outseq[0]); X X /* and dump it out */ X ostring(outseq); X X /* if the function is a prefix key, i.e. we're changing the definition X of a prefix key, then they typed a dummy function name, which X has been translated into a dummy function pointer */ X if (kcmd == &f_cntl_af || kcmd == &f_cntl_xf || X kcmd == &f_unarg || kcmd == &f_esc) { X register CMDFUNC **cfp; X /* search for an existing binding for the prefix key */ X cfp = asciitbl; X found = FALSE; X for (cfp = asciitbl; cfp < &asciitbl[128]; cfp++) { X if (*cfp == kcmd) { X unbindchar(cfp - asciitbl); X break; X } X } X X /* reset the appropriate global prefix variable */ X if (kcmd == &f_cntl_af) X cntl_a = c; X if (kcmd == &f_cntl_xf) X cntl_x = c; X if (kcmd == &f_unarg) X reptc = c; X if (kcmd == &f_esc) X abortc = c; X } X X if ((c & (CTLA|SPEC|CTLX)) == 0) { X asciitbl[c] = kcmd; X } else { X for(kbp = kbindtbl; kbp->k_cmd && kbp->k_code != c; kbp++) X ; X if (kbp->k_cmd) { /* found it, change it in place */ X kbp->k_cmd = kcmd; X } else { X if (kbp >= &kbindtbl[NBINDS-1]) { X mlwrite("Prefixed binding table full"); X return(FALSE); X } X kbp->k_code = c; /* add keycode */ X kbp->k_cmd = kcmd; /* and func pointer */ X ++kbp; /* and make sure the next is null */ X kbp->k_code = 0; X kbp->k_cmd = NULL; X } X } X X return TRUE; } X /* unbindkey: delete a key from the key binding table */ X unbindkey(f, n) int f, n; /* command arguments [IGNORED] */ { X register int c; /* command key to unbind */ X char outseq[80]; /* output buffer for keystroke sequence */ X char *kcod2prc(); X X /* prompt the user to type in a key to unbind */ X mlwrite(": unbind-key "); X X /* get the command sequence to unbind */ X if (clexec) { X char tok[NSTRING]; X macarg(tok); /* get the next token */ X c = prc2kcod(tok); X } else { X c = kbd_seq(); X } X X /* change it to something we can print as well */ X kcod2prc(c, &outseq[0]); X X /* and dump it out */ X ostring(outseq); X X /* if it isn't bound, bitch */ X if (unbindchar(c) == FALSE) { X mlwrite("[Key not bound]"); X return(FALSE); X } X return(TRUE); } X unbindchar(c) int c; /* command key to unbind */ { X register KBIND *kbp; /* pointer into the command table */ X register KBIND *skbp; /* saved pointer into the command table */ X register int found; /* matched command flag */ X X if ((c & (CTLA|SPEC|CTLX)) == 0) { X asciitbl[c] = NULL; X } else { X /* search the table to see if the key exists */ X for (kbp = kbindtbl; kbp->k_cmd && kbp->k_code != c; kbp++) X ; X X /* if it isn't bound, bitch */ X if (kbp->k_cmd == NULL) X return(FALSE); X X /* save the pointer and scan to the end of the table */ X skbp = kbp; X while (kbp->k_cmd != NULL) X ++kbp; X --kbp; /* backup to the last legit entry */ X X /* copy the last entry to the current one */ X skbp->k_code = kbp->k_code; X skbp->k_cmd = kbp->k_cmd; X X /* null out the last one */ X kbp->k_code = 0; X kbp->k_cmd = NULL; X } X return TRUE; } X /* describe bindings bring up a fake buffer and list the key bindings X into it with view mode */ desbind(f, n) { X return mkblist(NULL); } X #if APROP apro(f, n) /* Apropos (List functions that match a substring) */ { X static char mstring[NSTRING] = 0; /* string to match cmd names to */ X register int s; X X X s = mlreply("Apropos string: ", mstring, NSTRING - 1); X if (s != TRUE) X return(s); X X return mkblist(mstring); } #endif X mkblist(mstring) char *mstring; { X register BUFFER *bp; X register int s; X X /* create the buffer list buffer */ X bp = bfind("[Binding List]", OK_CREAT, BFSCRTCH); X if (bp == NULL) X return FALSE; X X if ((s=bclear(bp)) != TRUE) /* clear old text (?) */ X return (s); X s = buildlist(mstring,bp); X if (s != TRUE || popupbuff(bp) == FALSE) { X mlwrite("[Sorry, can't list. ]"); X zotbuf(bp); X return (s); X } X strcpy(bp->b_fname, ""); X bp->b_mode |= MDVIEW; X bp->b_flag |= BFSCRTCH; X bp->b_flag &= ~BFCHG; /* Don't complain! */ X bp->b_active = TRUE; X X return TRUE; } X X /* build a binding list (limited or full) */ buildlist(mstring, bp) char *mstring; /* match string if partial list, NULL to list all */ register BUFFER *bp; /* buffer to put binding list into */ { #if ST520 & LATTICE #define register #endif X register WINDOW *wp; /* scanning pointer to windows */ X register KBIND *kbp; /* pointer into a key binding table */ X register CMDFUNC **cfp; /* pointer into the ascii table */ X register NTAB *nptr,*nptr2; /* pointer into the name table */ X char *strp; /* pointer int string to send */ X int cpos; /* current position to use in outseq */ X char outseq[81]; /* output buffer for keystroke sequence */ X int i,pass; X char *kcod2prc(); X X X /* let us know this is in progress */ X mlwrite("[Building binding list]"); X X /* build the contents of this window, inserting it line by line */ X for (pass = 0; pass < 2; pass++) { X for (nptr = nametbl; nptr->n_name != NULL; ++nptr) { X X /* if we've already described this one, move on */ X if (nptr->n_cmd->c_flags & LISTED) X continue; X X /* try to avoid alphabetizing by the real short names */ X if (pass == 0 && strlen(nptr->n_name) <= 2) X continue; X X /* add in the command name */ X strcpy(outseq,"\""); X strcat(outseq, nptr->n_name); X strcat(outseq,"\""); X cpos = strlen(outseq); X while (cpos < 32) X outseq[cpos++] = ' '; X outseq[cpos] = 0; X #if APROP X /* if we are executing an apropos command X and current string doesn't include the search string */ X if (mstring && (strinc(outseq, mstring) == FALSE)) X continue; #endif X /* look in the simple ascii binding table first */ X for(cfp = asciitbl, i = 0; cfp < &asciitbl[128]; cfp++, i++) { X if (*cfp == nptr->n_cmd) { X cpos = kcod2prc(i, &outseq[strlen(outseq)]) - X outseq; X while(cpos & 7) X outseq[cpos++] = ' '; X outseq[cpos] = '\0'; X } X } X /* then look in the multi-key table */ X for(kbp = kbindtbl; kbp->k_cmd; kbp++) { X if (kbp->k_cmd == nptr->n_cmd) { X cpos = X kcod2prc(kbp->k_code, &outseq[strlen(outseq)]) - X outseq; X while(cpos & 7) X outseq[cpos++] = ' '; X outseq[cpos] = '\0'; X } X } X /* dump the line */ X addline(bp,outseq,-1); X X cpos = 0; X X /* then look for synonyms */ X for (nptr2 = nametbl; nptr2->n_name != NULL; ++nptr2) { X /* if it's the one we're on, skip */ X if (nptr2 == nptr) X continue; X /* if it's already been listed, skip */ X if (nptr2->n_cmd->c_flags & LISTED) X continue; X /* if it's not a synonym, skip */ X if (nptr2->n_cmd != nptr->n_cmd) X continue; X while (cpos < 8) X outseq[cpos++] = ' '; X outseq[cpos] = '\0'; X strcat(outseq,"\""); X strcat(outseq,nptr2->n_name); X strcat(outseq,"\""); X addline(bp,outseq,-1); X cpos = 0; /* and clear the line */ X X } X X nptr->n_cmd->c_flags |= LISTED; /* mark it as already listed */ X } X } X X for (nptr = nametbl; nptr->n_name != NULL; ++nptr) X nptr->n_cmd->c_flags &= ~LISTED; /* mark it as unlisted */ X X mlwrite(""); /* clear the mode line */ X return(TRUE); } X #if APROP strinc(source, sub) /* does source include sub? */ char *source; /* string to search in */ char *sub; /* substring to look for */ { X char *sp; /* ptr into source */ X char *nxtsp; /* next ptr into source */ X char *tp; /* ptr into substring */ X X /* for each character in the source string */ X sp = source; X while (*sp) { X tp = sub; X nxtsp = sp; X X /* is the substring here? */ X while (*tp) { X if (*nxtsp++ != *tp) X break; X else X tp++; X } X X /* yes, return a success */ X if (*tp == 0) X return(TRUE); X X /* no, onward */ X sp++; X } X return(FALSE); } #endif X #endif /* REBIND */ X X /* execute the startup file */ X startup(sfname) char *sfname; /* name of startup file */ { X char *fname; /* resulting file name to execute */ X X /* look up the startup file */ X fname = flook(sfname, FL_HERE_HOME); X X /* if it isn't around, don't sweat it */ X if (fname == NULL) { X mlwrite("[Can't find startup file %s]",sfname); X return(TRUE); X } X X /* otherwise, execute the sucker */ X return(dofile(fname)); } X /* Look up the existence of a file along the normal or PATH X environment variable. Look first in the HOME directory if X asked and possible */ X char * flook(fname, hflag) char *fname; /* base file name to search for */ int hflag; /* Look in the HOME environment variable first? */ { X register char *home; /* path to home directory */ X register char *path; /* environmental PATH variable */ X register char *sp; /* pointer into path spec */ X register int i; /* index */ X static char fspec[NSTRING]; /* full path spec to search */ X char *getenv(); X X /* tak care of special cases */ X if (!fname || !fname[0] || isspace(fname[0])) X return NULL; X else if (fname[0] == '!') X return fname; X X /* always try the current directory first */ X if (ffropen(fname) == FIOSUC) { X ffclose(); X return(fname); X } X X if (hflag == FL_HERE) X return NULL; X #if ENVFUNC X X if (hflag) { X home = getenv("HOME"); X if (home != NULL) { X /* build home dir file spec */ X strcpy(fspec, home); X strcat(fspec, "/"); X strcat(fspec, fname); X X /* and try it out */ X if (ffropen(fspec) == FIOSUC) { X ffclose(); X return(fspec); X } X } X } X X if (hflag == FL_HERE_HOME) X return NULL; X #if PATHLOOK X /* get the PATH variable */ X path = getenv("PATH"); X if (path != NULL) X while (*path) { X X /* build next possible file spec */ X sp = fspec; X while (*path && (*path != PATHCHR)) X *sp++ = *path++; X *sp++ = '/'; X *sp = 0; X strcat(fspec, fname); X X /* and try it out */ X if (ffropen(fspec) == FIOSUC) { X ffclose(); X return(fspec); X } X X if (*path == PATHCHR) X ++path; X } #endif #endif X X /* look it up via the old table method */ X for (i=2; i < NPNAMES; i++) { X strcpy(fspec, pathname[i]); X strcat(fspec, fname); X X /* and try it out */ X if (ffropen(fspec) == FIOSUC) { X ffclose(); X return(fspec); X } X } X X X return NULL; /* no such luck */ } X /* translate a 10-bit keycode to its printable name (like "M-j") */ char * kcod2prc(c, seq) int c; /* sequence to translate */ char *seq; /* destination string for sequence */ { X char *ptr; /* pointer into current position in sequence */ X X ptr = seq; X X /* apply cntl_a sequence if needed */ X if (c & CTLA) { X *ptr++ = '^'; X *ptr++ = 'A'; X *ptr++ = '-'; X } X X /* apply ^X sequence if needed */ X if (c & CTLX) { X *ptr++ = '^'; X *ptr++ = 'X'; X *ptr++ = '-'; X } X X /* apply SPEC sequence if needed */ X if (c & SPEC) { X *ptr++ = 'F'; X *ptr++ = 'N'; X *ptr++ = '-'; X } X X c = kcod2key(c); X X /* apply control sequence if needed */ X if (iscntrl(c)) { X *ptr++ = '^'; X c = toalpha(c); X } X X /* and output the final sequence */ X X if (c == ' ') { X *ptr++ = '<'; X *ptr++ = 's'; X *ptr++ = 'p'; X *ptr++ = '>'; X } else if (c == '\t') { X *ptr++ = '<'; X *ptr++ = 't'; X *ptr++ = 'a'; X *ptr++ = 'b'; X *ptr++ = '>'; X } else { X *ptr++ = c; X } X *ptr = 0; /* terminate the string */ X return ptr; } X X /* kcod2fnc: translate a 10-bit keycode to a function pointer */ /* (look a key binding up in the binding table) */ CMDFUNC * kcod2fnc(c) int c; /* key to find what is bound to it */ { X register KBIND *kbp; X X if ((c & (CTLA|SPEC|CTLX)) == 0) { X return asciitbl[c]; X } else { X for (kbp = kbindtbl; kbp->k_cmd && kbp->k_code != c; kbp++) X ; X return kbp->k_cmd; X } } X X /* fnc2engl: translate a function pointer to the english name for X that function */ X char * fnc2engl(cfp) CMDFUNC *cfp; /* ptr to the requested function to bind to */ { X register NTAB *nptr; /* pointer into the name table */ X X /* skim through the table, looking for a match */ X for (nptr = nametbl; nptr->n_cmd; nptr++) { SHAR_EOF true || echo 'restore of bind.c failed' echo 'End of Vile part 1' echo 'File bind.c is continued in part 2' echo 2 > _shar_seq_.tmp exit 0 -- paul fox, pgf@cayman.com, (617)494-1999 Cayman Systems, 26 Landsdowne St., Cambridge, MA 02139