|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.