home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************************
- * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE *
- * is provided to you without charge, and with no warranty. You may give *
- * away copies of JOVE, including sources, provided that this notice is *
- * included in all the files. *
- ***************************************************************************/
-
- #include "jove.h"
- #include "io.h"
- #include "re.h"
- #include "ctype.h"
-
- #ifdef MAC
- # include "mac.h"
- #else
- # include <sys/stat.h>
- #endif
-
- #ifdef MAC
- # undef private
- # define private
- #endif
-
- #ifdef LINT_ARGS
- private Bufpos * doisearch(int, int, int);
-
- private void
- IncSearch(int),
- replace(int, int);
- private int
- isearch(int, Bufpos *),
- lookup(char *, char *, char *, char *),
- substitute(int, Line *, int, Line *, int);
- #else
- private Bufpos * doisearch();
-
- private void
- IncSearch(),
- replace();
- private int
- isearch(),
- lookup(),
- substitute();
- #endif /* LINT_ARGS */
-
- #ifdef MAC
- # undef private
- # define private static
- #endif
-
- private int
- substitute(query, l1, char1, l2, char2)
- Line *l1,
- *l2;
- {
- Line *lp;
- int numdone = 0,
- offset = curchar,
- stop = NO;
- disk_line UNDO_da = 0;
- Line *UNDO_lp = 0;
-
- lsave();
- REdirection = FORWARD;
-
- lp = l1;
- for (lp = l1; (lp != l2->l_next) && !stop; lp = lp->l_next) {
- offset = (lp == l1) ? char1 : 0;
- while (!stop && re_lindex(lp, offset, compbuf, alternates, 0)) {
- if (lp == l2 && REeom > char2) /* nope, leave this alone */
- break;
- DotTo(lp, REeom);
- offset = curchar;
- if (query) {
- message("Replace (Type '?' for help)? ");
- reswitch: redisplay();
- switch (CharUpcase(getchar())) {
- case '.':
- stop = YES;
- /* Fall into ... */
-
- case ' ':
- case 'Y':
- break;
-
- case BS:
- case RUBOUT:
- case 'N':
- if (linebuf[offset++] == '\0')
- goto nxtline;
- continue;
-
- case CTL('W'):
- re_dosub(linebuf, YES);
- numdone += 1;
- offset = curchar = REbom;
- makedirty(curline);
- /* Fall into ... */
-
- case CTL('R'):
- case 'R':
- RErecur();
- offset = curchar;
- lp = curline;
- continue;
-
- case CTL('U'):
- case 'U':
- if (UNDO_lp == 0)
- continue;
- lp = UNDO_lp;
- lp->l_dline = UNDO_da | DIRTY;
- offset = 0;
- numdone -= 1;
- continue;
-
- case 'P':
- case '!':
- query = 0;
- break;
-
- case CR:
- case LF:
- case 'Q':
- goto done;
-
- case CTL('L'):
- RedrawDisplay();
- goto reswitch;
-
- default:
- rbell();
- message("Space or Y, Period, Rubout or N, C-R or R, C-W, C-U or U, P or !, Return.");
- goto reswitch;
- }
- }
- re_dosub(linebuf, NO);
- numdone += 1;
- modify();
- offset = curchar = REeom;
- makedirty(curline);
- if (query) {
- message(mesgbuf); /* no blinking */
- redisplay(); /* show the change */
- }
- UNDO_da = curline->l_dline;
- UNDO_lp = curline;
- if (linebuf[offset] == 0)
- nxtline: break;
- }
- }
- done: return numdone;
- }
-
- /* prompt for search and replacement strings and do the substitution */
- private void
- replace(query, inreg)
- {
- Mark *m;
- char *rep_ptr;
- Line *l1 = curline,
- *l2 = curbuf->b_last;
- int char1 = curchar,
- char2 = length(curbuf->b_last),
- numdone;
-
- if (inreg) {
- m = CurMark();
- l2 = m->m_line;
- char2 = m->m_char;
- (void) fixorder(&l1, &char1, &l2, &char2);
- }
-
- /* get search string */
- strcpy(rep_search, ask(rep_search[0] ? rep_search : (char *) 0, ProcFmt));
- REcompile(rep_search, UseRE, compbuf, alternates);
- /* Now the replacement string. Do_ask() so the user can play with
- the default (previous) replacement string by typing C-R in ask(),
- OR, he can just hit Return to replace with nothing. */
- rep_ptr = do_ask("\r\n", (int (*)()) 0, rep_str, ": %f %s with ", rep_search);
- if (rep_ptr == 0)
- rep_ptr = NullStr;
- strcpy(rep_str, rep_ptr);
-
- if (((numdone = substitute(query, l1, char1, l2, char2)) != 0) &&
- (inreg == NO)) {
- do_set_mark(l1, char1);
- add_mess(" "); /* just making things pretty */
- } else
- message("");
- add_mess("(%d substitution%n)", numdone, numdone);
- }
-
- void
- RegReplace()
- {
- replace(0, YES);
- }
-
- void
- QRepSearch()
- {
- replace(1, NO);
- }
-
- void
- RepSearch()
- {
- replace(0, NO);
- }
-
- /* Lookup a tag in tag file FILE. FILE is assumed to be sorted
- alphabetically. The FASTTAGS code, which is implemented with
- a binary search, depends on this assumption. If it's not true
- it is possible to comment out the fast tag code (which is clearly
- labeled) and everything else will just work. */
-
- private int
- lookup(searchbuf, filebuf, tag, file)
- char *searchbuf,
- *filebuf,
- *tag,
- *file;
- {
- register int taglen = strlen(tag);
- char line[BUFSIZ],
- pattern[128];
- register File *fp;
- struct stat stbuf;
- int fast = YES,
- success = NO;
- register off_t lower, upper;
-
- sprintf(pattern, "^%s[^\t]*\t*\\([^\t]*\\)\t*[?/]\\([^?/]*\\)[?/]", tag);
- fp = open_file(file, iobuff, F_READ, !COMPLAIN, QUIET);
- if (fp == NIL)
- return 0;
-
- /* ********BEGIN FAST TAG CODE******** */
-
- if (stat(file, &stbuf) < 0)
- fast = NO;
- else {
- lower = 0;
- upper = stbuf.st_size;
- if (upper - lower < BUFSIZ)
- fast = NO;
- }
- if (fast == YES) for (;;) {
- off_t mid;
- int whichway,
- chars_eq;
-
- if (upper - lower < BUFSIZ) {
- f_seek(fp, lower);
- break; /* stop this nonsense */
- }
- mid = (lower + upper) / 2;
- f_seek(fp, mid);
- f_toNL(fp);
- if (f_gets(fp, line, sizeof line) == EOF)
- break;
- chars_eq = numcomp(line, tag);
- if (chars_eq == taglen && iswhite(line[chars_eq]))
- goto found;
- whichway = line[chars_eq] - tag[chars_eq];
- if (whichway < 0) { /* line is BEFORE tag */
- lower = mid;
- continue;
- } else if (whichway > 0) { /* line is AFTER tag */
- upper = mid;
- continue;
- }
- }
- f_toNL(fp);
- /* END FAST TAG CODE */
-
- while (f_gets(fp, line, sizeof line) != EOF) {
- int cmp;
-
- if (line[0] > *tag)
- break;
- else if ((cmp = strncmp(line, tag, taglen)) > 0)
- break;
- else if (cmp < 0)
- continue;
- /* if we get here, we've found the match */
- found: if (!LookingAt(pattern, line, 0)) {
- complain("I thought I saw it!");
- break;
- } else {
- putmatch(1, filebuf, FILESIZE);
- putmatch(2, searchbuf, 100);
- success = YES;
- break;
- }
- }
- close_file(fp);
-
- if (success == NO)
- s_mess("Can't find tag \"%s\".", tag);
- return success;
- }
-
- #ifndef MSDOS
- char TagFile[FILESIZE] = "./tags";
- #else /* MSDOS */
- char TagFile[FILESIZE] = "tags";
- #endif /* MSDOS */
-
- void
- find_tag(tag, localp)
- char *tag;
- {
- char filebuf[FILESIZE],
- sstr[100],
- tfbuf[FILESIZE];
- register Bufpos *bp;
- register Buffer *b;
- char *tagfname;
-
- if (!localp) {
- char prompt[128];
-
- sprintf(prompt, "With tag file (%s default): ", TagFile);
- tagfname = ask_file(prompt, TagFile, tfbuf);
- } else
- tagfname = TagFile;
- if (lookup(sstr, filebuf, tag, tagfname) == 0)
- return;
- set_mark();
- b = do_find(curwind, filebuf, 0);
- if (curbuf != b)
- SetABuf(curbuf);
- SetBuf(b);
- if ((bp = dosearch(sstr, BACKWARD, 0)) == 0 &&
- ((bp = dosearch(sstr, FORWARD, 0)) == 0))
- message("Well, I found the file, but the tag is missing.");
- else
- SetDot(bp);
- }
-
- void
- FindTag()
- {
- int localp = !is_an_arg();
- char tag[128];
-
- strcpy(tag, ask((char *) 0, ProcFmt));
- find_tag(tag, localp);
- }
-
- /* Find Tag at Dot. */
-
- void
- FDotTag()
- {
- int c1 = curchar,
- c2 = c1;
- char tagname[50];
-
- if (!ismword(linebuf[curchar]))
- complain("Not a tag!");
- while (c1 > 0 && ismword(linebuf[c1 - 1]))
- c1 -= 1;
- while (ismword(linebuf[c2]))
- c2 += 1;
-
- null_ncpy(tagname, linebuf + c1, c2 - c1);
- find_tag(tagname, !is_an_arg());
- }
-
- /* I-search returns a code saying what to do:
- STOP: We found the match, so unwind the stack and leave
- where it is.
- DELETE: Rubout the last command.
- BACKUP: Back up to where the isearch was last NOT failing.
-
- When a character is typed it is appended to the search string, and
- then, isearch is called recursively. When C-S or C-R is typed, isearch
- is again called recursively. */
-
- #define STOP 1
- #define DELETE 2
- #define BACKUP 3
- #define TOSTART 4
-
- static char ISbuf[128],
- *incp = 0;
- int SExitChar = CR;
-
- #define cmp_char(a, b) ((a) == (b) || (CaseIgnore && (CharUpcase(a) == CharUpcase(b))))
-
- static Bufpos *
- doisearch(dir, c, failing)
- register int c,
- dir,
- failing;
- {
- static Bufpos buf;
- Bufpos *bp;
- extern int okay_wrap;
-
- if (c == CTL('S') || c == CTL('R'))
- goto dosrch;
-
- if (failing)
- return 0;
- DOTsave(&buf);
- if (dir == FORWARD) {
- if (cmp_char(linebuf[curchar], c)) {
- buf.p_char = curchar + 1;
- return &buf;
- }
- } else {
- if (look_at(ISbuf))
- return &buf;
- }
- dosrch: okay_wrap = YES;
- if ((bp = dosearch(ISbuf, dir, 0)) == 0)
- rbell(); /* ring the first time there's no match */
- okay_wrap = NO;
- return bp;
- }
-
- void
- IncFSearch()
- {
- IncSearch(FORWARD);
- }
-
- void
- IncRSearch()
- {
- IncSearch(BACKWARD);
- }
-
- private void
- IncSearch(dir)
- {
- Bufpos save_env;
-
- DOTsave(&save_env);
- ISbuf[0] = 0;
- incp = ISbuf;
- if (isearch(dir, &save_env) == TOSTART)
- SetDot(&save_env);
- else {
- if (LineDist(curline, save_env.p_line) >= MarkThresh)
- do_set_mark(save_env.p_line, save_env.p_char);
- }
- setsearch(ISbuf);
- }
-
- /* Nicely recursive. */
-
- private int
- isearch(dir, bp)
- Bufpos *bp;
- {
- Bufpos pushbp;
- int c,
- ndir,
- failing;
- char *orig_incp;
-
- if (bp != 0) { /* Move to the new position. */
- pushbp.p_line = bp->p_line;
- pushbp.p_char = bp->p_char;
- SetDot(bp);
- failing = 0;
- } else {
- DOTsave(&pushbp);
- failing = 1;
- }
- orig_incp = incp;
- ndir = dir; /* Same direction as when we got here, unless
- we change it with C-S or C-R. */
- for (;;) {
- SetDot(&pushbp);
- message(NullStr);
- if (failing)
- add_mess("Failing ");
- if (dir == BACKWARD)
- add_mess("reverse-");
- add_mess("I-search: %s", ISbuf);
- DrawMesg(NO);
- add_mess(NullStr); /* tell me this is disgusting ... */
- c = getch();
- if (c == SExitChar)
- return STOP;
- if (c == AbortChar) {
- /* If we're failing, we backup until we're no longer
- failing or we've reached the beginning; else, we
- just about the search and go back to the start. */
- if (failing)
- return BACKUP;
- return TOSTART;
- }
- switch (c) {
- case RUBOUT:
- case BS:
- return DELETE;
-
- case CTL('\\'):
- c = CTL('S');
-
- case CTL('S'):
- case CTL('R'):
- /* If this is the first time through and we have a
- search string left over from last time, use that
- one now. */
- if (incp == ISbuf) {
- strcpy(ISbuf, getsearch());
- incp = &ISbuf[strlen(ISbuf)];
- }
- ndir = (c == CTL('S')) ? FORWARD : BACKWARD;
- /* If we're failing and we're not changing our
- direction, don't recur since there's no way
- the search can work. */
- if (failing && ndir == dir) {
- rbell();
- continue;
- }
- break;
-
- case '\\':
- if (incp > &ISbuf[(sizeof ISbuf) - 1]) {
- rbell();
- continue;
- }
- *incp++ = '\\';
- add_mess("\\");
- /* Fall into ... */
-
- case CTL('Q'):
- case CTL('^'):
- add_mess("");
- c = getch() | 0400;
- /* Fall into ... */
-
- default:
- if (c & 0400)
- c &= CHARMASK;
- else {
- #ifdef IBMPC
- if (c == RUBOUT || c == 0xff || (c < ' ' && c != '\t')) {
- #else
- if (c > RUBOUT || (c < ' ' && c != '\t')) {
- #endif
- Ungetc(c);
- return STOP;
- }
- }
- if (incp > &ISbuf[(sizeof ISbuf) - 1]) {
- rbell();
- continue;
- }
- *incp++ = c;
- *incp = 0;
- break;
- }
- add_mess("%s", orig_incp);
- add_mess(" ..."); /* so we know what's going on */
- DrawMesg(NO); /* do it now */
- switch (isearch(ndir, doisearch(ndir, c, failing))) {
- case TOSTART:
- return TOSTART;
-
- case STOP:
- return STOP;
-
- case BACKUP:
- /* If we're not failing, we just continue to to the
- for loop; otherwise we keep returning to the
- previous levels until we find one that isn't
- failing OR we reach the beginning. */
- if (failing)
- return BACKUP;
- /* Fall into ... */
-
- case DELETE:
- incp = orig_incp;
- *incp = 0;
- continue;
- }
- }
- }
-