home *** CD-ROM | disk | FTP | other *** search
- From: pgf@cayman.COM (Paul Fox)
- Newsgroups: alt.sources
- Subject: Vile 12/17 - vi feel-alike (multi-window)
- Message-ID: <4531@cayman.COM>
- Date: 7 Jun 91 22:10:04 GMT
-
- #!/bin/sh
- # this is vileshar.12 (part 12 of Vile)
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file readme.news continued
- #
- if test ! -r _shar_seq_.tmp; then
- echo 'Please unpack part 1 first!'
- exit 1
- fi
- (read Scheck
- if test "$Scheck" != 12; then
- echo Please unpack part "$Scheck" next!
- exit 1
- else
- exit 0
- fi
- ) < _shar_seq_.tmp || exit 1
- echo 'x - continuing file readme.news'
- sed 's/^X//' << 'SHAR_EOF' >> 'readme.news' &&
- X buffers, windows, and files.
- X
- X The number of lines may be selected by the user when the editor is
- X invoked (-L40 for 40 lines), and the font size and the number of
- X columns is then set by the size of the window the user chooses
- X from the NeWS interface.
- X
- The primary distribution mechanism used to offload i/o is selective time
- buffering. Printable text is displayed locally as it is issued by the
- user, being flushed to the remote machine (where the actual editor is
- running) after a suitable period has elapsed during which no input is
- received. For normal text this period is 2 seconds. Commands (control
- characters and escape sequences) are also buffered in time, with a
- period of .4 seconds. Certain prefixes are also defined (^X and escape),
- so that these characters are assigned long timeouts and the following
- character a short timeout. The editor controls this timing data, and has
- the capability to throw the system into "immediate" mode, where every
- character is treated as a command. This is done temporarily to support
- the incremental search and query replace functions of emacs. The
- protocol puts an absolute upper bound on the number of packets that can
- be transmitted per second, which would be 1 every .4 seconds if the user
- entered commands at exactly that rate. Issuing commands at a faster or
- slower rate will improve the performance (reduce the packet load).
- X
- As local printable text is inserted, a different font is used to
- indicate that the remote machine has yet to confirm the entry. After a
- timeout has occurred and a packet of text and commands sent to the
- remote machine, the screen update will be done with the normal font.
- X
- Screen updates are optimized so that an update is done only when
- absolutely necessary. To help with apparent performance in low bandwidth
- situations, the remote display driver will search for and optimize out
- any scrolls or reverse scrolls. Essentially what has been implemented
- here (in a limited fashion) is a NeWS distributed implementation of
- curses, although as yet no attempt has been made to obey the syntax of
- curses.
- X
- The Mouse
- X
- The mouse is used to position the cursor and for cutting and pasting
- text. It should be used in preference to the motion keys because it is
- much more efficient, sending far fewer packets to the remote machine.
- It should not be used in keyboard macros however, as it's movement
- commands are not relative.
- X
- Text is entered at the block cursor, NOT the mouse cursor. To move the
- block cursor, move the mouse cursor to the desired position. After the
- mouse has been motionless for 1/5 second, the remote machine will adjust
- the block cursor to match the mouse position. While waiting for the
- remote machine to respond the mouse cursor takes the form of an
- hourglass, to indicate to the user that it is not safe to type. The
- alignment of cursors is not exact, since the text cursor positioning
- must take tabs into account and can't be placed past the end of a line.
- This is a feature, not a bug
- X
- The left mouse button is used for cutting out text. To cut out a block
- of text, move the mouse cursor to the starting location, press the left
- button and move the mouse to the ending location (keeping the button
- depressed). When the button is released the text will be wiped out
- (moved to the kill buffer). The middle mouse button will yank text from
- the kill buffer and insert it at the current (mouse cursor) location.
- The right mouse button invokes a walking menu. This mouse behavior is
- not in the standard Sunview style, and as a result it is not (yet)
- possible to exchange information between the editor and other NeWS
- applications.
- X
- Function Keys
- X
- The user is free to bind the function keys to various emacs commands. If
- this is done, it is recommended that the definitions be kept in a file
- named .emacsrc to avoid retyping them (the file ..emacsrc is
- automatically read when the editor is invoked). The function keys can
- also be redefined on the fly using the menu. The shift and control keys
- have no effect when used with the function keys.
- X
- Altering the definitions is only necessary if the default definitions
- are not satisfactory. The default definitions for the function keys are:
- X
- X top right
- X
- 1) find file page up
- 2) read file top of file
- 3) insert file reverse incremental search
- 4) view file page down
- 5) save file end of file
- 6) write file incremental search
- 7) rename file beginning of line
- 8) copy region cursor up
- 9) get argument end of line
- 10) cursor left
- 11) set mark
- 12) cursor right
- 13) previous word
- 14) cursor down
- 15) next word
- X
- X
- "Bugs" and Limitations
- X
- At present the distribution mechanism is ignorant of key rebindings,
- that is, the emacs rebinding function does not alter the timing
- information. Care should be taken when binding characters to keys. In
- particular, be careful not to rebind the emacs prefix keys ^X or ESC.
- Also, since the menu entries send "normal" emacs sequences, rebinding
- these sequences should be avoided. Function keys are available for
- binding.
- X
- If for some reason the editing process on the remote machine is killed
- by methods other than emacs commands, the window may not be eliminated
- (and NeWS might have to be restarted to get rid of it). Currently the
- only "correct" ways of terminating are with the window menu "quit" or
- "save & exit" choices, or with their equivalent emacs sequences (^X C
- and ESC Z). The frame or icon menu "Zap" function will also terminate
- the editor, but will not prompt the user for confirmation if changes
- have not been saved to files. Do not ^C or otherwise kill the remote
- editor.
- SHAR_EOF
- echo 'File readme.news is complete' &&
- chmod 0444 readme.news ||
- echo 'restore of readme.news failed'
- Wc_c="`wc -c < 'readme.news'`"
- test 7014 -eq "$Wc_c" ||
- echo 'readme.news: original size 7014, current size' "$Wc_c"
- # ============= region.c ==============
- echo 'x - extracting region.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'region.c' &&
- /*
- X * The routines in this file
- X * deal with the region, that magic space
- X * between "." and mark. Some functions are
- X * commands. Some functions are just for
- X * internal use.
- X */
- #include <stdio.h>
- #include "estruct.h"
- #include "edef.h"
- X
- #if MEGAMAX & ST520
- overlay "region"
- #endif
- X
- /*
- X * Kill the region. Ask "getregion"
- X * to figure out the bounds of the region.
- X * Move "." to the start, and kill the characters.
- X */
- killregion(f, n)
- {
- X register int s;
- X REGION region;
- X
- X if (curbp->b_mode&MDVIEW) /* don't allow this command if */
- X return(rdonly()); /* we are in read only mode */
- X if ((s=getregion(®ion)) != TRUE)
- X return (s);
- X kregcirculate(TRUE);
- X kdelete(); /* command, so do magic */
- X curwp->w_dotp = region.r_linep;
- X curwp->w_doto = region.r_offset;
- X if (fulllineregions)
- X kregflag |= KLINES;
- X s = ldelete(region.r_size, TRUE);
- X ukb = 0;
- X return (s);
- }
- X
- /*
- X * Copy all of the characters in the
- X * region to the kill buffer. Don't move dot
- X * at all. This is a bit like a kill region followed
- X * by a yank.
- X */
- yankregion(f, n)
- {
- X register LINE *linep;
- X register int loffs;
- X register int s;
- X REGION region;
- X
- X if ((s=getregion(®ion)) != TRUE)
- X return (s);
- X kregcirculate(TRUE);
- X kdelete();
- X linep = region.r_linep; /* Current line. */
- X loffs = region.r_offset; /* Current offset. */
- X if (fulllineregions)
- X kregflag |= KLINES|KYANK;
- X while (region.r_size--) {
- X if (loffs == llength(linep)) { /* End of line. */
- X if ((s=kinsert('\n')) != TRUE) {
- X ukb = 0;
- X return (s);
- X }
- X linep = lforw(linep);
- X loffs = 0;
- X } else { /* Middle of line. */
- X if ((s=kinsert(lgetc(linep, loffs))) != TRUE) {
- X ukb = 0;
- X return (s);
- X }
- X ++loffs;
- X }
- X }
- X mlwrite("[region yanked]");
- X ukb = 0;
- X return (TRUE);
- }
- X
- /*
- X * shift region left by a tab stop
- X */
- shiftrregion(f, n)
- {
- X register LINE *linep;
- X register int loffs;
- X register int s;
- X REGION region;
- X
- X if (curbp->b_mode&MDVIEW) /* don't allow this command if */
- X return(rdonly()); /* we are in read only mode */
- X if ((s=getregion(®ion)) != TRUE)
- X return (s);
- X linep = region.r_linep;
- X loffs = region.r_offset;
- X if (loffs != 0) { /* possibly on first time through */
- X region.r_size -= llength(linep)-loffs+1;
- X loffs = 0;
- X linep = lforw(linep);
- X }
- X s = TRUE;
- X while (region.r_size > 0) {
- X /* adjust r_size now, while line length is right */
- X region.r_size -= llength(linep)+1;
- X if (llength(linep) != 0) {
- X curwp->w_dotp = linep;
- X curwp->w_doto = 0;
- X if ((s = linsert(1,'\t')) != TRUE)
- X return (s);
- X }
- X linep = lforw(linep);
- X }
- X firstnonwhite(f,n);
- X return (TRUE);
- }
- X
- /*
- X * shift region left by a tab stop
- X */
- shiftlregion(f, n)
- {
- X register LINE *linep;
- X register int loffs;
- X register int c;
- X register int s;
- X register int i;
- X REGION region;
- X
- X if (curbp->b_mode&MDVIEW) /* don't allow this command if */
- X return(rdonly()); /* we are in read only mode */
- X if ((s=getregion(®ion)) != TRUE)
- X return (s);
- X linep = region.r_linep;
- X loffs = region.r_offset;
- X if (loffs != 0) { /* possibly on first time through */
- X region.r_size -= llength(linep)-loffs+1;
- X loffs = 0;
- X linep = lforw(linep);
- X }
- X s = TRUE;
- X while (region.r_size > 0) {
- X /* adjust r_size now, while line length is right */
- X region.r_size -= llength(linep)+1;
- X if (llength(linep) != 0) {
- X curwp->w_dotp = linep;
- X curwp->w_doto = 0;
- X if ((c = lgetc(linep,0)) == '\t') { /* delete the tab */
- X i = 1;
- X } else if (c == ' ') {
- X i = 1;
- X /* after this, i'th char is _not_ a space,
- X or 0-7 are spaces */
- X while ((c = lgetc(linep,i)) == ' ' && i < TABVAL)
- X i++;
- X if (i != TABVAL && c == '\t') /* ith char is tab */
- X i++;
- X } else {
- X i = 0;
- X }
- X
- X if ( i!=0 && (s = ldelete((long)i,FALSE)) != TRUE)
- X return (s);
- X }
- X linep = lforw(linep);
- X }
- X firstnonwhite(f,n);
- X return (TRUE);
- }
- X
- _to_lower(c)
- {
- X if (isupper(c))
- X return(c ^ DIFCASE);
- X return -1;
- }
- X
- _to_upper(c)
- {
- X if (islower(c))
- X return(c ^ DIFCASE);
- X return -1;
- }
- X
- _to_caseflip(c)
- {
- X if (isalpha(c))
- X return(c ^ DIFCASE);
- X return -1;
- }
- X
- flipregion(f, n)
- {
- X return charprocreg(f,n,_to_caseflip);
- }
- X
- lowerregion(f, n)
- {
- X return charprocreg(f,n,_to_lower);
- }
- X
- upperregion(f, n)
- {
- X return charprocreg(f,n,_to_upper);
- }
- X
- charprocreg(f, n, func)
- int (*func)();
- {
- X register LINE *linep;
- X register int loffs;
- X register int c,nc;
- X register int s;
- X REGION region;
- X
- X if (curbp->b_mode&MDVIEW) /* don't allow this command if */
- X return(rdonly()); /* we are in read only mode */
- X if ((s=getregion(®ion)) != TRUE)
- X return (s);
- X lchange(WFHARD);
- X linep = region.r_linep;
- X loffs = region.r_offset;
- X while (region.r_size--) {
- X if (loffs == llength(linep)) {
- X linep = lforw(linep);
- X loffs = 0;
- X } else {
- X c = lgetc(linep, loffs);
- X nc = (func)(c);
- X if (nc != -1) {
- X copy_for_undo(linep);
- X lputc(linep, loffs, nc);
- X }
- X ++loffs;
- X }
- X }
- X return (TRUE);
- }
- X
- /*
- X * This routine figures out the
- X * bounds of the region in the current window, and
- X * fills in the fields of the "REGION" structure pointed
- X * to by "rp". Because the dot and mark are usually very
- X * close together, we scan outward from dot looking for
- X * mark. This should save time. Return a standard code.
- X */
- getregion(rp)
- register REGION *rp;
- {
- X register LINE *flp;
- X register LINE *blp;
- X long fsize;
- X long bsize;
- X
- X if (curwp->w_mkp == NULL) {
- X mlwrite("No mark set in this window");
- X return FALSE;
- X }
- X if (curwp->w_dotp == curwp->w_mkp) {
- X rp->r_linep = curwp->w_dotp;
- X if (fulllineregions) {
- X rp->r_offset = 0;
- X rp->r_size = (long)llength(curwp->w_dotp)+1;
- X rp->r_endlinep = lforw(curwp->w_dotp);
- X rp->r_endoffset = 0;
- X return TRUE;
- X }
- X rp->r_endlinep = curwp->w_dotp;
- X if (curwp->w_doto < curwp->w_mko) {
- X rp->r_offset = curwp->w_doto;
- X rp->r_size = (long)(curwp->w_mko-curwp->w_doto);
- X rp->r_endoffset = curwp->w_mko;
- X } else {
- X rp->r_offset = curwp->w_mko;
- X rp->r_size = (long)(curwp->w_doto-curwp->w_mko);
- X rp->r_endoffset = curwp->w_doto;
- X }
- X return TRUE;
- X }
- X blp = curwp->w_dotp;
- X flp = curwp->w_dotp;
- X if (fulllineregions) {
- X bsize = (long)(llength(blp)+1);
- X fsize = (long)(llength(flp)+1);
- X } else {
- X bsize = (long)curwp->w_doto;
- X fsize = (long)(llength(flp)-curwp->w_doto+1);
- X }
- X while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) {
- X if (flp != curbp->b_linep) {
- X flp = lforw(flp);
- X if (flp == curwp->w_mkp) {
- X rp->r_linep = curwp->w_dotp;
- X if (fulllineregions) {
- X rp->r_offset = 0;
- X rp->r_size = fsize+
- X llength(curwp->w_mkp)+1;
- X rp->r_endlinep = lforw(flp);
- X rp->r_endoffset = 0;
- X return TRUE;
- X }
- X rp->r_offset = curwp->w_doto;
- X rp->r_size = fsize+curwp->w_mko;
- X rp->r_endlinep = flp;
- X rp->r_endoffset = curwp->w_mko;
- X return TRUE;
- X }
- X fsize += llength(flp)+1;
- X }
- X if (lback(blp) != curbp->b_linep) {
- X blp = lback(blp);
- X bsize += llength(blp)+1;
- X if (blp == curwp->w_mkp) {
- X rp->r_linep = blp;
- X if (fulllineregions) {
- X rp->r_offset = 0;
- X rp->r_size = bsize;
- X rp->r_endlinep = lforw(curwp->w_dotp);
- X rp->r_endoffset = 0;
- X return TRUE;
- X }
- X rp->r_endlinep = curwp->w_dotp;
- X rp->r_endoffset = curwp->w_doto;
- X rp->r_offset = curwp->w_mko;
- X rp->r_size = bsize - curwp->w_mko;
- X return TRUE;
- X }
- X }
- X }
- X mlwrite("Bug: lost mark");
- X return FALSE;
- }
- X
- SHAR_EOF
- chmod 0444 region.c ||
- echo 'restore of region.c failed'
- Wc_c="`wc -c < 'region.c'`"
- test 9127 -eq "$Wc_c" ||
- echo 'region.c: original size 9127, current size' "$Wc_c"
- # ============= search.c ==============
- echo 'x - extracting search.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'search.c' &&
- /*
- X * The functions in this file implement commands that search in the forward
- X * and backward directions.
- X * heavily modified by Paul Fox, 1990
- X *
- X * Aug. 1986 John M. Gamble:
- X * ... a limited number of regular expressions - 'any',
- X * 'character class', 'closure', 'beginning of line', and
- X * 'end of line'.
- X *
- X * Replacement metacharacters will have to wait for a re-write of
- X * the replaces function, and a new variation of ldelete().
- X *
- X * For those curious as to my references, i made use of
- X * Kernighan & Plauger's "Software Tools."
- X * I deliberately did not look at any published grep or editor
- X * source (aside from this one) for inspiration. I did make use of
- X * Allen Hollub's bitmap routines as published in Doctor Dobb's Journal,
- X * June, 1985 and modified them for the limited needs of character class
- X * matching. Any inefficiences, bugs, stupid coding examples, etc.,
- X * are therefore my own responsibility.
- X *
- X */
- X
- #include <stdio.h>
- #include "estruct.h"
- #include "edef.h"
- X
- #if LATTICE
- #define void int
- #endif
- X
- int mcmatch();
- int readpattern();
- #if SEARCH_AND_REPLACE
- int replaces();
- #endif
- int nextch();
- #if MAGIC
- int mcstr();
- int mceq();
- int cclmake();
- int biteq();
- BITMAP clearbits();
- void setbit();
- #endif
- X
- int lastdirec;
- LINE *boundline;
- int boundoff;
- X
- scrforwsearch(f,n)
- {
- X return fsearch(f,n,FALSE,TRUE);
- }
- X
- scrbacksearch(f,n)
- {
- X return bsearch(f,n,FALSE,TRUE);
- }
- X
- char onlyonemsg[] = "Only one occurence of pattern";
- char notfoundmsg[] = "Not found";
- X
- /*
- X * forwsearch -- Search forward. Get a search string from the user, and
- X * search for the string. If found, reset the "." to be just after
- X * the match string, and (perhaps) repaint the display.
- X */
- X
- forwsearch(f, n)
- int f, n;
- {
- X fsearch(f, n, FALSE, NULL);
- }
- X
- /* extra args -- marking if called from globals, and should mark lines, and
- X fromscreen, if the searchpattern is on the screen, so we don't need to
- X ask for it. */
- fsearch(f, n, marking, fromscreen)
- int f, n;
- {
- X register int status = TRUE;
- X int wrapok;
- X int c;
- X LINE *curdotp;
- X int curoff;
- X int didmark = FALSE;
- X
- X if (f && n < 0)
- X return bsearch(f, -n, NULL, NULL);
- X
- X wrapok = marking || (curwp->w_bufp->b_mode & MDSWRAP) != 0;
- X
- X lastdirec = 0;
- X
- X /* Ask the user for the text of a pattern. If the
- X * response is TRUE (responses other than FALSE are
- X * possible), search for the pattern for as long as
- X * n is positive (n == 0 will go through once, which
- X * is just fine).
- X *
- X * If "marking", then we were called to do line marking for the
- X * global command.
- X */
- X if (!marking && (status = readpattern("Search: ", &pat[0],
- X TRUE, lastkey, fromscreen)) != TRUE) {
- X return status;
- X }
- X
- X curdotp = curwp->w_dotp;
- X curoff = curwp->w_doto;
- X setboundry(wrapok,curwp->w_dotp,curwp->w_doto,FORWARD);
- X do {
- X nextch(&(curwp->w_dotp),&(curwp->w_doto), FORWARD,wrapok);
- X status = thescanner(&pat[0], FORWARD, PTBEG, wrapok);
- X if (status == ABORT) {
- X TTbeep();
- X mlwrite("[Aborted]");
- X curwp->w_dotp = curdotp;
- X curwp->w_doto = curoff;
- X return status;
- X }
- X /* if found, mark the line */
- X if (status && marking) {
- X /* if we were on a match when we started, then
- X thescanner returns TRUE, even though it's
- X on a boundary. quit if we find ourselves
- X marking a line twice */
- X if (lismarked(curwp->w_dotp))
- X break;
- X lsetmarked(curwp->w_dotp);
- X /* and, so the next nextch gets to next line */
- X curwp->w_doto = llength(curwp->w_dotp);
- X didmark = TRUE;
- X }
- X } while ((marking || --n > 0) && status == TRUE);
- X
- X if (!marking && !status)
- X nextch(&(curwp->w_dotp),&(curwp->w_doto), REVERSE,wrapok);
- X
- X if (marking) { /* restore dot and offset */
- X curwp->w_dotp = curdotp;
- X curwp->w_doto = curoff;
- X } else if (status) {
- X savematch();
- X if (curwp->w_dotp == curdotp && curwp->w_doto == curoff) {
- X mlwrite(onlyonemsg);
- X TTbeep();
- X }
- X }
- X
- X /* Complain if not there. */
- X if ((marking && didmark == FALSE) ||
- X (!marking && status == FALSE)) {
- X mlwrite(notfoundmsg);
- X TTbeep();
- X return FALSE;
- X }
- X
- X return TRUE;
- }
- X
- /*
- X * forwhunt -- Search forward for a previously acquired search string.
- X * If found, reset the "." to be just after the match string,
- X * and (perhaps) repaint the display.
- X */
- X
- forwhunt(f, n)
- int f, n; /* default flag / numeric argument */
- {
- X register int status = TRUE;
- X int wrapok;
- X LINE *curdotp;
- X int curoff;
- X
- X wrapok = (curwp->w_bufp->b_mode & MDSWRAP) != 0;
- X
- X if (n < 0) /* search backwards */
- X return(backhunt(f, -n));
- X
- X /* Make sure a pattern exists, or that we didn't switch
- X * into MAGIC mode until after we entered the pattern.
- X */
- X if (pat[0] == '\0')
- X {
- X mlwrite("No pattern set");
- X return FALSE;
- X }
- X /* mlwrite("Searching ahead..."); */
- #if MAGIC
- X if ((curwp->w_bufp->b_mode & MDMAGIC) && (mcpat[0].mc_type == MCNIL))
- X {
- X if (!mcstr())
- X return FALSE;
- X }
- #endif
- X
- X /* Search for the pattern for as long as
- X * n is positive (n == 0 will go through once, which
- X * is just fine).
- X */
- X curdotp = curwp->w_dotp;
- X curoff = curwp->w_doto;
- X setboundry(wrapok,curwp->w_dotp,curwp->w_doto,FORWARD);
- X do {
- X nextch(&(curwp->w_dotp),&(curwp->w_doto),FORWARD,wrapok);
- X status = thescanner(&pat[0], FORWARD, PTBEG, wrapok);
- X } while ((--n > 0) && status == TRUE);
- X
- X /* Save away the match, or complain if not there. */
- X if (status == TRUE) {
- X savematch();
- X if (curwp->w_dotp == curdotp && curwp->w_doto == curoff) {
- X mlwrite(onlyonemsg);
- X TTbeep();
- X }
- X } else if (status == FALSE) {
- X nextch(&(curwp->w_dotp),&(curwp->w_doto),REVERSE,wrapok);
- X mlwrite(notfoundmsg);
- X TTbeep();
- X } else if (status == ABORT) {
- X TTbeep();
- X mlwrite("[Aborted]");
- X curwp->w_dotp = curdotp;
- X curwp->w_doto = curoff;
- X return status;
- X }
- X
- X return(status);
- }
- X
- /*
- X * backsearch -- Reverse search. Get a search string from the user, and
- X * search, starting at "." and proceeding toward the front of the buffer.
- X * If found "." is left pointing at the first character of the pattern
- X * (the last character that was matched).
- X */
- backsearch(f, n)
- int f, n;
- {
- X return bsearch(f, n, FALSE, NULL);
- }
- X
- bsearch(f, n, dummy, fromscreen)
- int f, n; /* default flag / numeric argument */
- {
- X register int status = TRUE;
- X int wrapok;
- X LINE *curdotp;
- X int curoff;
- X
- X if (n < 0)
- X return fsearch(f, -n, NULL, fromscreen);
- X
- X wrapok = (curwp->w_bufp->b_mode & MDSWRAP) != 0;
- X
- X lastdirec = 1;
- X
- X /* Ask the user for the text of a pattern. If the
- X * response is TRUE (responses other than FALSE are
- X * possible), search for the pattern for as long as
- X * n is positive (n == 0 will go through once, which
- X * is just fine).
- X */
- X if ((status = readpattern("Reverse search: ", &pat[0],
- X TRUE, lastkey, fromscreen)) == TRUE) {
- X curdotp = curwp->w_dotp;
- X curoff = curwp->w_doto;
- X setboundry(wrapok,curwp->w_dotp,curwp->w_doto,REVERSE);
- X do {
- X nextch(&(curwp->w_dotp),&(curwp->w_doto),REVERSE,
- X wrapok);
- X status = thescanner(&tap[0], REVERSE, PTBEG, wrapok);
- X } while ((--n > 0) && status == TRUE);
- X
- X /* Save away the match, or complain if not there. */
- X if (status == TRUE)
- X savematch();
- X if (curwp->w_dotp == curdotp && curwp->w_doto == curoff) {
- X mlwrite(onlyonemsg);
- X TTbeep();
- X }
- X else if (status == FALSE) {
- X nextch(&(curwp->w_dotp),&(curwp->w_doto),FORWARD,
- X wrapok);
- X mlwrite(notfoundmsg);
- X TTbeep();
- X } else if (status == ABORT) {
- X TTbeep();
- X mlwrite("[Aborted]");
- X curwp->w_dotp = curdotp;
- X curwp->w_doto = curoff;
- X return status;
- X }
- X }
- X return(status);
- }
- X
- /*
- X * backhunt -- Reverse search for a previously acquired search string,
- X * starting at "." and proceeding toward the front of the buffer.
- X * If found "." is left pointing at the first character of the pattern
- X * (the last character that was matched).
- X */
- backhunt(f, n)
- int f, n; /* default flag / numeric argument */
- {
- X register int status = TRUE;
- X int wrapok;
- X LINE *curdotp;
- X int curoff;
- X
- X wrapok = (curwp->w_bufp->b_mode & MDSWRAP) != 0;
- X
- X if (n < 0)
- X return(forwhunt(f, -n));
- X
- X /* Make sure a pattern exists, or that we didn't switch
- X * into MAGIC mode until after we entered the pattern.
- X */
- X if (tap[0] == '\0')
- X {
- X mlwrite("No pattern set");
- X return FALSE;
- X }
- X /* mlwrite("Searching back..."); */
- #if MAGIC
- X if ((curwp->w_bufp->b_mode & MDMAGIC) && (tapcm[0].mc_type == MCNIL))
- X {
- X if (!mcstr())
- X return FALSE;
- X }
- #endif
- X
- X /* Go search for it for as long as
- X * n is positive (n == 0 will go through once, which
- X * is just fine).
- X */
- X
- X curdotp = curwp->w_dotp;
- X curoff = curwp->w_doto;
- X setboundry(wrapok,curwp->w_dotp,curwp->w_doto,REVERSE);
- X do {
- X nextch(&(curwp->w_dotp),&(curwp->w_doto),REVERSE,wrapok);
- X status = thescanner(&tap[0], REVERSE, PTBEG, wrapok);
- X } while ((--n > 0) && status == TRUE);
- X
- X /* Save away the match, or complain
- X * if not there.
- X */
- X if (status == TRUE) {
- X savematch();
- X if (curwp->w_dotp == curdotp && curwp->w_doto == curoff) {
- X mlwrite(onlyonemsg);
- X TTbeep();
- X }
- X } else if (status == FALSE) {
- X nextch(&(curwp->w_dotp),&(curwp->w_doto), FORWARD,wrapok);
- X mlwrite(notfoundmsg);
- X TTbeep();
- X } else if (status == ABORT) {
- X TTbeep();
- X mlwrite("[Aborted]");
- X curwp->w_dotp = curdotp;
- X curwp->w_doto = curoff;
- X return status;
- X }
- X
- X return(status);
- }
- X
- consearch(f,n)
- {
- X if (lastdirec == 0)
- X return(forwhunt(f,n));
- X else
- X return(backhunt(f,n));
- }
- X
- revsearch(f,n)
- {
- X if (lastdirec == 0)
- X return(backhunt(f,n));
- X else
- X return(forwhunt(f,n));
- }
- X
- X
- /*
- X * thescanner -- Search for a pattern in either direction. If found,
- X * reset the "." to be at the start or just after the match string,
- X * and (perhaps) repaint the display.
- X */
- int
- thescanner(patrn, direct, beg_or_end, wrapok)
- char *patrn; /* pointer into pattern */
- int direct; /* which way to go.*/
- int beg_or_end; /* put point at beginning or end of pattern.*/
- {
- X LINE *curline; /* current line during scan */
- X int curoff; /* position within current line */
- X int found;
- X int (*matcher)();
- X int mcmatch();
- X int litmatch();
- X
- X /* If we are going in reverse, then the 'end' is actually
- X * the beginning of the pattern. Toggle it.
- X */
- X beg_or_end ^= direct;
- X
- X /*
- X * Save the old matchlen length, in case it is
- X * horribly different (closure) from the old length.
- X * This is terribly important for query-replace undo
- X * command.
- X */
- X mlenold = matchlen;
- X
- X /* Setup local scan pointers to global ".".
- X */
- X curline = curwp->w_dotp;
- X curoff = curwp->w_doto;
- #if MAGIC
- X if (magical && (curwp->w_bufp->b_mode & MDMAGIC)) {
- X matcher = mcmatch;
- X if (direct == FORWARD)
- X patrn = (char *)mcpat;
- X else
- X patrn = (char *)tapcm;
- X } else
- #endif
- X {
- X matcher = litmatch;
- X if (direct == FORWARD)
- X patrn = pat;
- X else
- X patrn = tap;
- X }
- X
- X /* Scan each character until we hit the head link record.
- X */
- X do {
- X if (interrupted) return ABORT;
- X
- X /* Save the current position in case we need to
- X * restore it on a match, and initialize matchlen to
- X * zero in case we are doing a search for replacement.
- X */
- X matchline = curline;
- X matchoff = curoff;
- X matchlen = 0;
- X
- X if ((*matcher)(patrn, direct, &curline, &curoff)) {
- X /* A SUCCESSFULL MATCH!!!
- X * reset the global "." pointers.
- X */
- X if (beg_or_end == PTEND) /* at end of string */
- X {
- X curwp->w_dotp = curline;
- X curwp->w_doto = curoff;
- X }
- X else /* at beginning of string */
- X {
- X curwp->w_dotp = matchline;
- X curwp->w_doto = matchoff;
- X }
- X
- X curwp->w_flag |= WFMOVE; /* flag that we have moved */
- X return TRUE;
- X }
- X
- X /* Advance the cursor.
- X */
- X nextch(&curline, &curoff, direct,wrapok);
- X } while (!boundry(curline, curoff, direct, wrapok));
- X
- X return FALSE; /* We could not find a match.*/
- }
- X
- #if MAGIC
- /*
- X * mcmatch -- Search for a meta-pattern in either direction. Based on the
- X * recursive routine amatch() (for "anchored match") in
- X * Kernighan & Plauger's "Software Tools".
- X */
- mcmatch(mcptr, direct, pcwline, pcwoff)
- register MC *mcptr; /* string to scan for */
- int direct; /* which way to go.*/
- LINE **pcwline; /* current line during scan */
- int *pcwoff; /* position within current line */
- {
- X register int c; /* character at current position */
- X LINE *curline; /* current line during scan */
- X int curoff; /* position within current line */
- X int nchars;
- X
- X /* Set up local scan pointers to ".", and get
- X * the current character. Then loop around
- X * the pattern pointer until success or failure.
- X */
- X curline = *pcwline;
- X curoff = *pcwoff;
- X
- X /* The beginning-of-line and end-of-line metacharacters
- X * do not compare against characters, they compare
- X * against positions.
- X * BOL is guaranteed to be at the start of the pattern
- X * for forward searches, and at the end of the pattern
- X * for reverse searches. The reverse is true for EOL.
- X * So, for a start, we check for them on entry.
- X */
- X if (mcptr->mc_type == BOL)
- X {
- X if (curoff != 0)
- X return FALSE;
- X mcptr++;
- X }
- X
- X if (mcptr->mc_type == EOL)
- X {
- X if (curoff != llength(curline))
- X return FALSE;
- X mcptr++;
- X }
- X
- X while (mcptr->mc_type != MCNIL)
- X {
- X c = nextch(&curline, &curoff, direct, FALSE);
- X
- X if (mcptr->mc_type & CLOSURE)
- X {
- X /* Try to match as many characters as possible
- X * against the current meta-character. A
- X * newline or boundary never matches a closure.
- X */
- X nchars = 0;
- X while (c != '\n' && c != -1 && mceq(c, mcptr))
- X {
- X nchars++;
- X c = nextch(&curline, &curoff, direct, FALSE);
- X }
- X
- X /* We are now at the character that made us
- X * fail. nchars is the number of successful
- X * matches. Try to match the rest of the pattern.
- X * Shrink the closure by one for each failure.
- X * Since closure matches *zero* or more occurences
- X * of a pattern, a match may start even if the
- X * previous loop matched no characters.
- X */
- X mcptr++;
- X
- X for (;;)
- X {
- X /* back up, since mcmatch goes forward first */
- X (void)nextch(&curline, &curoff,
- X direct ^ REVERSE, FALSE);
- X
- X if (mcmatch(mcptr, direct, &curline, &curoff))
- X {
- X matchlen += nchars;
- X goto success;
- X }
- X
- X if (nchars-- == 0)
- X return FALSE;
- X }
- X }
- X else /* Not closure.*/
- X {
- X /* The only way we'd get a BOL metacharacter
- X * at this point is at the end of the reversed pattern.
- X * The only way we'd get an EOL metacharacter
- X * here is at the end of a regular pattern.
- X * So if we match one or the other, and are at
- X * the appropriate position, we are guaranteed success
- X * (since the next pattern character has to be MCNIL).
- X * Before we report success, however, we back up by
- X * one character, so as to leave the cursor in the
- X * correct position. For example, a search for ")$"
- X * will leave the cursor at the end of the line, while
- X * a search for ")<NL>" will leave the cursor at the
- X * beginning of the next line. This follows the
- X * notion that the meta-character '$' (and likewise
- X * '^') match positions, not characters.
- X */
- X if (mcptr->mc_type == BOL)
- X {
- X if (curoff == llength(curline))
- X {
- X (void)nextch(&curline, &curoff,
- X direct ^ REVERSE, FALSE);
- X goto success;
- X }
- X else
- X {
- X return FALSE;
- X }
- X }
- X if (mcptr->mc_type == EOL)
- X {
- X if (curoff == 0)
- X {
- X (void)nextch(&curline, &curoff,
- X direct ^ REVERSE, FALSE);
- X goto success;
- X }
- X else
- X {
- X return FALSE;
- X }
- X }
- X
- X
- X /* Neither BOL nor EOL, so go through
- X * the meta-character equal function.
- X */
- X if (!mceq(c, mcptr))
- X return FALSE;
- X }
- X
- X /* Increment the length counter and
- X * advance the pattern pointer.
- X */
- X matchlen++;
- X mcptr++;
- X } /* End of mcptr loop.*/
- X
- X /* A SUCCESSFULL MATCH!!!
- X * Reset the "." pointers.
- X */
- success:
- X *pcwline = curline;
- X *pcwoff = curoff;
- X
- X
- X return TRUE;
- }
- #endif
- X
- /*
- X * litmatch -- Search for a literal match in either direction.
- X */
- litmatch(patptr, direct, pcwline, pcwoff)
- register char *patptr; /* string to scan for */
- int direct; /* which way to go.*/
- LINE **pcwline; /* current line during scan */
- int *pcwoff; /* position within current line */
- {
- X register int c; /* character at current position */
- X LINE *curline; /* current line during scan */
- X int curoff; /* position within current line */
- X
- X /* Set up local scan pointers to ".", and get
- X * the current character. Then loop around
- X * the pattern pointer until success or failure.
- X */
- X curline = *pcwline;
- X curoff = *pcwoff;
- X
- X while (*patptr != '\0') {
- X c = nextch(&curline, &curoff, direct, FALSE);
- X
- X if (!eq(c, *patptr))
- X return FALSE;
- X
- X /* Increment the length counter and
- X * advance the pattern pointer.
- X */
- X matchlen++;
- X patptr++;
- X }
- X
- X *pcwline = curline;
- X *pcwoff = curoff;
- X
- X
- X return TRUE;
- }
- X
- X
- /*
- X * eq -- Compare two characters. The "bc" comes from the buffer, "pc"
- X * from the pattern. If we are not in EXACT mode, fold out the case.
- X */
- int
- eq(bc, pc)
- register char bc;
- register char pc;
- {
- X if (curwp->w_bufp->b_mode & MDEXACT)
- X return (bc ^ pc) == 0;
- X /* take out the bit that makes upper and lowercase different */
- X return ((bc ^ pc) & ~DIFCASE) == 0;
- }
- X
- scrsearchpat(f,n)
- {
- X int s;
- X s = readpattern("", pat, TRUE, 0, TRUE);
- X mlwrite("Search pattern is now %s", pat);
- X lastdirec = 0;
- X return s;
- }
- /*
- X * readpattern -- Read a pattern. Stash it in apat. If it is the
- X * search string, create the reverse pattern and the magic
- X * pattern, assuming we are in MAGIC mode (and defined that way).
- X * Apat is not updated if the user types in an empty line. If
- X * the user typed an empty line, and there is no old pattern, it is
- X * an error. Display the old pattern, in the style of Jeff Lomicka.
- X * There is some do-it-yourself control expansion.
- X * An alternate termination character is passed in.
- X */
- readpattern(prompt, apat, srch, c, fromscreen)
- char *prompt;
- char *apat;
- int srch;
- int fromscreen;
- {
- X int status;
- X
- X /* Read a pattern. Either we get one,
- X * or we just get the META charater, and use the previous pattern.
- X * Then, if it's the search string, make a reversed pattern.
- X * *Then*, make the meta-pattern, if we are defined that way.
- X */
- X if (fromscreen) {
- X status = screen_string(apat, NPAT, _ident);
- X if (status != TRUE)
- X return status;
- X } else {
- X status = kbd_string(prompt, apat, NPAT, c, NO_EXPAND);
- X }
- X if (status == TRUE) {
- X if (srch) { /* If we are doing the search string.*/
- X mlenold = matchlen = strlen(apat);
- X /* Reverse string copy.
- X */
- X rvstrcpy(tap, apat);
- #if MAGIC
- X /* Only make the meta-pattern if in magic mode,
- X * since the pattern in question might have an
- X * invalid meta combination.
- X */
- X if ((curwp->w_bufp->b_mode & MDMAGIC) == 0)
- X mcclear();
- X else
- X status = mcstr();
- #endif
- X }
- X } else if (status == FALSE && *apat != 0) { /* Old one */
- X status = TRUE;
- X }
- X
- X return status;
- }
- X
- /*
- X * savematch -- We found the pattern? Let's save it away.
- X */
- X
- savematch()
- {
- X register char *ptr; /* ptr into malloced last match string */
- X register int j; /* index */
- X LINE *curline; /* line of last match */
- X int curoff; /* offset " " */
- X
- X /* free any existing match string */
- X if (patmatch != NULL)
- X free(patmatch);
- X
- X /* attempt to allocate a new one */
- X ptr = patmatch = malloc(matchlen + 1);
- X if (ptr == NULL)
- X return;
- X
- X /* save the match! */
- X curoff = matchoff;
- X curline = matchline;
- X
- X for (j = 0; j < matchlen; j++)
- X *ptr++ = nextch(&curline, &curoff, FORWARD, FALSE);
- X
- X /* null terminate the match string */
- X *ptr = '\0';
- }
- X
- /*
- X * rvstrcpy -- Reverse string copy.
- X */
- rvstrcpy(rvstr, str)
- register char *rvstr, *str;
- {
- X register int i;
- X
- X str += (i = strlen(str));
- X
- X while (i-- > 0)
- X *rvstr++ = *--str;
- X
- X *rvstr = '\0';
- }
- X
- rvstrncpy(rvstr, str, n)
- register char *rvstr, *str;
- {
- X register int i;
- X
- X i = strlen(str);
- X if (n < i) i = n;
- X
- X str += i;
- X
- X while (i-- > 0)
- X *rvstr++ = *--str;
- X
- X *rvstr = '\0';
- }
- X
- #if SEARCH_AND_REPLACE
- /*
- X * sreplace -- Search and replace.
- X */
- sreplace(f, n)
- {
- X return replaces(FALSE, f, n);
- }
- X
- /*
- X * qreplace -- search and replace with query.
- X */
- qreplace(f, n)
- {
- X register int s;
- X s = replaces(TRUE, f, n);
- #if NeWS /* user must not buffer output */
- X newsimmediateoff() ;
- #endif
- X return(s) ;
- }
- X
- /*
- X * replaces -- Search for a string and replace it with another
- X * string. Query might be enabled (according to kind).
- X * f,n unused
- X */
- replaces(kind, f, n)
- int kind; /* Query enabled flag */
- {
- X register int status; /* success flag on pattern inputs */
- X register int rlength; /* length of replacement string */
- X register int numsub; /* number of substitutions */
- X int nlflag; /* last char of search string a <NL>? */
- X int nlrepl; /* was a replace done on the last line? */
- X int c; /* input char for query */
- X char tpat[NPAT]; /* temporary to hold search pattern */
- X LINE *lastline; /* position of last replace and */
- X int lastoff; /* offset (for 'u' query option) */
- X REGION region;
- X
- X /* we don't really care much about size, etc., but getregion does
- X a nice job of scanning for the mark, so we use it. Then
- X we pretend that wrapping around the bottom of the file is
- X okay, and use the boundary code to keep us from going
- X past the region end. */
- X if (curwp->w_mkp == curwp->w_dotp) {
- X if (curwp->w_doto > curwp->w_mko) {
- X int tmpoff;
- X tmpoff = curwp->w_doto;
- X curwp->w_doto = curwp->w_mko;
- X curwp->w_mko = tmpoff;
- X }
- X } else {
- X getregion(®ion);
- X if (region.r_linep == curwp->w_mkp)
- X swapmark();
- X }
- X if (fulllineregions) {
- X curwp->w_doto = 0;
- X curwp->w_mko = llength(curwp->w_mkp);
- X }
- X if (curwp->w_mkp == curbp->b_linep) {
- X mlwrite("BUG: mark is at b_linep");
- X return FALSE;
- X }
- X
- X /* Ask the user for the text of a pattern.
- X */
- X if ((status = readpattern(
- X (kind == FALSE ? "Replace: " : "Query replace: "),
- X &pat[0], TRUE, '\n', FALSE)) != TRUE)
- X return status;
- X
- X /* Ask for the replacement string.
- X */
- X if ((status = readpattern("with: ", &rpat[0], FALSE, '\n', FALSE))
- X == ABORT)
- X return status;
- X
- X /* Find the length of the replacement string.
- X */
- X rlength = strlen(&rpat[0]);
- X
- X /* Set up flags so we can make sure not to do a recursive
- X * replace on the last line.
- X */
- X nlflag = (pat[matchlen - 1] == '\n');
- X nlrepl = FALSE;
- X
- X if (kind)
- X {
- X /* Build query replace question string.
- X */
- X strcpy(tpat, "Replace '");
- X expandp(&pat[0], &tpat[strlen(tpat)], NPAT/3);
- X strcat(tpat, "' with '");
- X expandp(&rpat[0], &tpat[strlen(tpat)], NPAT/3);
- X strcat(tpat, "'? ");
- X
- X /* Initialize last replaced pointers.
- X */
- X lastline = NULL;
- X lastoff = 0;
- #if NeWS
- X newsimmediateon() ;
- #endif
- X }
- X
- X numsub = 0;
- X
- X while ( nlflag == FALSE || nlrepl == FALSE ) {
- X
- X if (interrupted) return ABORT;
- X
- X /* Search for the pattern.
- X * If we search with a regular expression,
- X * matchlen is reset to the true length of
- X * the matched string.
- X */
- X setboundry(TRUE,curwp->w_mkp,curwp->w_mko,FORWARD);
- #if MAGIC
- X if (magical && (curwp->w_bufp->b_mode & MDMAGIC) != 0) {
- X if (!thescanner(&mcpat[0], FORWARD, PTBEG, TRUE))
- X break;
- X } else
- #endif
- X if (!thescanner(&pat[0], FORWARD, PTBEG, TRUE))
- X break; /* all done */
- X
- X /* Check if we are on the last line.
- X */
- X nlrepl = (lforw(curwp->w_dotp) == curwp->w_bufp->b_linep);
- X
- X /* Check for query.
- X */
- X if (kind)
- X {
- X /* Get the query.
- X */
- pprompt: mlwrite(&tpat[0], &pat[0], &rpat[0]);
- qprompt:
- X update(TRUE); /* show the proposed place to change */
- nprompt:
- X c = kbd_key(); /* and input */
- X mlwrite(""); /* and clear it */
- X
- X if (c == abortc) {
- X mlwrite("[Aborted]");
- X return(FALSE);
- X }
- X
- X /* And respond appropriately.
- X */
- X switch (c)
- X {
- X case tocntrl('Q'):
- X case tocntrl('S'):
- X goto nprompt;
- X
- X case 'y': /* yes, substitute */
- X savematch();
- X break;
- X
- X case 'n': /* no, onward */
- X nextch( &(curwp->w_dotp),
- X &(curwp->w_doto),FORWARD,TRUE);
- X continue;
- X
- X case '!': /* yes/stop asking */
- X kind = FALSE;
- X break;
- X
- X case 'u': /* undo last and re-prompt */
- X
- X /* Restore old position.
- X */
- X if (lastline == NULL)
- X {
- X /* There is nothing to undo.
- X */
- X TTbeep();
- X goto pprompt;
- X }
- X curwp->w_dotp = lastline;
- X curwp->w_doto = lastoff;
- X lastline = NULL;
- X lastoff = 0;
- X
- X /* Delete the new string.
- X */
- X backchar(FALSE, rlength);
- X status = delins(rlength, patmatch);
- X if (status != TRUE) {
- X return (status);
- X }
- X
- X /* Record one less substitution,
- X * backup, and reprompt.
- X */
- X --numsub;
- X backchar(TRUE, mlenold);
- X matchline = curwp->w_dotp;
- X matchoff = curwp->w_doto;
- X goto pprompt;
- X
- X default: /* bitch and beep */
- X TTbeep();
- X
- X case 'h':
- X case '?': /* help me */
- X mlwrite(
- X "(Y)es, (N)o, (!)Do rest, (U)ndo last, (ESC)Abort: ");
- X goto qprompt;
- X
- X } /* end of switch */
- X } /* end of "if kind" */
- X
- X /*
- X * Delete the sucker, and insert its
- X * replacement.
- X */
- X status = delins(matchlen, &rpat[0]);
- X if (status != TRUE) {
- X return (status);
- X }
- X
- X /* Save where we are if we might undo this....
- X */
- X if (kind)
- X {
- X lastline = curwp->w_dotp;
- X lastoff = curwp->w_doto;
- X }
- X
- X numsub++; /* increment # of substitutions */
- X }
- X
- X /* And report the results.
- X */
- X mlwrite("%d substitutions", numsub);
- X return(TRUE);
- }
- X
- /*
- X * delins -- Delete a specified length from the current
- X * point, then insert the string.
- X */
- delins(dlength, instr)
- int dlength;
- char *instr;
- {
- X int status;
- X char tmpc;
- X
- X /* Zap what we gotta,
- X * and insert its replacement.
- X */
- X if (!(status = ldelete((long) dlength, FALSE)))
- X {
- X mlwrite("Error while deleting");
- X return(FALSE);
- X } else {
- X while (tmpc = *instr)
- X {
- X status = (tmpc == '\n'? lnewline(): linsert(1, tmpc));
- X
- X /* Insertion error?
- X */
- X if (!status)
- X {
- X mlwrite("Out of memory while inserting");
- X break;
- X }
- X instr++;
- X }
- X }
- X return (status);
- }
- #endif
- X
- /*
- X * expandp -- Expand control key sequences for output.
- X */
- expandp(srcstr, deststr, maxlength)
- char *srcstr; /* string to expand */
- char *deststr; /* destination of expanded string */
- int maxlength; /* maximum chars in destination */
- {
- X unsigned char c; /* current char to translate */
- X
- X /* Scan through the string.
- X */
- X while ((c = *srcstr++) != 0)
- X {
- X if (c == '\n') /* it's a newline */
- X {
- X *deststr++ = '<';
- X *deststr++ = 'N';
- X *deststr++ = 'L';
- X *deststr++ = '>';
- X maxlength -= 4;
- X }
- X else if (!isprint(c)) /* control character */
- X {
- X *deststr++ = '^';
- X *deststr++ = toalpha(c);
- X maxlength -= 2;
- X }
- X else if (c == '%')
- X {
- X *deststr++ = '%';
- X *deststr++ = '%';
- X maxlength -= 2;
- X }
- X else /* any other character */
- X {
- X *deststr++ = c;
- X maxlength--;
- X }
- X
- X /* check for maxlength */
- X if (maxlength < 4)
- X {
- X *deststr++ = '$';
- X *deststr = '\0';
- X return(FALSE);
- X }
- X }
- X *deststr = '\0';
- X return(TRUE);
- }
- X
- /*
- X * boundry -- Return information depending on whether we may search no
- X * further. Beginning of file and end of file are the obvious
- X * cases, but we may want to add further optional boundary restrictions
- X * in future, a' la VMS EDT. At the moment, just return TRUE or
- X * FALSE depending on if a boundary is hit (ouch).
- X */
- int
- boundry(curline, curoff)
- LINE *curline;
- int curoff;
- {
- X return (curline == boundline) && (curoff == boundoff);
- }
- X
- setboundry(wrapok,lp,off,dir)
- LINE *lp;
- {
- X if (wrapok) {
- X (void)nextch(&lp,&off,dir,TRUE);
- X boundline = lp;
- X boundoff = off;
- X } else {
- X boundline = curbp->b_linep;
- X boundoff = 0;
- X }
- }
- X
- /*
- X * nextch -- retrieve the next/previous character in the buffer,
- X * and advance/retreat the point.
- X * The order in which this is done is significant, and depends
- X * upon the direction of the search. Forward searches look at
- X * the current character and move, reverse searches move and
- X * look at the character.
- X */
- nextch(pcurline, pcuroff, dir, wrapok)
- LINE **pcurline;
- int *pcuroff;
- int dir;
- {
- X register LINE *curline;
- X register int curoff;
- X register int c;
- X
- X /* dummy up a -1, which will never match anything, as the only
- X character on the header line */
- X
- X curline = *pcurline;
- X curoff = *pcuroff;
- X if (dir == FORWARD) {
- X if (curoff == ((curline == curbp->b_linep)?1:llength(curline)))
- X { /* if at EOL */
- X curline = lforw(curline); /* skip to next line */
- X curoff = 0;
- X c = '\n'; /* and return a <NL> */
- X } else {
- X c = lgetc(curline, curoff++); /* get the char */
- X if (curline == curbp->b_linep)
- X c = -1;
- X }
- X } else { /* Reverse.*/
- X if (curoff == 0) {
- X curline = lback(curline);
- X curoff = (curline == curbp->b_linep)?1:llength(curline);
- X c = '\n';
- X } else {
- X c = lgetc(curline, --curoff);
- X if (curline == curbp->b_linep)
- X c = -1;
- X }
- X }
- X *pcurline = curline;
- X *pcuroff = curoff;
- X
- X return (c);
- }
- X
- #if MAGIC
- /*
- X * mcstr -- Set up the 'magic' array. The closure symbol is taken as
- X * a literal character when (1) it is the first character in the
- X * pattern, and (2) when preceded by a symbol that does not allow
- X * closure, such as a newline, beginning of line symbol, or another
- X * closure symbol.
- X *
- X * Coding comment (jmg): yes, i know i have gotos that are, strictly
- X * speaking, unnecessary. But right now we are so cramped for
- X * code space that i will grab what i can in order to remain
- X * within the 64K limit. C compilers actually do very little
- X * in the way of optimizing - they expect you to do that.
- X */
- int
- mcstr()
- {
- X MC *mcptr, *rtpcm;
- X char *patptr;
- X int mj;
- X int pchr;
- X int status = TRUE;
- X int does_closure = FALSE;
- X
- X /* If we had metacharacters in the MC array previously,
- X * free up any bitmaps that may have been allocated.
- X */
- X if (magical)
- X mcclear();
- X
- X magical = FALSE;
- X mj = 0;
- X mcptr = &mcpat[0];
- X patptr = &pat[0];
- X
- X while ((pchr = *patptr) && status)
- X {
- X switch (pchr)
- X {
- X case MC_CCL:
- X status = cclmake(&patptr, mcptr);
- X magical = TRUE;
- X does_closure = TRUE;
- X break;
- X case MC_BOL:
- X if (mj != 0)
- X goto litcase;
- X
- X mcptr->mc_type = BOL;
- X magical = TRUE;
- X does_closure = FALSE;
- X break;
- X case MC_EOL:
- X if (*(patptr + 1) != '\0')
- X goto litcase;
- X
- X mcptr->mc_type = EOL;
- X magical = TRUE;
- X does_closure = FALSE;
- X break;
- X case MC_ANY:
- X mcptr->mc_type = ANY;
- X magical = TRUE;
- X does_closure = TRUE;
- X break;
- X case MC_CLOSURE:
- X /* Does the closure symbol mean closure here?
- X * If so, back up to the previous element
- X * and indicate it is enclosed.
- X */
- X if (!does_closure)
- X goto litcase;
- X mj--;
- X mcptr--;
- X mcptr->mc_type |= CLOSURE;
- X magical = TRUE;
- X does_closure = FALSE;
- X break;
- X
- X /* Note: no break between MC_ESC case and the default.
- X */
- X case MC_ESC:
- X if (*(patptr + 1) != '\0')
- X {
- X pchr = *++patptr;
- X magical = TRUE;
- X }
- X default:
- litcase: mcptr->mc_type = LITCHAR;
- X mcptr->u.lchar = pchr;
- X does_closure = (pchr != '\n');
- X break;
- X } /* End of switch.*/
- X mcptr++;
- X patptr++;
- X mj++;
- X } /* End of while.*/
- X
- X /* Close off the meta-string.
- X */
- X mcptr->mc_type = MCNIL;
- X
- X /* Set up the reverse array, if the status is good. Please note the
- X * structure assignment - your compiler may not like that.
- X * If the status is not good, nil out the meta-pattern.
- X * The only way the status would be bad is from the cclmake()
- X * routine, and the bitmap for that member is guarenteed to be
- X * freed. So we stomp a MCNIL value there, and call mcclear()
- X * to free any other bitmaps.
- X */
- X if (status)
- X {
- X rtpcm = &tapcm[0];
- X while (--mj >= 0)
- X {
- #if LATTICE
- X movmem(--mcptr, rtpcm++, sizeof (MC));
- #endif
- X
- #if MWC86 | AZTEC | MSC | TURBO | VMS | USG | BSD | V7
- X *rtpcm++ = *--mcptr;
- #endif
- X }
- X rtpcm->mc_type = MCNIL;
- X }
- X else
- X {
- X (--mcptr)->mc_type = MCNIL;
- X mcclear();
- X }
- X
- X return(status);
- }
- X
- /*
- X * mcclear -- Free up any CCL bitmaps, and MCNIL the MC arrays.
- X */
- mcclear()
- {
- X register MC *mcptr;
- X
- X mcptr = &mcpat[0];
- X
- X while (mcptr->mc_type != MCNIL)
- X {
- X if ((mcptr->mc_type & MASKCL) == CCL ||
- X (mcptr->mc_type & MASKCL) == NCCL)
- X free(mcptr->u.cclmap);
- X mcptr++;
- X }
- X mcpat[0].mc_type = tapcm[0].mc_type = MCNIL;
- }
- X
- /*
- X * mceq -- meta-character equality with a character. In Kernighan & Plauger's
- X * Software Tools, this is the function omatch(), but i felt there
- X * were too many functions with the 'match' name already.
- X */
- mceq(bc, mt)
- int bc;
- MC *mt;
- {
- X register int result;
- X
- X if (bc < 0)
- X return FALSE;
- X
- X switch (mt->mc_type & MASKCL)
- X {
- X case LITCHAR:
- X result = eq(bc, mt->u.lchar);
- X break;
- X
- X case ANY:
- X result = (bc != '\n');
- X break;
- X
- X case CCL:
- X if (!(result = biteq(bc, mt->u.cclmap)))
- X {
- X if ((curwp->w_bufp->b_mode & MDEXACT) == 0 &&
- X isalpha(bc))
- X {
- X result = biteq(CHCASE(bc),mt->u.cclmap);
- X }
- X }
- X break;
- X
- X case NCCL:
- X
- X if (bc == '\n') {
- X result = FALSE;
- X } else {
- X result = !biteq(bc, mt->u.cclmap);
- X
- X if ((curwp->w_bufp->b_mode & MDEXACT) == 0 &&
- X isalpha(bc))
- X {
- X result &= !biteq(CHCASE(bc),
- X mt->u.cclmap);
- X }
- X }
- X break;
- X
- X default:
- X mlwrite("mceq: what is %d?", mt->mc_type);
- X result = FALSE;
- X break;
- X
- X } /* End of switch.*/
- X
- X return (result);
- }
- X
- /*
- X * cclmake -- create the bitmap for the character class.
- X * ppatptr is left pointing to the end-of-character-class character,
- X * so that a loop may automatically increment with safety.
- X */
- cclmake(ppatptr, mcptr)
- char **ppatptr;
- MC *mcptr;
- {
- X BITMAP bmap;
- X register char *patptr;
- X register int pchr, ochr;
- X
- X if ((bmap = clearbits()) == NULL)
- X {
- X mlwrite("Out of memory");
- X return FALSE;
- X }
- X
- X mcptr->u.cclmap = bmap;
- X patptr = *ppatptr;
- X
- X /*
- X * Test the initial character(s) in ccl for
- X * special cases - negate ccl, or an end ccl
- X * character as a first character. Anything
- X * else gets set in the bitmap.
- X */
- X if (*++patptr == MC_NCCL)
- X {
- X patptr++;
- X mcptr->mc_type = NCCL;
- X }
- X else
- X mcptr->mc_type = CCL;
- X
- X if ((ochr = *patptr) == MC_ECCL)
- X {
- X mlwrite("Empty character class");
- X return (FALSE);
- X }
- X else
- X {
- X if (ochr == MC_ESC)
- X ochr = *++patptr;
- X
- X setbit(ochr, bmap);
- X patptr++;
- X }
- X
- X while (ochr != '\0' && (pchr = *patptr) != MC_ECCL)
- X {
- X switch (pchr)
- X {
- X /* Range character loses its meaning
- X * if it is the last character in
- X * the class.
- X */
- X case MC_RCCL:
- X if (*(patptr + 1) == MC_ECCL)
- X setbit(pchr, bmap);
- X else
- X {
- X pchr = *++patptr;
- X while (++ochr <= pchr)
- X setbit(ochr, bmap);
- X }
- X break;
- X
- X /* Note: no break between case MC_ESC and the default.
- X */
- X case MC_ESC:
- X pchr = *++patptr;
- X default:
- X setbit(pchr, bmap);
- X break;
- X }
- X patptr++;
- X ochr = pchr;
- X }
- X
- X *ppatptr = patptr;
- X
- X if (ochr == '\0')
- X {
- X mlwrite("Missing '%c'",MC_ECCL);
- X free(bmap);
- X return FALSE;
- X }
- X return TRUE;
- }
- X
- /*
- X * biteq -- is the character in the bitmap?
- X */
- biteq(bc, cclmap)
- int bc;
- BITMAP cclmap;
- {
- X if (bc >= HICHAR || bc < 0)
- X return FALSE;
- X
- X return( (*(cclmap + (bc >> 3)) & BIT(bc & 7))? TRUE: FALSE );
- }
- X
- /*
- X * clearbits -- Allocate and zero out a CCL bitmap.
- X */
- BITMAP
- clearbits()
- {
- X
- X BITMAP cclstart, cclmap;
- X register int j;
- X
- X if ((cclmap = cclstart = (BITMAP) malloc(HIBYTE)) != NULL)
- X for (j = 0; j < HIBYTE; j++)
- X *cclmap++ = 0;
- X
- X return (cclstart);
- }
- X
- /*
- X * setbit -- Set a bit (ON only) in the bitmap.
- X */
- void
- setbit(bc, cclmap)
- int bc;
- BITMAP cclmap;
- {
- X if (bc < HICHAR && bc >= 0)
- X *(cclmap + (bc >> 3)) |= BIT(bc & 7);
- }
- #endif
- SHAR_EOF
- chmod 0444 search.c ||
- echo 'restore of search.c failed'
- Wc_c="`wc -c < 'search.c'`"
- test 35047 -eq "$Wc_c" ||
- echo 'search.c: original size 35047, current size' "$Wc_c"
- # ============= shorten/COPYING ==============
- if test ! -d 'shorten'; then
- echo 'x - creating directory shorten'
- mkdir 'shorten'
- fi
- echo 'x - extracting shorten/COPYING (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'shorten/COPYING' &&
- The code distributed with vile in the "shortnames" subdirectory is covered
- by the following license. The vile code itself is _not_ covered by the GNU
- public license.
- X
- X GNU EMACS GENERAL PUBLIC LICENSE
- X (Clarified 11 Feb 1988)
- X
- X Copyright (C) 1985, 1987, 1988 Richard M. Stallman
- X Everyone is permitted to copy and distribute verbatim copies
- X of this license, but changing it is not allowed. You can also
- X use this wording to make the terms for other programs.
- X
- X The license agreements of most software companies keep you at the
- mercy of those companies. By contrast, our general public license is
- intended to give everyone the right to share GNU Emacs. To make
- sure that you get the rights we want you to have, we need to make
- restrictions that forbid anyone to deny you these rights or to ask you
- to surrender the rights. Hence this license agreement.
- X
- X Specifically, we want to make sure that you have the right to give
- away copies of Emacs, that you receive source code or else can get it
- if you want it, that you can change Emacs or use pieces of it in new
- free programs, and that you know you can do these things.
- X
- X To make sure that everyone has such rights, we have to forbid you to
- deprive anyone else of these rights. For example, if you distribute
- copies of Emacs, you must give the recipients all the rights that you
- have. You must make sure that they, too, receive or can get the
- source code. And you must tell them their rights.
- X
- X Also, for our own protection, we must make certain that everyone
- finds out that there is no warranty for GNU Emacs. If Emacs is
- modified by someone else and passed on, we want its recipients to know
- that what they have is not what we distributed, so that any problems
- introduced by others will not reflect on our reputation.
- X
- X Therefore we (Richard Stallman and the Free Software Fundation,
- Inc.) make the following terms which say what you must do to be
- allowed to distribute or change GNU Emacs.
- X
- X COPYING POLICIES
- X
- X 1. You may copy and distribute verbatim copies of GNU Emacs source code
- as you receive it, in any medium, provided that you conspicuously and
- appropriately publish on each copy a valid copyright notice "Copyright
- (C) 1988 Free Software Foundation, Inc." (or with whatever year is
- appropriate); keep intact the notices on all files that refer to this
- License Agreement and to the absence of any warranty; and give any
- other recipients of the GNU Emacs program a copy of this License
- Agreement along with the program. You may charge a distribution fee
- SHAR_EOF
- true || echo 'restore of shorten/COPYING failed'
- echo 'End of Vile part 12'
- echo 'File shorten/COPYING is continued in part 13'
- echo 13 > _shar_seq_.tmp
- exit 0
- --
- paul fox, pgf@cayman.com, (617)494-1999
- Cayman Systems, 26 Landsdowne St., Cambridge, MA 02139
-