1: /*************************************************************************
   2:  * This program is copyright (C) 1985, 1986 by Jonathan Payne.  It is    *
   3:  * provided to you without charge for use only on a licensed Unix        *
   4:  * system.  You may copy JOVE provided that this notice is included with *
   5:  * the copy.  You may not sell copies of this program or versions        *
   6:  * modified for use on microcomputer systems, unless the copies are      *
   7:  * included with a Unix system distribution and the source is provided.  *
   8:  *************************************************************************/
   9: 
  10: #include "jove.h"
  11: #include "io.h"
  12: #include "re.h"
  13: 
  14: static
  15: substitute(query, l1, char1, l2, char2)
  16: Line    *l1,
  17:     *l2;
  18: {
  19:     Line    *lp;
  20:     int numdone = 0,
  21:         offset = curchar,
  22:         stop = 0;
  23:     disk_line   UNDO_da = 0;
  24:     Line        *UNDO_lp = 0;
  25: 
  26:     lsave();
  27:     REdirection = FORWARD;
  28: 
  29:     lp = l1;
  30:     for (lp = l1; (lp != l2->l_next) && !stop; lp = lp->l_next) {
  31:         offset = (lp == l1) ? char1 : 0;
  32:         while (!stop && re_lindex(lp, offset, compbuf, alternates, 0)) {
  33:             if (lp == l2 && REeom > char2)  /* nope, leave this alone */
  34:                 break;
  35:             DotTo(lp, REeom);
  36:             offset = curchar;
  37:             if (query) {
  38:                 message("Replace (Type '?' for help)? ");
  39: reswitch:           redisplay();
  40:                 switch (Upper(getchar())) {
  41:                 case '.':
  42:                     stop++;
  43:                     /* Fall into ... */
  44: 
  45:                 case ' ':
  46:                 case 'Y':
  47:                     break;
  48: 
  49:                 case BS:
  50:                 case RUBOUT:
  51:                 case 'N':
  52:                     if (linebuf[offset++] == '\0')
  53:                         goto nxtline;
  54:                     continue;
  55: 
  56:                 case CTL(W):
  57:                     re_dosub(linebuf, YES);
  58:                     numdone++;
  59:                     offset = curchar = REbom;
  60:                     makedirty(curline);
  61:                     /* Fall into ... */
  62: 
  63:                 case CTL(R):
  64:                 case 'R':
  65:                     RErecur();
  66:                     offset = curchar;
  67:                     lp = curline;
  68:                     continue;
  69: 
  70:                 case CTL(U):
  71:                 case 'U':
  72:                     if (UNDO_lp == 0)
  73:                         continue;
  74:                     lp = UNDO_lp;
  75:                     lp->l_dline = UNDO_da | DIRTY;
  76:                     offset = 0;
  77:                     numdone--;
  78:                     continue;
  79: 
  80:                 case 'P':
  81:                 case '!':
  82:                     query = 0;
  83:                     break;
  84: 
  85:                 case CR:
  86:                 case LF:
  87:                 case 'Q':
  88:                     goto done;
  89: 
  90:                 case CTL(L):
  91:                     RedrawDisplay();
  92:                     goto reswitch;
  93: 
  94:                 default:
  95:                     rbell();
  96: message("Space or Y, Period, Rubout or N, C-R or R, C-W, C-U or U, P or !, Return.");
  97:                     goto reswitch;
  98:                 }
  99:             }
 100:             re_dosub(linebuf, NO);
 101:             numdone++;
 102:             modify();
 103:             offset = curchar = REeom;
 104:             makedirty(curline);
 105:             if (query) {
 106:                 message(mesgbuf);   /* No blinking. */
 107:                 redisplay();        /* Show the change. */
 108:             }
 109:             UNDO_da = curline->l_dline;
 110:             UNDO_lp = curline;
 111:             if (linebuf[offset] == 0)
 112: nxtline:            break;
 113:         }
 114:     }
 115:     SetMark();
 116: done:   s_mess("%d substitution%n.", numdone, numdone);
 117: }
 118: 
 119: /* Prompt for search and replacement strings and do the substitution.  The
 120:    point is restored when we're done. */
 121: 
 122: static
 123: replace(query, inreg)
 124: {
 125:     Mark    *save = MakeMark(curline, curchar, FLOATER),
 126:         *m;
 127:     char    *rep_ptr;
 128:     Line    *l1 = curline,
 129:         *l2 = curbuf->b_last;
 130:     int char1 = curchar,
 131:         char2 = length(curbuf->b_last);
 132: 
 133:     if (inreg) {
 134:         m = CurMark();
 135:         l2 = m->m_line;
 136:         char2 = m->m_char;
 137:         (void) fixorder(&l1, &char1, &l2, &char2);
 138:     }
 139: 
 140:     /* Get search string. */
 141:     strcpy(rep_search, ask(rep_search[0] ? rep_search : (char *) 0, ProcFmt));
 142:     REcompile(rep_search, UseRE, compbuf, alternates);
 143:     /* Now the replacement string.  Do_ask() so the user can play with
 144: 	   the default (previous) replacement string by typing C-R in ask(),
 145: 	   OR, he can just hit Return to replace with nothing. */
 146:     rep_ptr = do_ask("\r\n", (int (*)()) 0, rep_str, ": %f %s with ", rep_search);
 147:     if (rep_ptr == 0)
 148:         rep_ptr = NullStr;
 149:     strcpy(rep_str, rep_ptr);
 150: 
 151:     substitute(query, l1, char1, l2, char2);
 152:     ToMark(save);
 153:     DelMark(save);
 154: }
 155: 
 156: RegReplace()
 157: {
 158:     replace(0, YES);
 159: }
 160: 
 161: QRepSearch()
 162: {
 163:     replace(1, NO);
 164: }
 165: 
 166: RepSearch()
 167: {
 168:     replace(0, NO);
 169: }
 170: 
 171: /* C tags package. */
 172: 
 173: static
 174: lookup(searchbuf, filebuf, tag, file)
 175: char    *searchbuf,
 176:     *filebuf,
 177:     *tag,
 178:     *file;
 179: {
 180:     register int    taglen = strlen(tag);
 181:     char    line[128],
 182:         pattern[100];
 183:     File    *fp;
 184: 
 185:     fp = open_file(file, iobuff, F_READ, !COMPLAIN, QUIET);
 186:     if (fp == NIL)
 187:         return 0;
 188:     sprintf(pattern, "^%s[^\t]*\t\\([^\t]*\\)\t[?/]\\(.*\\)[?/]$", tag);
 189:     while (f_gets(fp, line, sizeof line) != EOF) {
 190:         if (line[0] != *tag || strncmp(tag, line, taglen) != 0)
 191:             continue;
 192:         if (!LookingAt(pattern, line, 0)) {
 193:             complain("I thought I saw it!");
 194:             break;
 195:         } else {
 196:             putmatch(2, searchbuf, 100);
 197:             putmatch(1, filebuf, 100);
 198:             close_file(fp);
 199:             return 1;
 200:         }
 201:     }
 202:     f_close(fp);
 203:     s_mess("Can't find tag \"%s\".", tag);
 204:     return 0;
 205: }
 206: 
 207: char    TagFile[128] = "./tags";
 208: 
 209: find_tag(tag, localp)
 210: char    *tag;
 211: {
 212:     char    filebuf[FILESIZE],
 213:         sstr[100];
 214:     register Bufpos *bp;
 215:     register Buffer *b;
 216:     char    *tagfname;
 217: 
 218:     if (!localp)
 219:         tagfname = ask(TagFile, "With tag file (%s default): ", TagFile);
 220:     else
 221:         tagfname = TagFile;
 222:     if (lookup(sstr, filebuf, tag, tagfname) == 0)
 223:         return;
 224:     SetMark();
 225:     b = do_find(curwind, filebuf, 0);
 226:     if (curbuf != b)
 227:         SetABuf(curbuf);
 228:     SetBuf(b);
 229:     if ((bp = dosearch(sstr, BACKWARD, 0)) == 0 &&
 230:         (WrapScan || ((bp = dosearch(sstr, FORWARD, 0)) == 0)))
 231:         message("Well, I found the file, but the tag is missing.");
 232:     else
 233:         SetDot(bp);
 234: }
 235: 
 236: FindTag()
 237: {
 238:     int localp = !exp_p;
 239:     char    tag[128];
 240: 
 241:     strcpy(tag, ask((char *) 0, ProcFmt));
 242:     find_tag(tag, localp);
 243: }
 244: 
 245: /* Find Tag at Dot. */
 246: 
 247: FDotTag()
 248: {
 249:     int c1 = curchar,
 250:         c2 = c1;
 251:     char    tagname[50];
 252: 
 253:     if (!ismword(linebuf[curchar]))
 254:         complain("Not a tag!");
 255:     while (c1 > 0 && ismword(linebuf[c1 - 1]))
 256:         c1--;
 257:     while (ismword(linebuf[c2]))
 258:         c2++;
 259: 
 260:     null_ncpy(tagname, linebuf + c1, c2 - c1);
 261:     find_tag(tagname, !exp_p);
 262: }
 263: 
 264: /* I-search returns a code saying what to do:
 265:    STOP:	We found the match, so unwind the stack and leave
 266: 		where it is.
 267:    DELETE:	Rubout the last command.
 268:    BACKUP:	Back up to where the isearch was last NOT failing.
 269: 
 270:    When a character is typed it is appended to the search string, and
 271:    then, isearch is called recursively.  When C-S or C-R is typed, isearch
 272:    is again called recursively. */
 273: 
 274: #define STOP    1
 275: #define DELETE  2
 276: #define BACKUP  3
 277: #define TOSTART 4
 278: 
 279: static char ISbuf[128],
 280:         *incp = 0;
 281: int SExitChar = CR;
 282: 
 283: #define cmp_char(a, b)  ((a) == (b) || (CaseIgnore && (Upper(a) == Upper(b))))
 284: 
 285: static Bufpos *
 286: doisearch(dir, c, failing)
 287: register int    c,
 288:         dir,
 289:         failing;
 290: {
 291:     static Bufpos   buf;
 292:     Bufpos  *bp;
 293: 
 294:     if (c == CTL(S) || c == CTL(R))
 295:         goto dosrch;
 296: 
 297:     if (failing)
 298:         return 0;
 299:     DOTsave(&buf);
 300:     if (dir == FORWARD) {
 301:         if (cmp_char(linebuf[curchar], c)) {
 302:             buf.p_char = curchar + 1;
 303:             return &buf;
 304:         }
 305:     } else {
 306:         if (look_at(ISbuf))
 307:             return &buf;
 308:     }
 309: dosrch: if ((bp = dosearch(ISbuf, dir, 0)) == 0)
 310:         rbell();    /* ring the first time there's no match */
 311:     return bp;
 312: }
 313: 
 314: IncFSearch()
 315: {
 316:     IncSearch(FORWARD);
 317: }
 318: 
 319: IncRSearch()
 320: {
 321:     IncSearch(BACKWARD);
 322: }
 323: 
 324: static
 325: IncSearch(dir)
 326: {
 327:     Bufpos  save_env;
 328: 
 329:     DOTsave(&save_env);
 330:     ISbuf[0] = 0;
 331:     incp = ISbuf;
 332:     if (isearch(dir, &save_env) == TOSTART)
 333:         SetDot(&save_env);
 334:     else {
 335:         if (LineDist(curline, save_env.p_line) >= MarkThresh)
 336:             DoSetMark(save_env.p_line, save_env.p_char);
 337:     }
 338:     setsearch(ISbuf);
 339:     message(ISbuf);
 340: }
 341: 
 342: /* Nicely recursive. */
 343: 
 344: static
 345: isearch(dir, bp)
 346: Bufpos  *bp;
 347: {
 348:     Bufpos  pushbp;
 349:     int c,
 350:         ndir,
 351:         failing;
 352:     char    *orig_incp;
 353: 
 354:     if (bp != 0) {      /* Move to the new position. */
 355:         pushbp.p_line = bp->p_line;
 356:         pushbp.p_char = bp->p_char;
 357:         SetDot(bp);
 358:         failing = 0;
 359:     } else {
 360:         DOTsave(&pushbp);
 361:         failing = 1;
 362:     }
 363:     orig_incp = incp;
 364:     ndir = dir;     /* Same direction as when we got here, unless
 365: 				   we change it with C-S or C-R. */
 366:     for (;;) {
 367:         SetDot(&pushbp);
 368:         message(NullStr);
 369:         if (failing)
 370:             add_mess("Failing ");
 371:         if (dir == BACKWARD)
 372:             add_mess("reverse-");
 373:         add_mess("I-search: %s", ISbuf);
 374:         DrawMesg(NO);
 375:         add_mess(NullStr);  /* tell me this is disgusting ... */
 376:         c = getch();
 377:         if (c == SExitChar)
 378:             return STOP;
 379:         switch (c) {
 380:         case RUBOUT:
 381:         case BS:
 382:             return DELETE;
 383: 
 384:         case CTL(G):
 385:             /* If we're failing, we backup until we're no longer
 386: 			   failing or we've reached the beginning; else, we
 387: 			   just about the search and go back to the start. */
 388:             if (failing)
 389:                 return BACKUP;
 390:             return TOSTART;
 391: 
 392:         case CTL(\\):
 393:             c = CTL(S);
 394:         case CTL(S):
 395:         case CTL(R):
 396:             /* If this is the first time through and we have a
 397: 			   search string left over from last time, use that
 398: 			   one now. */
 399:             if (incp == ISbuf) {
 400:                 strcpy(ISbuf, getsearch());
 401:                 incp = &ISbuf[strlen(ISbuf)];
 402:             }
 403:             ndir = (c == CTL(S)) ? FORWARD : BACKWARD;
 404:             /* If we're failing and we're not changing our
 405: 			   direction, don't recur since there's no way
 406: 			   the search can work. */
 407:             if (failing && ndir == dir) {
 408:                 rbell();
 409:                 continue;
 410:             }
 411:             break;
 412: 
 413:         case '\\':
 414:             if (incp > &ISbuf[(sizeof ISbuf) - 1]) {
 415:                 rbell();
 416:                 continue;
 417:             }
 418:             *incp++ = '\\';
 419:             add_mess("\\");
 420:             /* Fall into ... */
 421: 
 422:         case CTL(Q):
 423:         case CTL(^):
 424:             add_mess("");
 425:             c = getch() | 0400;
 426:             /* Fall into ... */
 427: 
 428:         default:
 429:             if (c & 0400)
 430:                 c &= 0177;
 431:             else {
 432:                 if (c > RUBOUT || (c < ' ' && c != '\t')) {
 433:                     Ungetc(c);
 434:                     return STOP;
 435:                 }
 436:             }
 437:             if (incp > &ISbuf[(sizeof ISbuf) - 1]) {
 438:                 rbell();
 439:                 continue;
 440:             }
 441:             *incp++ = c;
 442:             *incp = 0;
 443:             break;
 444:         }
 445:         add_mess("%s", orig_incp);
 446:         add_mess(" ...");   /* so we know what's going on */
 447:         DrawMesg(NO);       /* do it now */
 448:         switch (isearch(ndir, doisearch(ndir, c, failing))) {
 449:         case TOSTART:
 450:             return TOSTART;
 451: 
 452:         case STOP:
 453:             return STOP;
 454: 
 455:         case BACKUP:
 456:             /* If we're not failing, we just continue to to the
 457: 			   for loop; otherwise we keep returning to the
 458: 			   previous levels until we find one that isn't
 459: 			   failing OR we reach the beginning. */
 460:             if (failing)
 461:                 return BACKUP;
 462:             /* Fall into ... */
 463: 
 464:         case DELETE:
 465:             incp = orig_incp;
 466:             *incp = 0;
 467:             continue;
 468:         }
 469:     }
 470: }

Defined functions

FDotTag defined in line 247; used 2 times
FindTag defined in line 236; used 4 times
IncFSearch defined in line 314; used 2 times
IncRSearch defined in line 319; used 2 times
IncSearch defined in line 324; used 2 times
QRepSearch defined in line 161; used 2 times
RegReplace defined in line 156; used 2 times
RepSearch defined in line 166; used 2 times
doisearch defined in line 285; used 1 times
find_tag defined in line 209; used 3 times
isearch defined in line 344; used 2 times
lookup defined in line 173; used 1 times
replace defined in line 122; used 3 times
substitute defined in line 14; used 1 times

Defined variables

ISbuf defined in line 279; used 15 times
SExitChar defined in line 281; used 3 times
TagFile defined in line 207; used 7 times
incp defined in line 280; used 11 times

Defined macros

BACKUP defined in line 276; used 2 times
DELETE defined in line 275; used 1 times
STOP defined in line 274; used 3 times
TOSTART defined in line 277; used 3 times
cmp_char defined in line 283; used 1 times
Last modified: 1986-03-28
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1869
Valid CSS Valid XHTML 1.0 Strict