home *** CD-ROM | disk | FTP | other *** search
- From: pgf@cayman.COM (Paul Fox)
- Newsgroups: alt.sources
- Subject: Vile 08/17 - vi feel-alike (multi-window)
- Message-ID: <4527@cayman.COM>
- Date: 7 Jun 91 22:09:42 GMT
-
- #!/bin/sh
- # this is vileshar.08 (part 8 of Vile)
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file input.c continued
- #
- if test ! -r _shar_seq_.tmp; then
- echo 'Please unpack part 1 first!'
- exit 1
- fi
- (read Scheck
- if test "$Scheck" != 8; then
- echo Please unpack part "$Scheck" next!
- exit 1
- else
- exit 0
- fi
- ) < _shar_seq_.tmp || exit 1
- echo 'x - continuing file input.c'
- sed 's/^X//' << 'SHAR_EOF' >> 'input.c' &&
- X * macro throw the prompt away, and return the remembered response. This
- X * lets macros run at full speed. The reply is always terminated by a carriage
- X * return. Handle erase, kill, and abort keys.
- X */
- X
- mlreply(prompt, buf, bufn)
- char *prompt;
- char *buf;
- {
- X return kbd_string(prompt, buf, bufn, '\n',EXPAND);
- }
- X
- /* as above, but don't expand special punctuation, like #, %, ~, etc. */
- mlreply_no_exp(prompt, buf, bufn)
- char *prompt;
- char *buf;
- {
- X return kbd_string(prompt, buf, bufn, '\n',NO_EXPAND);
- }
- X
- /* kcod2key: translate 10-bit keycode to single key value */
- /* probably defined as a macro in estruct.h */
- #ifndef kcod2key
- kcod2key(c)
- int c;
- {
- X return c & 0x7f;
- }
- #endif
- X
- X
- /* the numbered buffer names increment each time they are referenced */
- incr_dot_kregnum()
- {
- X if (dotcmdmode == PLAY) {
- X if (isdigit(*dotcmdptr) && *dotcmdptr < '9')
- X (*dotcmdptr)++;
- X }
- }
- X
- int tungotc = -1;
- X
- tungetc(c)
- {
- X tungotc = c;
- }
- X
- tpeekc()
- {
- X return tungotc;
- }
- X
- /* tgetc: Get a key from the terminal driver, resolve any keyboard
- X macro action */
- int
- tgetc()
- {
- X int c; /* fetched character */
- X
- X if (dotcmdmode == PLAY) {
- X
- X if (interrupted) {
- X dotcmdmode = STOP;
- X return (kcod2key(abortc));
- X }
- X
- X /* if there is some left... */
- X if (dotcmdptr < dotcmdend)
- X return(*dotcmdptr++);
- X
- X /* at the end of last repitition? */
- X if (--dotcmdrep < 1) {
- X dotcmdmode = RECORD;
- X tmpcmdptr = &tmpcmdm[0];
- X tmpcmdend = tmpcmdptr;
- #if VISMAC == 0
- X /* force a screen update after all is done */
- X update(FALSE);
- #endif
- X } else {
- X
- X /* reset the macro to the begining for the next rep */
- X dotcmdptr = &dotcmdm[0];
- X return((int)*dotcmdptr++);
- X }
- X } else if (kbdmode == PLAY) {
- X /* if we are playing a keyboard macro back, */
- X
- X /* if there is some left... */
- X if (kbdptr < kbdend)
- X return((int)*kbdptr++);
- X
- X /* at the end of last repitition? */
- X if (--kbdrep < 1) {
- X kbdmode = STOP;
- #if VISMAC == 0
- X /* force a screen update after all is done */
- X update(FALSE);
- #endif
- X } else {
- X
- X /* reset the macro to the begining for the next rep */
- X kbdptr = &kbdm[0];
- X return((int)*kbdptr++);
- X }
- X }
- X
- X
- X if (tungotc >= 0) {
- X c = tungotc;
- X tungotc = -1;
- X } else { /* fetch a character from the terminal driver */
- X interrupted = 0;
- X c = TTgetc();
- X if (c == -1 || c == kcod2key(intrc)) {
- X c = kcod2key(abortc);
- X return lastkey = c;
- X }
- X }
- X
- X /* save it if we need to */
- X if (dotcmdmode == RECORD) {
- X *tmpcmdptr++ = c;
- X tmpcmdend = tmpcmdptr;
- X
- X /* don't overrun the buffer */
- X /* (we're recording, so must be using tmp) */
- X if (tmpcmdptr == &tmpcmdm[NKBDM - 1]) {
- X dotcmdmode = STOP;
- X TTbeep();
- X }
- X }
- X
- X /* save it if we need to */
- X if (kbdmode == RECORD) {
- X *kbdptr++ = c;
- X kbdend = kbdptr;
- X
- X /* don't overrun the buffer */
- X if (kbdptr == &kbdm[NKBDM - 1]) {
- X kbdmode = STOP;
- X TTbeep();
- X }
- X }
- X
- X /* and finally give the char back */
- X /* record it for $lastkey */
- X return(lastkey = c);
- }
- X
- /* KBD_KEY: Get one keystroke. The only prefix legal here
- X is the SPEC prefix. */
- kbd_key()
- {
- X int c;
- X
- X /* get a keystroke */
- X c = tgetc();
- X
- #if MSDOS | ST520
- X if (c == 0) { /* Apply SPEC prefix */
- X c = tgetc();
- X if (insertmode) continue;
- X return(last1key = SPEC | c);
- X }
- #endif
- X
- #if AMIGA
- X /* apply SPEC prefix */
- X if ((unsigned)c == 155) {
- X int d;
- X c = tgetc();
- X
- X /* first try to see if it is a cursor key */
- X if ((c >= 'A' && c <= 'D') || c == 'S' || c == 'T') {
- X if (insertmode) continue;
- X return(last1key = SPEC | c);
- X }
- X
- X /* next, a 2 char sequence */
- X d = tgetc();
- X if (d == '~') {
- X if (insertmode) continue;
- X return(last1key = SPEC | c);
- X }
- X
- X /* decode a 3 char sequence */
- X c = d + ' ';
- X /* if a shifted function key, eat the tilde */
- X if (d >= '0' && d <= '9')
- X d = tgetc();
- X if (insertmode) continue;
- X return(last1key = SPEC | c);
- X }
- #endif
- X
- #if WANGPC
- X if (c == 0x1F) { /* Apply SPEC prefix */
- X c = tgetc();
- X if (insertmode) continue;
- X return(last1key = SPEC | c);
- X }
- #endif
- X
- X return (last1key = c);
- }
- X
- /* KBD_SEQ: Get a command sequence (multiple keystrokes) from
- X the keyboard.
- X Process all applicable prefix keys.
- X Set lastcmd for commands which want stuttering.
- */
- kbd_seq()
- {
- X int c; /* fetched keystroke */
- X
- X /* get initial character */
- X c = kbd_key();
- X
- X /* process CTLA prefix */
- X if (c == cntl_a) {
- X c = kbd_key();
- #if BEFORE
- X if (islower(c)) /* Force to upper */
- X c = toupper(c);
- #endif
- X return (lastcmd = CTLA | c);
- X }
- X
- X /* process CTLX prefix */
- X if (c == cntl_x) {
- X c = kbd_key();
- X return (lastcmd = CTLX | c);
- X }
- X
- X /* otherwise, just return it */
- X return (lastcmd = c);
- }
- X
- screen_string(buf,bufn,inclchartype)
- char *buf;
- {
- X register int i = 0;
- X register int s = TRUE;
- X
- X setmark();
- X while (s == TRUE && i < bufn &&
- X curwp->w_doto != llength(curwp->w_dotp)) {
- X buf[i] = lgetc(curwp->w_dotp, curwp->w_doto);
- X if (!istype(inclchartype, buf[i]))
- X break;
- X s = forwchar(FALSE, 1);
- X i++;
- X }
- X buf[i] = '\0';
- X swapmark();
- X
- X return buf[0] != '\0';
- }
- X
- /* A more generalized prompt/reply function allowing the caller
- X to specify a terminator other than '\n'. Both are accepted.
- X Assumes the buffer already contains a valid (possibly
- X null) string to use as the default response.
- */
- kbd_string(prompt, buf, bufn, eolchar, expand)
- char *prompt;
- char *buf;
- int eolchar;
- {
- X register int cpos; /* current character position in string */
- X register int c;
- X register int quotef; /* are we quoting the next char? */
- X int firstchar = TRUE;
- X
- X if (clexec)
- X return nextarg(buf);
- X
- X lineinput = TRUE;
- X
- X cpos = 0;
- X quotef = FALSE;
- X
- X
- X /* prompt the user for the input string */
- X mlwrite(prompt);
- X /* put out the default response, which comes in already in the
- X buffer */
- X while((c = buf[cpos]) != '\0' && cpos < bufn-1) {
- X if (!isprint(c)) {
- X if (disinp)
- X TTputc('^');
- X ++ttcol;
- X c = toalpha(c);
- X }
- X
- X if (disinp)
- X TTputc(c);
- X ++ttcol;
- X ++cpos;
- X }
- X TTflush();
- X
- X for (;;) {
- X /* get a character from the user */
- X c = kbd_key();
- X
- X /* If it is a <ret>, change it to a <NL> */
- X if (c == '\r' && quotef == FALSE)
- X c = '\n';
- X
- X /* if they hit the line terminate, wrap it up */
- X /* don't allow newlines in the string -- they cause real
- X problems, especially when searching for patterns
- X containing them -pgf */
- X /* never a newline, and only eolchar if ^V or \ precedes it */
- X if (c == '\n' || (c == eolchar &&
- X quotef == FALSE && cpos > 0 && buf[cpos-1] != '\\'))
- X {
- X if (buf[cpos] != '\0')
- X buf[cpos++] = 0;
- X
- X lineinput = FALSE;
- X /* if buffer is empty, return FALSE */
- X if (buf[0] == 0)
- X return(FALSE);
- X
- X return(TRUE);
- X }
- X
- #if NeWS /* make sure cursor is where we think it is before output */
- X TTmove(ttrow,ttcol) ;
- #endif
- X /* change from command form back to character form */
- X c = kcod2key(c);
- X
- X if (c == kcod2key(abortc) && quotef == FALSE) {
- X buf[cpos] = 0;
- X esc(FALSE, 0);
- X TTflush();
- X lineinput = FALSE;
- X return ABORT;
- X } else if (isbackspace(c) && quotef==FALSE) {
- X /* rubout/erase */
- X if (cpos != 0) {
- X outstring("\b \b");
- X --ttcol;
- X
- X if (!isprint(buf[--cpos])) {
- X outstring("\b \b");
- X --ttcol;
- X }
- X
- X TTflush();
- X } else {
- X buf[0] = 0;
- X mlerase();
- X lineinput = FALSE;
- X return FALSE;
- X }
- X
- X } else if (c == kcod2key(killc) && quotef == FALSE) {
- X /* C-U, kill */
- X killit:
- X while (cpos != 0) {
- X outstring("\b \b");
- X --ttcol;
- X
- X if (!isprint(buf[--cpos])) {
- X outstring("\b \b");
- X --ttcol;
- X }
- X }
- X TTflush();
- X
- X } else if (expand == EXPAND) {
- X /* we prefer to expand to filenames, but a buffer name
- X will do */
- X char *cp = NULL;
- X char *hist_lookup();
- X if (firstchar == TRUE) {
- X tungetc(c);
- X goto killit;
- X }
- X switch(c) {
- X case '%':
- X cp = curbp->b_fname;
- X if (!*cp || isspace(*cp))
- X cp = curbp->b_bname;
- X break;
- X case '#':
- X cp = hist_lookup(1); /* returns buffer name */
- X if (cp) {
- X /* but we want a file */
- X BUFFER *bp;
- X bp = bfind(cp,NO_CREAT,0);
- X cp = bp->b_fname;
- X if (!*cp || isspace(*cp)) {
- X /* oh well, use the buffer */
- X cp = bp->b_bname;
- X }
- X }
- X break;
- X /* case tocntrl('W'): */
- X case ':':
- X {
- X char str[80];
- X if (screen_string(str, 80, _path))
- X cp = str;
- X break;
- X }
- X default:
- X goto trymore;
- X }
- X
- X if (!cp) {
- X TTbeep();
- X continue;
- X }
- X while (cpos < bufn-1 && (c = *cp++)) {
- X buf[cpos++] = c;
- X if (!isprint(c)) {
- X outstring("^");
- X ++ttcol;
- X c = toalpha(c);
- X }
- X if (disinp)
- X TTputc(c);
- X ++ttcol;
- X }
- X TTflush();
- X } else {
- X trymore:
- X if (c == kcod2key(quotec) && quotef == FALSE) {
- X quotef = TRUE;
- X } else {
- X quotef = FALSE;
- X if (firstchar == TRUE) {
- X tungetc(c);
- X goto killit;
- X }
- X if (cpos < bufn-1) {
- X buf[cpos++] = c;
- X
- X if (!isprint(c)) {
- X outstring("^");
- X ++ttcol;
- X c = toalpha(c);
- X }
- X
- X if (disinp)
- X TTputc(c);
- X
- X ++ttcol;
- X TTflush();
- X }
- X }
- X }
- X firstchar = FALSE;
- X }
- }
- X
- outstring(s) /* output a string of input characters */
- char *s; /* string to output */
- {
- X if (disinp)
- X while (*s)
- X TTputc(*s++);
- }
- X
- ostring(s) /* output a string of output characters */
- char *s; /* string to output */
- {
- X if (discmd)
- X while (*s)
- X TTputc(*s++);
- }
- SHAR_EOF
- echo 'File input.c is complete' &&
- chmod 0444 input.c ||
- echo 'restore of input.c failed'
- Wc_c="`wc -c < 'input.c'`"
- test 10225 -eq "$Wc_c" ||
- echo 'input.c: original size 10225, current size' "$Wc_c"
- # ============= isearch.c ==============
- echo 'x - extracting isearch.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'isearch.c' &&
- /* vile note, 6/1/91, pgf -- I haven't tried this code in a long time */
- /*
- X * The functions in this file implement commands that perform incremental
- X * searches in the forward and backward directions. This "ISearch" command
- X * is intended to emulate the same command from the original EMACS
- X * implementation (ITS). Contains references to routines internal to
- X * SEARCH.C.
- X *
- X * REVISION HISTORY:
- X *
- X * D. R. Banks 9-May-86
- X * - added ITS EMACSlike ISearch
- X *
- X * John M. Gamble 5-Oct-86
- X * - Made iterative search use search.c's scanner() routine.
- X * This allowed the elimination of bakscan().
- X * - Put isearch constants into estruct.h
- X * - Eliminated the passing of 'status' to scanmore() and
- X * checknext(), since there were no circumstances where
- X * it ever equalled FALSE.
- X */
- X
- X
- #include <stdio.h>
- #include "estruct.h"
- #include "edef.h"
- X
- #if ISRCH
- X
- extern int thescanner(); /* Handy search routine */
- extern int eq(); /* Compare chars, match case */
- X
- /* A couple of "own" variables for re-eat */
- X
- int (*saved_get_char)(); /* Get character routine */
- int eaten_char = -1; /* Re-eaten char */
- X
- /* A couple more "own" variables for the command string */
- X
- int cmd_buff[CMDBUFLEN]; /* Save the command args here */
- int cmd_offset; /* Current offset into command buff */
- int cmd_reexecute = -1; /* > 0 if re-executing command */
- X
- X
- /*
- X * Subroutine to do incremental reverse search. It actually uses the
- X * same code as the normal incremental search, as both can go both ways.
- X */
- X
- int risearch(f, n)
- {
- X LINE *curline; /* Current line on entry */
- X int curoff; /* Current offset on entry */
- X
- X /* remember the initial . on entry: */
- X
- X curline = curwp->w_dotp; /* Save the current line pointer */
- X curoff = curwp->w_doto; /* Save the current offset */
- X
- X /* Make sure the search doesn't match where we already are: */
- X
- X backchar(TRUE, 1); /* Back up a character */
- X
- #if NeWS
- X newsimmediateon() ;
- #endif
- X
- X if (!(isearch(f, -n))) /* Call ISearch backwards */
- X { /* If error in search: */
- X curwp->w_dotp = curline; /* Reset the line pointer */
- X curwp->w_doto = curoff; /* and the offset to original value */
- X curwp->w_flag |= WFMOVE; /* Say we've moved */
- X update(FALSE); /* And force an update */
- X mlwrite ("[search failed]"); /* Say we died */
- X TTbeep();
- X } else
- X mlerase (); /* If happy, just erase the cmd line */
- X
- #if NeWS
- X newsimmediateoff() ;
- #endif
- }
- X
- /* Again, but for the forward direction */
- X
- int fisearch(f, n)
- {
- X LINE *curline; /* Current line on entry */
- X int curoff; /* Current offset on entry */
- X
- X /* remember the initial . on entry: */
- X
- X curline = curwp->w_dotp; /* Save the current line pointer */
- X curoff = curwp->w_doto; /* Save the current offset */
- X
- X /* do the search */
- X
- #if NeWS
- X newsimmediateon() ;
- #endif
- X
- X if (!(isearch(f, n))) /* Call ISearch forwards */
- X { /* If error in search: */
- X curwp->w_dotp = curline; /* Reset the line pointer */
- X curwp->w_doto = curoff; /* and the offset to original value */
- X curwp->w_flag |= WFMOVE; /* Say we've moved */
- X update(FALSE); /* And force an update */
- X mlwrite ("[search failed]"); /* Say we died */
- X TTbeep();
- X } else
- X mlerase (); /* If happy, just erase the cmd line */
- X
- #if NeWS
- X newsimmediateoff() ;
- #endif
- }
- X
- /*
- X * Subroutine to do an incremental search. In general, this works similarly
- X * to the older micro-emacs search function, except that the search happens
- X * as each character is typed, with the screen and cursor updated with each
- X * new search character.
- X *
- X * While searching forward, each successive character will leave the cursor
- X * at the end of the entire matched string. Typing a Control-S or Control-X
- X * will cause the next occurrence of the string to be searched for (where the
- X * next occurrence does NOT overlap the current occurrence). A Control-R will
- X * change to a backwards search, META will terminate the search and Control-G
- X * will abort the search. Rubout will back up to the previous match of the
- X * string, or if the starting point is reached first, it will delete the
- X * last character from the search string.
- X *
- X * While searching backward, each successive character will leave the cursor
- X * at the beginning of the matched string. Typing a Control-R will search
- X * backward for the next occurrence of the string. Control-S or Control-X
- X * will revert the search to the forward direction. In general, the reverse
- X * incremental search is just like the forward incremental search inverted.
- X *
- X * In all cases, if the search fails, the user will be feeped, and the search
- X * will stall until the pattern string is edited back into something that
- X * exists (or until the search is aborted).
- X */
- X
- isearch(f, n)
- {
- X int status; /* Search status */
- X int col; /* prompt column */
- X register int cpos; /* character number in search string */
- X register int c; /* current input character */
- X char pat_save[NPAT]; /* Saved copy of the old pattern str */
- X LINE *curline; /* Current line on entry */
- X int curoff; /* Current offset on entry */
- X int init_direction; /* The initial search direction */
- X
- X /* Initialize starting conditions */
- X
- X cmd_reexecute = -1; /* We're not re-executing (yet?) */
- X cmd_offset = 0; /* Start at the beginning of the buff */
- X cmd_buff[0] = '\0'; /* Init the command buffer */
- X strncpy (pat_save, pat, NPAT); /* Save the old pattern string */
- X curline = curwp->w_dotp; /* Save the current line pointer */
- X curoff = curwp->w_doto; /* Save the current offset */
- X init_direction = n; /* Save the initial search direction */
- X setboundry(FALSE,NULL,0,0); /* keep thescanner() finite */
- X
- X /* This is a good place to start a re-execution: */
- X
- start_over:
- X
- X /* ask the user for the text of a pattern */
- X col = promptpattern("ISearch: "); /* Prompt, remember the col */
- X
- X cpos = 0; /* Start afresh */
- X status = TRUE; /* Assume everything's cool */
- X
- X /*
- X Get the first character in the pattern. If we get an initial Control-S
- X or Control-R, re-use the old search string and find the first occurrence
- X */
- X
- X c = kcod2key(get_char()); /* Get the first character */
- X if ((c == IS_FORWARD) ||
- X (c == IS_REVERSE)) /* Reuse old search string? */
- X {
- X for (cpos = 0; pat[cpos] != 0; cpos++) /* Yup, find the length */
- X col = echochar(pat[cpos],col); /* and re-echo the string */
- X if (c == IS_REVERSE) { /* forward search? */
- X n = -1; /* No, search in reverse */
- X backchar (TRUE, 1); /* Be defensive about EOB */
- X } else
- X n = 1; /* Yes, search forward */
- X status = scanmore(pat, n); /* Do the search */
- X c = kcod2key(get_char()); /* Get another character */
- X }
- X
- X /* Top of the per character loop */
- X
- X for (;;) /* ISearch per character loop */
- X {
- X /* Check for special characters first: */
- X /* Most cases here change the search */
- X
- X if (c == kcod2key(abortc)) /* Want to quit searching? */
- X return (TRUE); /* Quit searching now */
- X
- X if (isbackspace(c))
- X c = '\b';
- X
- X if (c == kcod2key(quotec)) /* quote character? */
- X c = kcod2key(get_char()); /* Get the next char */
- X
- X switch (c) /* dispatch on the input char */
- X {
- X case IS_REVERSE: /* If backward search */
- X case IS_FORWARD: /* If forward search */
- X if (c == IS_REVERSE) /* If reverse search */
- X n = -1; /* Set the reverse direction */
- X else /* Otherwise, */
- X n = 1; /* go forward */
- X status = scanmore(pat, n); /* Start the search again */
- X c = kcod2key(get_char()); /* Get the next char */
- X continue; /* Go continue with the search*/
- X
- X case '\r': /* Carriage return */
- X c = '\n'; /* Make it a new line */
- X break; /* Make sure we use it */
- X
- X case '\t': /* Generically allowed */
- X case '\n': /* controlled characters */
- X break; /* Make sure we use it */
- X
- X case '\b': /* or if a Rubout: */
- X if (cmd_offset <= 1) /* Anything to delete? */
- X return (TRUE); /* No, just exit */
- X --cmd_offset; /* Back up over the Rubout */
- X cmd_buff[--cmd_offset] = '\0'; /* Yes, delete last char */
- X curwp->w_dotp = curline; /* Reset the line pointer */
- X curwp->w_doto = curoff; /* and the offset */
- X n = init_direction; /* Reset the search direction */
- X strncpy (pat, pat_save, NPAT); /* Restore the old search str */
- X cmd_reexecute = 0; /* Start the whole mess over */
- X goto start_over; /* Let it take care of itself */
- X
- X /* Presumably a quasi-normal character comes here */
- X
- X default: /* All other chars */
- X if (c < ' ') /* Is it printable? */
- X { /* Nope. */
- X reeat (c); /* Re-eat the char */
- X return (TRUE); /* And return the last status */
- X }
- X } /* Switch */
- X
- X /* I guess we got something to search for, so search for it */
- X
- X pat[cpos++] = c; /* put the char in the buffer */
- X if (cpos >= NPAT) /* too many chars in string? */
- X { /* Yup. Complain about it */
- X mlwrite("? Search string too long");
- X return(TRUE); /* Return an error */
- X }
- X pat[cpos] = 0; /* null terminate the buffer */
- X col = echochar(c,col); /* Echo the character */
- X if (!status) { /* If we lost last time */
- X TTbeep(); /* Feep again */
- X TTflush(); /* see that the feep feeps */
- X } else /* Otherwise, we must have won*/
- X if (!(status = checknext(c, pat, n))) /* See if match */
- X status = scanmore(pat, n); /* or find the next match */
- X c = kcod2key(get_char()); /* Get the next char */
- X } /* for {;;} */
- }
- X
- /*
- X * Trivial routine to insure that the next character in the search string is
- X * still true to whatever we're pointing to in the buffer. This routine will
- X * not attempt to move the "point" if the match fails, although it will
- X * implicitly move the "point" if we're forward searching, and find a match,
- X * since that's the way forward isearch works.
- X *
- X * If the compare fails, we return FALSE and assume the caller will call
- X * scanmore or something.
- X */
- X
- int checknext (chr, patrn, dir) /* Check next character in search string */
- char chr; /* Next char to look for */
- char *patrn; /* The entire search string (incl chr) */
- int dir; /* Search direction */
- {
- X register LINE *curline; /* current line during scan */
- X register int curoff; /* position within current line */
- X register int buffchar; /* character at current position */
- X int status; /* how well things go */
- X
- X
- X /* setup the local scan pointer to current "." */
- X
- X curline = curwp->w_dotp; /* Get the current line structure */
- X curoff = curwp->w_doto; /* Get the offset within that line */
- X
- X if (dir > 0) /* If searching forward */
- X {
- X if (curoff == llength(curline)) /* If at end of line */
- X {
- X curline = lforw(curline); /* Skip to the next line */
- X if (curline == curbp->b_linep)
- X return (FALSE); /* Abort if at end of buffer */
- X curoff = 0; /* Start at the beginning of the line */
- X buffchar = '\n'; /* And say the next char is NL */
- X } else
- X buffchar = lgetc(curline, curoff++); /* Get the next char */
- X if (status = eq(buffchar, chr)) /* Is it what we're looking for? */
- X {
- X curwp->w_dotp = curline; /* Yes, set the buffer's point */
- X curwp->w_doto = curoff; /* to the matched character */
- X curwp->w_flag |= WFMOVE; /* Say that we've moved */
- X }
- X return (status); /* And return the status */
- X } else /* Else, if reverse search: */
- X return (match_pat (patrn)); /* See if we're in the right place */
- }
- X
- /*
- X * This hack will search for the next occurrence of <pat> in the buffer, either
- X * forward or backward. It is called with the status of the prior search
- X * attempt, so that it knows not to bother if it didn't work last time. If
- X * we can't find any more matches, "point" is left where it was before. If
- X * we do find a match, "point" will be at the end of the matched string for
- X * forward searches and at the beginning of the matched string for reverse
- X * searches.
- X */
- X
- int scanmore(patrn, dir) /* search forward or back for a pattern */
- char *patrn; /* string to scan for */
- int dir; /* direction to search */
- {
- X int sts; /* search status */
- X
- X if (dir < 0) /* reverse search? */
- X {
- X rvstrcpy(tap, patrn); /* Put reversed string in tap */
- X sts = thescanner(tap, REVERSE, PTBEG, FALSE);
- X }
- X else /* Nope. Go forward */
- X sts = thescanner(patrn, FORWARD, PTEND, FALSE);
- X
- X if (!sts)
- X {
- X TTbeep(); /* Feep if search fails */
- X TTflush(); /* see that the feep feeps */
- X }
- X
- X return(sts); /* else, don't even try */
- }
- X
- /*
- X * The following is a worker subroutine used by the reverse search. It
- X * compares the pattern string with the characters at "." for equality. If
- X * any characters mismatch, it will return FALSE.
- X *
- X * This isn't used for forward searches, because forward searches leave "."
- X * at the end of the search string (instead of in front), so all that needs to
- X * be done is match the last char input.
- X */
- X
- int match_pat (patrn) /* See if the pattern string matches string at "." */
- char *patrn; /* String to match to buffer */
- {
- X register int i; /* Generic loop index/offset */
- X register int buffchar; /* character at current position */
- X register LINE *curline; /* current line during scan */
- X register int curoff; /* position within current line */
- X
- X /* setup the local scan pointer to current "." */
- X
- X curline = curwp->w_dotp; /* Get the current line structure */
- X curoff = curwp->w_doto; /* Get the offset within that line */
- X
- X /* top of per character compare loop: */
- X
- X for (i = 0; i < strlen(patrn); i++) /* Loop for all characters in patrn */
- X {
- X if (curoff == llength(curline)) /* If at end of line */
- X {
- X curline = lforw(curline); /* Skip to the next line */
- X curoff = 0; /* Start at the beginning of the line */
- X if (curline == curbp->b_linep)
- X return (FALSE); /* Abort if at end of buffer */
- X buffchar = '\n'; /* And say the next char is NL */
- X } else
- X buffchar = lgetc(curline, curoff++); /* Get the next char */
- X if (!eq(buffchar, patrn[i])) /* Is it what we're looking for? */
- X return (FALSE); /* Nope, just punt it then */
- X }
- X return (TRUE); /* Everything matched? Let's celebrate*/
- }
- X
- /* Routine to prompt for I-Search string. */
- X
- int promptpattern(prompt)
- char *prompt;
- {
- X char tpat[NPAT+20];
- X
- X strcpy(tpat, prompt); /* copy prompt to output string */
- X strcat(tpat, " ["); /* build new prompt string */
- X expandp(pat, &tpat[strlen(tpat)], NPAT/2); /* add old pattern */
- X strcat(tpat, "]: ");
- X
- X /* check to see if we are executing a command line */
- X if (!clexec) {
- X mlwrite(tpat);
- X }
- X return(strlen(tpat));
- }
- X
- /* routine to echo i-search characters */
- X
- int echochar(c,col)
- int c; /* character to be echoed */
- int col; /* column to be echoed in */
- {
- X movecursor(term.t_nrow,col); /* Position the cursor */
- X if (!isprint(c)) { /* control char */
- X TTputc('^'); /* Yes, output prefix */
- X TTputc(toalpha(c)); /* Make it "^X" */
- X col++; /* Count this char */
- X } else {
- X TTputc(c); /* Otherwise, output raw char */
- X }
- X TTflush(); /* Flush the output */
- X return(++col); /* return the new column no */
- }
- X
- /*
- X * Routine to get the next character from the input stream. If we're reading
- X * from the real terminal, force a screen update before we get the char.
- X * Otherwise, we must be re-executing the command string, so just return the
- X * next character.
- X */
- X
- int get_char ()
- {
- X int c; /* A place to get a character */
- X
- X /* See if we're re-executing: */
- X
- X if (cmd_reexecute >= 0) /* Is there an offset? */
- X if ((c = cmd_buff[cmd_reexecute++]) != 0)
- X return (c); /* Yes, return any character */
- X
- X /* We're not re-executing (or aren't any more). Try for a real char */
- X
- X cmd_reexecute = -1; /* Say we're in real mode again */
- X update(FALSE); /* Pretty up the screen */
- X if (cmd_offset >= CMDBUFLEN-1) /* If we're getting too big ... */
- X {
- X mlwrite ("? command too long"); /* Complain loudly and bitterly */
- X return (abortc); /* And force a quit */
- X }
- X c = kbd_key(); /* Get the next character */
- X cmd_buff[cmd_offset++] = c; /* Save the char for next time */
- X cmd_buff[cmd_offset] = '\0';/* And terminate the buffer */
- X return (c); /* Return the character */
- }
- X
- /*
- X * Hacky routine to re-eat a character. This will save the character to be
- X * re-eaten by redirecting the input call to a routine here. Hack, etc.
- X */
- X
- /* Come here on the next term.t_getchar call: */
- X
- int uneat()
- {
- X int c;
- X
- X term.t_getchar = saved_get_char; /* restore the routine address */
- X c = eaten_char; /* Get the re-eaten char */
- X eaten_char = -1; /* Clear the old char */
- X return(c); /* and return the last char */
- }
- X
- int reeat(c)
- int c;
- {
- X if (eaten_char != -1) /* If we've already been here */
- X return/*(NULL)*/; /* Don't do it again */
- X eaten_char = c; /* Else, save the char for later */
- X saved_get_char = term.t_getchar; /* Save the char get routine */
- X term.t_getchar = uneat; /* Replace it with ours */
- }
- #else
- isearch()
- {
- }
- #endif
- SHAR_EOF
- chmod 0444 isearch.c ||
- echo 'restore of isearch.c failed'
- Wc_c="`wc -c < 'isearch.c'`"
- test 18075 -eq "$Wc_c" ||
- echo 'isearch.c: original size 18075, current size' "$Wc_c"
- # ============= line.c ==============
- echo 'x - extracting line.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'line.c' &&
- /*
- X * The functions in this file are a general set of line management utilities.
- X * They are the only routines that touch the text. They also touch the buffer
- X * and window structures, to make sure that the necessary updating gets done.
- X * There are routines in this file that handle the kill register too. It isn't
- X * here for any good reason.
- X *
- X * Note that this code only updates the dot and mark values in the window list.
- X * Since all the code acts on the current window, the buffer that we are
- X * editing must be being displayed, which means that "b_nwnd" is non zero,
- X * which means that the dot and mark values in the buffer headers are nonsense.
- X */
- X
- #include <stdio.h>
- #include "estruct.h"
- #include "edef.h"
- X
- #define roundup(n) ((n+NBLOCK-1) & ~(NBLOCK-1))
- /*
- X * This routine allocates a block of memory large enough to hold a LINE
- X * containing "used" characters. The block is always rounded up a bit. Return
- X * a pointer to the new block, or NULL if there isn't any memory left. Print a
- X * message in the message line if no space.
- X */
- LINE *
- lalloc(used)
- register int used;
- {
- X register LINE *lp;
- X register int size;
- X
- X /* lalloc(-1) is used by undo for placeholders */
- X if (used < 0) {
- X size = 0;
- X } else {
- X size = roundup(used);
- X if (size == 0) /* Assume that an empty */
- X size = NBLOCK; /* line is for type-in. */
- X }
- X /* malloc 4 less, because struct LINE is 4 too big */
- X if ((lp = (LINE *) malloc(sizeof(LINE))) == NULL) {
- X mlwrite("[OUT OF MEMORY]");
- X return NULL;
- X }
- X if ((lp->l_text = malloc(size)) == NULL) {
- X mlwrite("[OUT OF MEMORY]");
- X free((char *)lp);
- X return NULL;
- X }
- X lp->l_size = size;
- X lp->l_used = used;
- X lsetclear(lp);
- X lp->l_nxtundo = NULL;
- X return (lp);
- }
- X
- lfree(lp)
- register LINE *lp;
- {
- X if (lp->l_text)
- X free(lp->l_text);
- X free((char *)lp);
- }
- X
- /*
- X * Delete line "lp". Fix all of the links that might point at it (they are
- X * moved to offset 0 of the next line. Unlink the line from whatever buffer it
- X * might be in. The buffers are updated too; the magic
- X * conditions described in the above comments don't hold here.
- X * Memory is not released, so line can be saved in undo stacks.
- X */
- lremove(bp,lp)
- register BUFFER *bp;
- register LINE *lp;
- {
- X register WINDOW *wp;
- X
- X wp = wheadp;
- X while (wp != NULL) {
- X if (wp->w_linep == lp)
- X wp->w_linep = lp->l_fp;
- X if (wp->w_dotp == lp) {
- X wp->w_dotp = lp->l_fp;
- X wp->w_doto = 0;
- X }
- X if (wp->w_mkp == lp) {
- X wp->w_mkp = lp->l_fp;
- X wp->w_mko = 0;
- X }
- #if 0
- X if (wp->w_ldmkp == lp) {
- X wp->w_ldmkp = lp->l_fp;
- X wp->w_ldmko = 0;
- X }
- #endif
- X wp = wp->w_wndp;
- X }
- X if (bp->b_nwnd == 0) {
- X if (bp->b_dotp == lp) {
- X bp->b_dotp = lp->l_fp;
- X bp->b_doto = 0;
- X }
- X if (bp->b_markp == lp) {
- X bp->b_markp = lp->l_fp;
- X bp->b_marko = 0;
- X }
- #if 0
- X if (bp->b_ldmkp == lp) {
- X bp->b_ldmkp = lp->l_fp;
- X bp->b_ldmko = 0;
- X }
- #endif
- X }
- #if 0
- X if (bp->b_nmmarks != NULL) { /* fix the named marks */
- X int i;
- X struct MARK *mp;
- X for (i = 0; i < 26; i++) {
- X mp = &(bp->b_nmmarks[i]);
- X if (mp->markp == lp) {
- X mp->markp = lp->l_fp;
- X mp->marko = 0;
- X }
- X }
- X }
- #endif
- X lp->l_bp->l_fp = lp->l_fp;
- X lp->l_fp->l_bp = lp->l_bp;
- }
- X
- /*
- X * This routine gets called when a character is changed in place in the current
- X * buffer. It updates all of the required flags in the buffer and window
- X * system. The flag used is passed as an argument; if the buffer is being
- X * displayed in more than 1 window we change EDIT to HARD. Set MODE if the
- X * mode line needs to be updated (the "*" has to be set).
- X */
- lchange(flag)
- register int flag;
- {
- X register WINDOW *wp;
- X
- X if (curbp->b_nwnd != 1) { /* Ensure hard. */
- X flag |= WFHARD;
- X }
- X if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */
- X flag |= WFMODE; /* update mode lines. */
- X curbp->b_flag |= BFCHG;
- X }
- X wp = wheadp;
- X while (wp != NULL) {
- X if (wp->w_bufp == curbp)
- X wp->w_flag |= flag;
- X wp = wp->w_wndp;
- X }
- }
- X
- insspace(f, n) /* insert spaces forward into text */
- int f, n; /* default flag and numeric argument */
- {
- X linsert(n, ' ');
- X backchar(f, n);
- }
- X
- /*
- X * Insert "n" copies of the character "c" at the current location of dot. In
- X * the easy case all that happens is the text is stored in the line. In the
- X * hard case, the line has to be reallocated. When the window list is updated,
- X * take special care; I screwed it up once. You always update dot in the
- X * current window. You update mark, and a dot in another window, if it is
- X * greater than the place where you did the insert. Return TRUE if all is
- X * well, and FALSE on errors.
- X */
- linsert(n, c)
- {
- X register char *cp1;
- X register char *cp2;
- X register LINE *lp1;
- X register LINE *lp2;
- X register LINE *lp3;
- X register int doto;
- X register int i;
- X register WINDOW *wp;
- X register char *ntext;
- X int nsize;
- X
- X lchange(WFEDIT);
- X lp1 = curwp->w_dotp; /* Current line */
- X if (lp1 == curbp->b_linep) { /* At the end: special */
- X if (curwp->w_doto != 0) {
- X mlwrite("bug: linsert");
- X return (FALSE);
- X }
- X if ((lp2=lalloc(n)) == NULL) /* Allocate new line */
- X return (FALSE);
- X copy_for_undo(lp1->l_bp); /* don't want preundodot to point
- X * at a new line if this is the
- X * first change */
- X lp3 = lp1->l_bp; /* Previous line */
- X lp3->l_fp = lp2; /* Link in */
- X lp2->l_fp = lp1;
- X lp1->l_bp = lp2;
- X lp2->l_bp = lp3;
- X for (i=0; i<n; ++i)
- X lp2->l_text[i] = c;
- X curwp->w_dotp = lp2;
- X curwp->w_doto = n;
- X tag_for_undo(lp2);
- X return (TRUE);
- X }
- X doto = curwp->w_doto; /* Save for later. */
- X if (lp1->l_used+n > lp1->l_size) { /* Hard: reallocate */
- X copy_for_undo(lp1);
- X /* first, create the new image */
- X if ((ntext=malloc(nsize = roundup(lp1->l_used+n))) == NULL)
- X return (FALSE);
- X memcpy(&ntext[0], &lp1->l_text[0], doto);
- X memset(&ntext[doto], c, n);
- X memcpy(&ntext[doto+n], &lp1->l_text[doto], lp1->l_used-doto );
- X free((char *)lp1->l_text);
- X lp1->l_text = ntext;
- X lp1->l_size = nsize;
- X lp1->l_used += n;
- X } else { /* Easy: in place */
- X copy_for_undo(lp1);
- X /* don't used memcpy: overlapping regions.... */
- X lp1->l_used += n;
- X cp2 = &lp1->l_text[lp1->l_used];
- X cp1 = cp2-n;
- X while (cp1 != &lp1->l_text[doto])
- X *--cp2 = *--cp1;
- X for (i=0; i<n; ++i) /* Add the characters */
- X lp1->l_text[doto+i] = c;
- X }
- X wp = wheadp; /* Update windows */
- X while (wp != NULL) {
- X if (wp->w_dotp == lp1) {
- X if (wp==curwp || wp->w_doto>doto)
- X wp->w_doto += n;
- X }
- X if (wp->w_mkp == lp1) {
- X if (wp->w_mko > doto)
- X wp->w_mko += n;
- X }
- X if (wp->w_ldmkp == lp1) {
- X if (wp->w_ldmko > doto)
- X wp->w_ldmko += n;
- X }
- X wp = wp->w_wndp;
- X }
- X if (curbp->b_nmmarks != NULL) { /* fix the named marks */
- X struct MARK *mp;
- X for (i = 0; i < 26; i++) {
- X mp = &(curbp->b_nmmarks[i]);
- X if (mp->markp == lp1) {
- X if (mp->marko > doto)
- X mp->marko += n;
- X }
- X }
- X }
- X return (TRUE);
- }
- X
- /*
- X * Insert a newline into the buffer at the current location of dot in the
- X * current window. The funny ass-backwards way it does things is not a botch;
- X * it just makes the last line in the file not a special case. Return TRUE if
- X * everything works out and FALSE on error (memory allocation failure). The
- X * update of dot and mark is a bit easier then in the above case, because the
- X * split forces more updating.
- X */
- lnewline()
- {
- X register char *cp1;
- X register char *cp2;
- X register LINE *lp1;
- X register LINE *lp2;
- X register int doto;
- X register WINDOW *wp;
- X
- X lchange(WFHARD|WFINS);
- X lp1 = curwp->w_dotp; /* Get the address and */
- X doto = curwp->w_doto; /* offset of "." */
- X if (lp1 != curbp->b_linep)
- X copy_for_undo(lp1);
- X if ((lp2=lalloc(doto)) == NULL) /* New first half line */
- X return (FALSE);
- X cp1 = &lp1->l_text[0]; /* Shuffle text around */
- X cp2 = &lp2->l_text[0];
- X while (cp1 != &lp1->l_text[doto])
- X *cp2++ = *cp1++;
- X cp2 = &lp1->l_text[0];
- X while (cp1 != &lp1->l_text[lp1->l_used])
- X *cp2++ = *cp1++;
- X lp1->l_used -= doto;
- X /* put lp2 in above lp1 */
- X lp2->l_bp = lp1->l_bp;
- X lp1->l_bp = lp2;
- X lp2->l_bp->l_fp = lp2;
- X lp2->l_fp = lp1;
- X tag_for_undo(lp2);
- X dumpuline(lp1);
- X wp = wheadp; /* Windows */
- X while (wp != NULL) {
- X if (wp->w_linep == lp1)
- X wp->w_linep = lp2;
- X if (wp->w_dotp == lp1) {
- X if (wp->w_doto < doto)
- X wp->w_dotp = lp2;
- X else
- X wp->w_doto -= doto;
- X }
- X if (wp->w_mkp == lp1) {
- X if (wp->w_mko < doto)
- X wp->w_mkp = lp2;
- X else
- X wp->w_mko -= doto;
- X }
- X if (wp->w_ldmkp == lp1) {
- X if (wp->w_ldmko < doto)
- X wp->w_ldmkp = lp2;
- X else
- X wp->w_ldmko -= doto;
- X }
- X wp = wp->w_wndp;
- X }
- X if (curbp->b_nmmarks != NULL) { /* fix the named marks */
- X int i;
- X struct MARK *mp;
- X for (i = 0; i < 26; i++) {
- X mp = &(curbp->b_nmmarks[i]);
- X if (mp->markp == lp1) {
- X if (mp->marko < doto)
- X mp->markp = lp2;
- X else
- X mp->marko -= doto;
- X }
- X }
- X }
- X return (TRUE);
- }
- X
- /*
- X * This function deletes "n" bytes, starting at dot. It understands how do deal
- X * with end of lines, etc. It returns TRUE if all of the characters were
- X * deleted, and FALSE if they were not (because dot ran into the end of the
- X * buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
- X */
- ldelete(n, kflag)
- long n; /* # of chars to delete */
- int kflag; /* put killed text in kill buffer flag */
- {
- X register char *cp1;
- X register char *cp2;
- X register LINE *dotp;
- X register LINE *nlp;
- X register int doto;
- X register int chunk;
- X register WINDOW *wp;
- X register int i,s;
- X
- X while (n != 0) {
- X dotp = curwp->w_dotp;
- X doto = curwp->w_doto;
- X if (dotp == curbp->b_linep) /* Hit end of buffer. */
- X return (FALSE);
- X chunk = dotp->l_used-doto; /* Size of chunk. */
- X if (chunk > (int)n)
- X chunk = (int)n;
- X if (chunk == 0) { /* End of line, merge. */
- X lchange(WFHARD|WFKILLS);
- X /* first take out any whole lines below this one */
- X nlp = lforw(dotp);
- X while (nlp != curbp->b_linep && llength(nlp)+1 < n) {
- X if (kflag) {
- X s = kinsert('\n');
- X for (i = 0; i < llength(nlp) &&
- X s == TRUE; i++)
- X s = kinsert(lgetc(nlp,i));
- X if (s != TRUE)
- X return(FALSE);
- X }
- X lremove(curbp,nlp);
- X toss_to_undo(nlp);
- X n -= llength(nlp)+1;
- X nlp = lforw(dotp);
- X }
- X if ((s = ldelnewline()) != TRUE)
- X return (s);
- X if (kflag && (s = kinsert('\n')) != TRUE)
- X return (s);
- X --n;
- X continue;
- X }
- X lchange(WFEDIT);
- X copy_for_undo(dotp);
- X cp1 = &dotp->l_text[doto]; /* Scrunch text. */
- X cp2 = cp1 + chunk;
- X if (kflag) { /* Kill? */
- X while (cp1 != cp2) {
- X if ((s = kinsert(*cp1)) != TRUE)
- X return (s);
- X ++cp1;
- X }
- X cp1 = &dotp->l_text[doto];
- X }
- X while (cp2 != &dotp->l_text[dotp->l_used])
- X *cp1++ = *cp2++;
- X dotp->l_used -= chunk;
- X wp = wheadp; /* Fix windows */
- X while (wp != NULL) {
- X if (wp->w_dotp==dotp && wp->w_doto > doto) {
- X wp->w_doto -= chunk;
- X if (wp->w_doto < doto)
- X wp->w_doto = doto;
- X }
- X if (wp->w_mkp==dotp && wp->w_mko > doto) {
- X wp->w_mko -= chunk;
- X if (wp->w_mko < doto)
- X wp->w_mko = doto;
- X }
- X if (wp->w_ldmkp==dotp && wp->w_ldmko > doto) {
- X wp->w_ldmko -= chunk;
- X if (wp->w_ldmko < doto)
- X wp->w_ldmko = doto;
- X }
- X wp = wp->w_wndp;
- X }
- X if (curbp->b_nmmarks != NULL) { /* fix the named marks */
- X struct MARK *mp;
- X for (i = 0; i < 26; i++) {
- X mp = &(curbp->b_nmmarks[i]);
- X if (mp->markp==dotp && mp->marko > doto) {
- X mp->marko -= chunk;
- X if (mp->marko < doto)
- X mp->marko = doto;
- X }
- X }
- X }
- X n -= chunk;
- X }
- X return (TRUE);
- }
- X
- /* getctext: grab and return a string with the text of
- X the current line
- */
- X
- char *getctext()
- X
- {
- X register LINE *lp; /* line to copy */
- X register int size; /* length of line to return */
- X register char *sp; /* string pointer into line */
- X register char *dp; /* string pointer into returned line */
- X char rline[NSTRING]; /* line to return */
- X
- X /* find the contents of the current line and its length */
- X lp = curwp->w_dotp;
- X sp = lp->l_text;
- X size = lp->l_used;
- X if (size >= NSTRING)
- X size = NSTRING - 1;
- X
- X /* copy it across */
- X dp = rline;
- X while (size--)
- X *dp++ = *sp++;
- X *dp = 0;
- X return(rline);
- }
- X
- #if ! SMALLER
- /* putctext: replace the current line with the passed in text */
- X
- putctext(iline)
- char *iline; /* contents of new line */
- {
- X register int status;
- X
- X /* delete the current line */
- X curwp->w_doto = 0; /* starting at the beginning of the line */
- X if ((status = deltoeol(TRUE, 1)) != TRUE)
- X return(status);
- X
- X /* insert the new line */
- X while (*iline) {
- X if (*iline == '\n') {
- X if (lnewline() != TRUE)
- X return(FALSE);
- X } else {
- X if (linsert(1, *iline) != TRUE)
- X return(FALSE);
- X }
- X ++iline;
- X }
- X status = lnewline();
- X backline(TRUE, 1);
- X return(status);
- }
- #endif
- X
- /*
- X * Delete a newline. Join the current line with the next line. If the next line
- X * is the magic header line always return TRUE; merging the last line with the
- X * header line can be thought of as always being a successful operation, even
- X * if nothing is done, and this makes the kill buffer work "right". Easy cases
- X * can be done by shuffling data around. Hard cases require that lines be moved
- X * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
- X * "ldelete" only.
- X */
- ldelnewline()
- {
- X register char *cp1;
- X register char *cp2;
- X register LINE *lp1;
- X register LINE *lp2;
- X register LINE *lp3;
- X register WINDOW *wp;
- X
- X lp1 = curwp->w_dotp;
- X /* if the current line is empty, remove it */
- X if (lp1->l_used == 0) { /* Blank line. */
- X lremove(curbp,lp1);
- X toss_to_undo(lp1);
- X return (TRUE);
- X }
- X lp2 = lp1->l_fp;
- X /* if the next line is empty, that's "currline\n\n", so we
- X remove the second \n by deleting the next line */
- X /* but never delete the newline on the last non-empty line */
- X if (lp2 == curbp->b_linep)
- X return (TRUE);
- X else if (lp2->l_used == 0) {
- X /* next line blank? */
- X lremove(curbp,lp2);
- X toss_to_undo(lp2);
- X return (TRUE);
- X }
- X /* no room in line above, make room */
- X if (lp2->l_used > lp1->l_size-lp1->l_used) {
- X char *ntext;
- X int nsize;
- X copy_for_undo(lp1);
- X /* first, create the new image */
- X if ((ntext=malloc(nsize = roundup(lp1->l_used + lp2->l_used)))
- X == NULL)
- X return (FALSE);
- X memcpy(&ntext[0], &lp1->l_text[0], lp1->l_used);
- X free((char *)lp1->l_text);
- X lp1->l_text = ntext;
- X }
- X cp1 = &lp1->l_text[lp1->l_used];
- X cp2 = &lp2->l_text[0];
- X while (cp2 != &lp2->l_text[lp2->l_used])
- X *cp1++ = *cp2++;
- X /* check all windows for references to the deleted line */
- X wp = wheadp;
- X while (wp != NULL) {
- X if (wp->w_linep == lp2)
- X wp->w_linep = lp1;
- X if (wp->w_dotp == lp2) {
- X wp->w_dotp = lp1;
- X wp->w_doto += lp1->l_used;
- X }
- X if (wp->w_mkp == lp2) {
- X wp->w_mkp = lp1;
- X wp->w_mko += lp1->l_used;
- X }
- X if (wp->w_ldmkp == lp2) {
- X wp->w_ldmkp = lp1;
- X wp->w_ldmko += lp1->l_used;
- X }
- X wp = wp->w_wndp;
- X }
- X if (curbp->b_nmmarks != NULL) { /* fix the named marks */
- X int i;
- X struct MARK *mp;
- X for (i = 0; i < 26; i++) {
- X mp = &(curbp->b_nmmarks[i]);
- X if (mp->markp == lp2) {
- X mp->markp = lp1;
- X mp->marko += lp1->l_used;
- X }
- X }
- X }
- X lp1->l_used += lp2->l_used;
- X lp1->l_fp = lp2->l_fp;
- X lp2->l_fp->l_bp = lp1;
- X dumpuline(lp1);
- X toss_to_undo(lp2);
- X return (TRUE);
- }
- X
- /*
- X * Delete all of the text saved in the kill buffer. Called by commands when a
- X * new kill context is being created. The kill buffer array is released, just
- X * in case the buffer has grown to immense size. No errors.
- X */
- kdelete()
- {
- X
- X if ((kregflag & KAPPEND) != 0)
- X kregflag = KAPPEND;
- X else
- X kregflag = KNEEDCLEAN;
- X
- }
- X
- /*
- X * Insert a character to the kill buffer, allocating new chunks as needed.
- X * Return TRUE if all is well, and FALSE on errors.
- X */
- X
- kinsert(c)
- int c; /* character to insert in the kill buffer */
- {
- X KILL *nchunk; /* ptr to newly malloced chunk */
- X KILLREG *kbp = &kbs[ukb];
- X
- X if ((kregflag & KNEEDCLEAN) && kbs[ukb].kbufh != NULL) {
- X KILL *kp; /* ptr to scan kill buffer chunk list */
- X
- X /* first, delete all the chunks */
- X kbs[ukb].kbufp = kbs[ukb].kbufh;
- X while (kbs[ukb].kbufp != NULL) {
- X kp = kbs[ukb].kbufp->d_next;
- X free((char *)(kbs[ukb].kbufp));
- X kbs[ukb].kbufp = kp;
- X }
- X
- X /* and reset all the kill buffer pointers */
- X kbs[ukb].kbufh = kbs[ukb].kbufp = NULL;
- X kbs[ukb].kused = KBLOCK;
- X
- X }
- X kregflag &= ~KNEEDCLEAN;
- X kbs[ukb].kbflag = kregflag;
- X
- X /* check to see if we need a new chunk */
- X if (kbp->kused >= KBLOCK || kbp->kbufh == NULL) {
- X if ((nchunk = (KILL *)malloc(sizeof(KILL))) == NULL)
- X return(FALSE);
- X if (kbp->kbufh == NULL) /* set head ptr if first time */
- X kbp->kbufh = nchunk;
- X /* point the current to this new one */
- X if (kbp->kbufp != NULL)
- X kbp->kbufp->d_next = nchunk;
- X kbp->kbufp = nchunk;
- X kbp->kbufp->d_next = NULL;
- X kbp->kused = 0;
- X }
- X
- X /* and now insert the character */
- X kbp->kbufp->d_chunk[kbp->kused++] = c;
- X return(TRUE);
- }
- X
- /* select one of the named registers for use with the following command */
- /* this could actually be handled as a command prefix, in kbdseq(), much
- X the way ^X-cmd and META-cmd are done, except that we need to be
- X able to accept any of
- X 3"adw "a3dw "ad3w
- X to delete 3 words into register a. So this routine gives us an
- X easy way to handle the second case. (The third case is handled in
- X operators(), the first in main())
- */
- usekreg(f,n)
- {
- X int c, status;
- X
- X /* take care of incrementing the buffer number, if we're replaying
- X a command via 'dot' */
- X incr_dot_kregnum();
- X
- X c = kbd_key();
- X
- X if (isdigit(c))
- X ukb = c - '0';
- X else if (islower(c))
- X ukb = c - 'a' + 10; /* named buffs are in 10 through 36 */
- X else if (isupper(c)) {
- X ukb = c - 'A' + 10;
- X kregflag |= KAPPEND;
- X } else {
- X TTbeep();
- X return (FALSE);
- X }
- X
- X /* get the next command from the keyboard */
- X c = kbd_seq();
- X
- X /* allow second chance for entering counts */
- X if (f == FALSE) {
- X do_num_proc(&c,&f,&n);
- X do_rept_arg_proc(&c,&f,&n);
- X }
- X
- X /* and execute the command */
- X status = execute(kcod2fnc(c), f, n);
- X
- X ukb = 0;
- X kregflag = 0;
- X
- X return(status);
- X
- }
- X
- /* buffers 0 through 9 are circulated automatically for full-line deletes */
- /* we re-use one of them until the KLINES flag is on, then we advance */
- /* to the next */
- kregcirculate(killing)
- {
- X static lastkb; /* index of the real "0 */
- X
- X if (ukb >= 10) /* then the user specified a lettered buffer */
- X return;
- X
- X /* we only allow killing into the real "0 */
- X /* ignore any other buffer spec */
- X if (killing) {
- X if ((kbs[lastkb].kbflag & KLINES) &&
- X ! (kbs[lastkb].kbflag & KYANK)) {
- X if (--lastkb < 0) lastkb = 9;
- X kbs[lastkb].kbflag = 0;
- X }
- X ukb = lastkb;
- X } else {
- X /* let 0 pass unmolested -- it is the default */
- X if (ukb == 0) {
- X ukb = lastkb;
- X } else {
- X /* for the others, if the current "0 has lines in it, it
- X must be `"1', else "1 is `"1'. get it? */
- X if (kbs[lastkb].kbflag & KLINES)
- X ukb = (lastkb + ukb - 1) % 10;
- X else
- X ukb = (lastkb + ukb) % 10;
- X }
- X }
- X
- }
- X
- putbefore(f,n)
- {
- X return doput(f,n,FALSE,FALSE);
- }
- X
- putafter(f,n)
- {
- X return doput(f,n,TRUE,FALSE);
- }
- X
- lineputbefore(f,n)
- {
- X return doput(f,n,FALSE,TRUE);
- }
- X
- lineputafter(f,n)
- {
- X return doput(f,n,TRUE,TRUE);
- }
- X
- X
- doput(f,n,after,putlines)
- {
- X int s, oukb, lining;
- X
- X if (!f)
- X n = 1;
- X
- X oukb = ukb;
- X kregcirculate(FALSE);
- X if (kbs[ukb].kbufh == NULL) {
- X if (ukb != 0)
- X mlwrite("Nothing in register %c",
- X (oukb<10)? oukb+'0' : oukb-10+'a');
- X TTbeep();
- X return(FALSE);
- X }
- X lining = (putlines == TRUE || (kbs[ukb].kbflag & KLINES));
- X if (lining) {
- X if (after && curwp->w_dotp != curbp->b_linep)
- X curwp->w_dotp = lforw(curwp->w_dotp);
- X curwp->w_doto = 0;
- X } else {
- X if (after && curwp->w_doto != llength(curwp->w_dotp))
- X forwchar(TRUE,1);
- X }
- X setmark();
- X s = put(n,lining);
- X if (s == TRUE)
- X swapmark();
- X if (curwp->w_dotp == curbp->b_linep)
- X curwp->w_dotp = lback(curwp->w_dotp);
- X if (lining)
- X firstnonwhite(FALSE,0);
- X ukb = 0;
- X return (s);
- }
- X
- /*
- X * Put text back from the kill register.
- X */
- put(n,aslines)
- {
- X register int c;
- X register int i;
- X int wasnl, suppressnl;
- X register char *sp; /* pointer into string to insert */
- X KILL *kp; /* pointer into kill register */
- X
- X if (n < 0)
- X return FALSE;
- X
- X /* make sure there is something to put */
- X if (kbs[ukb].kbufh == NULL)
- X return TRUE; /* not an error, just nothing */
- X
- X suppressnl = FALSE;
- X wasnl = FALSE;
- X
- X /* for each time.... */
- X while (n--) {
- X kp = kbs[ukb].kbufh;
- X while (kp != NULL) {
- X if (kp->d_next == NULL)
- X i = kbs[ukb].kused;
- X else
- X i = KBLOCK;
- X sp = kp->d_chunk;
- X while (i--) {
- X if ((c = *sp++) == '\n') {
- X if (lnewline() != TRUE)
- X return FALSE;
- X wasnl = TRUE;
- X } else {
- X if (curwp->w_dotp == curbp->b_linep)
- X suppressnl = TRUE;
- X if (linsert(1, c) != TRUE)
- X return FALSE;
- X wasnl = FALSE;
- X }
- X }
- X kp = kp->d_next;
- X }
- X if (wasnl) {
- X if (suppressnl) {
- X if (ldelnewline() != TRUE)
- X return FALSE;
- X }
- X } else {
- X if (aslines && !suppressnl) {
- X if (lnewline() != TRUE)
- X return FALSE;
- X }
- X }
- X }
- X curwp->w_flag |= WFHARD;
- X return (TRUE);
- }
- SHAR_EOF
- chmod 0444 line.c ||
- echo 'restore of line.c failed'
- Wc_c="`wc -c < 'line.c'`"
- test 20714 -eq "$Wc_c" ||
- echo 'line.c: original size 20714, current size' "$Wc_c"
- # ============= lock.c ==============
- echo 'x - extracting lock.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'lock.c' &&
- /* LOCK: File locking command routines for MicroEMACS
- X written by Daniel Lawrence
- X */
- X
- #include <stdio.h>
- #include "estruct.h"
- #include "edef.h"
- X
- #if FILOCK
- #if BSD
- #include <sys/errno.h>
- X
- extern int sys_nerr; /* number of system error messages defined */
- extern char *sys_errlist[]; /* list of message texts */
- extern int errno; /* current error */
- X
- char *lname[NLOCKS]; /* names of all locked files */
- int numlocks; /* # of current locks active */
- X
- /* lockchk: check a file for locking and add it to the list */
- X
- lockchk(fname)
- X
- char *fname; /* file to check for a lock */
- X
- {
- X register int i; /* loop indexes */
- X register int status; /* return status */
- X char *undolock();
- X
- X /* check to see if that file is already locked here */
- X if (numlocks > 0)
- X for (i=0; i < numlocks; ++i)
- X if (strcmp(fname, lname[i]) == 0)
- X return(TRUE);
- X
- X /* if we have a full locking table, bitch and leave */
- X if (numlocks == NLOCKS) {
- X mlwrite("LOCK ERROR: Lock table full");
- X return(ABORT);
- X }
- X
- X /* next, try to lock it */
- X status = lock(fname);
- X if (status == ABORT) /* file is locked, no override */
- X return(ABORT);
- X if (status == FALSE) /* locked, overriden, dont add to table */
- X return(TRUE);
- X
- X /* we have now locked it, add it to our table */
- X lname[++numlocks - 1] = malloc(strlen(fname) + 1);
- X if (lname[numlocks - 1] == NULL) { /* malloc failure */
- X undolock(fname); /* free the lock */
- X mlwrite("Cannot lock, out of memory");
- X --numlocks;
- X return(ABORT);
- X }
- X
- X /* everthing is cool, add it to the table */
- X strcpy(lname[numlocks-1], fname);
- X return(TRUE);
- }
- X
- /* lockrel: release all the file locks so others may edit */
- X
- lockrel()
- X
- {
- X register int i; /* loop index */
- X register int status; /* status of locks */
- X register int s; /* status of one unlock */
- X
- X status = TRUE;
- X if (numlocks > 0)
- X for (i=0; i < numlocks; ++i) {
- X if ((s = unlock(lname[i])) != TRUE)
- X status = s;
- X free(lname[i]);
- X }
- X numlocks = 0;
- X return(status);
- }
- X
- /* lock: Check and lock a file from access by others
- X returns TRUE = files was not locked and now is
- X FALSE = file was locked and overridden
- X ABORT = file was locked, abort command
- */
- X
- lock(fname)
- X
- char *fname; /* file name to lock */
- X
- {
- X register char *locker; /* lock error message */
- X register int status; /* return status */
- X char msg[NSTRING]; /* message string */
- X char *dolock();
- X
- X /* attempt to lock the file */
- X locker = dolock(fname);
- X if (locker == NULL) /* we win */
- X return(TRUE);
- X
- X /* file failed...abort */
- X if (strncmp(locker, "LOCK", 4) == 0) {
- X lckerror(locker);
- X return(ABORT);
- X }
- X
- X /* someone else has it....override? */
- X strcpy(msg, "File in use by ");
- X strcat(msg, locker);
- X strcat(msg, ", overide?");
- X status = mlyesno(msg); /* ask them */
- X if (status == TRUE)
- X return(FALSE);
- X else
- X return(ABORT);
- }
- X
- /* unlock: Unlock a file
- X this only warns the user if it fails
- X */
- X
- unlock(fname)
- X
- char *fname; /* file to unlock */
- X
- {
- X register char *locker; /* undolock return string */
- X char *undolock();
- X
- X /* unclock and return */
- X locker = undolock(fname);
- X if (locker == NULL)
- X return(TRUE);
- X
- X /* report the error and come back */
- X lckerror(locker);
- X return(FALSE);
- }
- X
- lckerror(errstr) /* report a lock error */
- X
- char *errstr; /* lock error string to print out */
- X
- {
- X char obuf[NSTRING]; /* output buffer for error message */
- X
- X strcpy(obuf, errstr);
- X strcat(obuf, " - ");
- X if (errno < sys_nerr)
- X strcat(obuf, sys_errlist[errno]);
- X else
- X strcat(obuf, "[can not get system error message]");
- X mlwrite(obuf);
- }
- #endif
- #else
- lckhello() /* dummy function */
- {
- }
- #endif
- SHAR_EOF
- chmod 0444 lock.c ||
- echo 'restore of lock.c failed'
- Wc_c="`wc -c < 'lock.c'`"
- test 3557 -eq "$Wc_c" ||
- echo 'lock.c: original size 3557, current size' "$Wc_c"
- # ============= main.c ==============
- echo 'x - extracting main.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'main.c' &&
- /*
- X * This used to be MicroEMACS 3.9
- X * written by Dave G. Conroy.
- X * substatially modified by Daniel M. Lawrence
- X *
- X * (C)opyright 1987 by Daniel M. Lawrence
- X * MicroEMACS 3.9 can be copied and distributed freely for any
- X * non-commercial purposes. MicroEMACS 3.9 can only be incorporated
- X * into commercial software with the permission of the current author.
- X *
- X * Turned into "VI Like Emacs", a.k.a. vile, by Paul Fox
- SHAR_EOF
- true || echo 'restore of main.c failed'
- echo 'End of Vile part 8'
- echo 'File main.c is continued in part 9'
- echo 9 > _shar_seq_.tmp
- exit 0
- --
- paul fox, pgf@cayman.com, (617)494-1999
- Cayman Systems, 26 Landsdowne St., Cambridge, MA 02139
-