1 /*
2 * Search & Replace system
3 * Copyright
4 * (C) 1992 Joseph H. Allen
5 *
6 * This file is part of JOE (Joe's Own Editor)
7 */
8 #include "config.h"
9 #include "types.h"
10
11 __RCSID("$MirOS: contrib/code/jupp/usearch.c,v 1.22 2018/10/20 16:34:40 tg Exp $");
12
13 #include <stdlib.h>
14
15 #include "b.h"
16 #include "bw.h"
17 #include "main.h"
18 #include "pw.h"
19 #include "queue.h"
20 #include "qw.h"
21 #include "regex.h"
22 #include "ublock.h"
23 #include "uedit.h"
24 #include "undo.h"
25 #include "usearch.h"
26 #include "utils.h"
27 #include "vs.h"
28 #include "charmap.h"
29 #include "w.h"
30 #include "va.h"
31 #include "tty.h"
32 #include "menu.h"
33 #include "hash.h"
34
35 int wrap = 0; /* Allow wrap */
36 int smode = 0; /* Decremented to zero by execmd */
37 int csmode = 0; /* Set for continued search mode */
38 int icase = 0; /* Set to force case insensitive search */
39
40 B *findhist = NULL; /* Search string history */
41 B *replhist = NULL; /* Replacement string history */
42
43 SRCH *globalsrch = NULL; /* Most recent completed search data */
44
45 SRCHREC fsr = { {&fsr, &fsr}, 0, 0, 0 };
46
47 /* Completion stuff: should go somewhere else */
48
49 unsigned char **word_list;
50
51 #define MAX_WORD_SIZE 64
52 static unsigned char **
get_word_list(B * b,int ignore)53 get_word_list(B *b, int ignore)
54 {
55 unsigned char buf[MAX_WORD_SIZE];
56 unsigned char *s;
57 unsigned char **list = 0;
58 HASH *h;
59 HENTRY *t;
60 P *p;
61 int c;
62 int idx;
63 int start = 0;
64
65 h = htmk(1024);
66
67 p = pdup(b->bof);
68 idx = 0;
69 while ((c=pgetc(p))!=NO_MORE_DATA)
70 if (idx) {
71 if (joe_isalnux(b->o.charmap, c)) {
72 if (idx!=MAX_WORD_SIZE)
73 buf[idx++] = c;
74 } else {
75 if (idx!=MAX_WORD_SIZE && start!=ignore) {
76 buf[idx] = 0;
77 if (!htfind(h,buf)) {
78 s = vsncpy(NULL,0,buf,idx);
79 htadd(h, s, s);
80 }
81 }
82 idx = 0;
83 }
84 } else {
85 start=p->byte-1;
86 if (joe_isalphx(b->o.charmap, c))
87 buf[idx++] = c;
88 }
89 prm(p);
90
91 for (idx = 0;idx != h->len;++idx)
92 for (t = h->tab[idx];t;t=t->next)
93 list = vaadd(list, /* checked */ US t->name);
94 if (list)
95 vasort(list, sLEN(list));
96
97 htrm(h);
98
99 return list;
100 }
101
102 static void
fcmplt_ins(BW * bw,unsigned char * line)103 fcmplt_ins(BW *bw, unsigned char *line)
104 {
105 P *p;
106 int c;
107
108 if (!piseol(bw->cursor)) {
109 c = brch(bw->cursor);
110 if (joe_isalnux(bw->b->o.charmap,c))
111 return;
112 }
113
114 /* Move p to beginning of word */
115
116 p = pdup(bw->cursor);
117 do
118 c = prgetc(p);
119 while (joe_isalnux(bw->b->o.charmap,c));
120 if (c!=NO_MORE_DATA)
121 pgetc(p);
122
123 if (bw->cursor->byte!=p->byte && bw->cursor->byte-p->byte<64) {
124 /* Insert single match */
125 bdel(p,bw->cursor);
126 binsm(bw->cursor,sv(line));
127 pfwrd(bw->cursor,sLEN(line));
128 bw->cursor->xcol = piscol(bw->cursor);
129 prm(p);
130 } else {
131 prm(p);
132 }
133 }
134
135 static int
fcmplt_abrt(BW * bw,int x,unsigned char * line)136 fcmplt_abrt(BW *bw, int x, unsigned char *line)
137 {
138 if (line) {
139 fcmplt_ins(bw, line);
140 vsrm(line);
141 }
142 return -1;
143 }
144
145 static int
fcmplt_rtn(MENU * m,int x,unsigned char * line)146 fcmplt_rtn(MENU *m, int x, unsigned char *line)
147 {
148 fcmplt_ins(m->parent->win->object.bw, m->list[x]);
149 vsrm(line);
150 m->object = NULL;
151 wabort(m->parent);
152 return 0;
153 }
154
ufinish(BW * bw)155 int ufinish(BW *bw)
156 {
157 unsigned char *line;
158 unsigned char *line1;
159 unsigned char **lst;
160 P *p;
161 int c;
162 MENU *m;
163
164 /* Make sure we're not in a word */
165
166 if (!piseol(bw->cursor)) {
167 c = brch(bw->cursor);
168 if (joe_isalnux(bw->b->o.charmap,c))
169 return -1;
170 }
171
172 /* Move p to beginning of word */
173
174 p = pdup(bw->cursor);
175 do
176 c = prgetc(p);
177 while (joe_isalnux(bw->b->o.charmap,c));
178 if (c!=NO_MORE_DATA)
179 pgetc(p);
180
181 if (bw->cursor->byte!=p->byte && bw->cursor->byte-p->byte<64) {
182 line = brvs(p, bw->cursor->byte-p->byte);
183
184 /* We have a word */
185
186 /* Get word list */
187 if (word_list)
188 varm(word_list);
189
190 word_list = get_word_list(bw->b, p->byte);
191
192 if (!word_list) {
193 vsrm(line);
194 prm(p);
195 return -1;
196 }
197
198 line1 = vsncpy(NULL,0,sv(line));
199 line1 = vsadd(line1,'*');
200 lst = regsub(word_list, aLEN(word_list), line1);
201 vsrm(line1);
202
203 if (!lst) {
204 ttputc(7);
205 vsrm(line);
206 return -1;
207 }
208
209 m = mkmenu(bw->parent, lst, fcmplt_rtn, fcmplt_abrt, NULL, 0, line, NULL);
210 if (!m) {
211 varm(lst);
212 vsrm(line);
213 return -1;
214 }
215
216 /* Possible match list is now in lst */
217
218 if (aLEN(lst) == 1)
219 return fcmplt_rtn(m, 0, line);
220 else if (smode)
221 return 0;
222 else {
223 unsigned char *com = mcomplete(m);
224 vsrm(m->object);
225 m->object = com;
226 wabort(m->parent);
227 smode = 2;
228 ttputc(7);
229 return 0;
230 }
231 } else {
232 prm(p);
233 return -1;
234 }
235 }
236
srch_cmplt(BW * bw)237 static int srch_cmplt(BW *bw)
238 {
239 jobject jO;
240
241 jO.bw = bw;
242 utypebw(jO, 9);
243 return 0;
244 }
245
246 /* Search forward.
247 bw, pattern and ignore must be set
248
249 The first possible string we can find is the one beginning under p
250
251 Returns p if we found a string:
252 The found string is placed in entire/pieces
253 p is placed right after the found string
254
255 Return 0 if we did not find the string:
256 p is left in its orignal spot
257 */
258
searchf(BW * bw,SRCH * srch,P * p)259 static P *searchf(BW *bw,SRCH *srch, P *p)
260 {
261 unsigned char *pattern = srch->pattern;
262 P *start;
263 P *end;
264 int x;
265
266 start = pdup(p);
267 end = pdup(p);
268
269 for (x = 0; x != sLEN(pattern) && pattern[x] != '\\' && (pattern[x]<128 || !p->b->o.charmap->type); ++x)
270 if (srch->ignore)
271 pattern[x] = joe_tolower(p->b->o.charmap,pattern[x]);
272 wrapped:
273 while (srch->ignore ? pifind(start, pattern, x) : pfind(start, pattern, x)) {
274 pset(end, start);
275 pfwrd(end, (long) x);
276 if (srch->wrap_flag && start->byte>=srch->wrap_p->byte)
277 break;
278 if (pmatch(srch->pieces, pattern + x, sLEN(pattern) - x, end, 0, srch->ignore)) {
279 srch->entire = vstrunc(srch->entire, (int) (end->byte - start->byte));
280 brmem(start, srch->entire, (int) (end->byte - start->byte));
281 pset(p, end);
282 prm(start);
283 prm(end);
284 return p;
285 }
286 if (pgetc(start) == NO_MORE_DATA)
287 break;
288 }
289 if (wrap && !srch->wrap_flag && srch->wrap_p) {
290 msgnw(bw->parent, UC "Wrapped");
291 srch->wrap_flag = 1;
292 p_goto_bof(start);
293 goto wrapped;
294 }
295
296 prm(start);
297 prm(end);
298 return NULL;
299 }
300
301 /* Search backwards.
302 bw, pattern and ignore must be set
303
304 The first possible string we can find is the one beginning one position
305 to the left of p.
306
307 Returns 1 if we found a string:
308 The found string is placed in entire
309 p is placed at the beginning of the string
310
311 Return 0 if we did not find the string:
312 p is left in its orignal spot
313 */
314
searchb(BW * bw,SRCH * srch,P * p)315 static P *searchb(BW *bw,SRCH *srch, P *p)
316 {
317 unsigned char *pattern = srch->pattern;
318 P *start;
319 P *end;
320 int x;
321
322 start = pdup(p);
323 end = pdup(p);
324
325 for (x = 0; x != sLEN(pattern) && pattern[x] != '\\' && (pattern[x]<128 || !p->b->o.charmap->type); ++x)
326 if (srch->ignore)
327 pattern[x] = joe_tolower(p->b->o.charmap,pattern[x]);
328
329 wrapped:
330 while (pbkwd(start, 1L)
331 && (srch->ignore ? prifind(start, pattern, x) : prfind(start, pattern, x))) {
332 pset(end, start);
333 pfwrd(end, (long) x);
334 if (srch->wrap_flag && start->byte<srch->wrap_p->byte)
335 break;
336 if (pmatch(srch->pieces, pattern + x, sLEN(pattern) - x, end, 0, srch->ignore)) {
337 srch->entire = vstrunc(srch->entire, (int) (end->byte - start->byte));
338 brmem(start, srch->entire, (int) (end->byte - start->byte));
339 pset(p, start);
340 prm(start);
341 prm(end);
342 return p;
343 }
344 }
345
346 if (wrap && !srch->wrap_flag && srch->wrap_p) {
347 msgnw(bw->parent, UC "Wrapped");
348 srch->wrap_flag = 1;
349 p_goto_eof(start);
350 goto wrapped;
351 }
352
353 prm(start);
354 prm(end);
355 return NULL;
356 }
357
358 /* Make a search stucture */
359
setmark(SRCH * srch)360 static SRCH *setmark(SRCH *srch)
361 {
362 if (markv(0))
363 srch->valid = 1;
364
365 srch->markb = markb;
366 if (srch->markb)
367 srch->markb->owner = &srch->markb;
368 markb = NULL;
369
370 srch->markk = markk;
371 if (srch->markk)
372 srch->markk->owner = &srch->markk;
373 markk = NULL;
374
375 return srch;
376 }
377
mksrch(unsigned char * pattern,unsigned char * replacement,int ignore,int backwards,int repeat,int replace,int rest)378 SRCH *mksrch(unsigned char *pattern, unsigned char *replacement, int ignore, int backwards, int repeat, int replace, int rest)
379 {
380 SRCH *srch = malloc(sizeof(SRCH));
381 int x;
382
383 srch->pattern = pattern;
384 srch->replacement = replacement;
385 srch->ignore = ignore;
386 srch->backwards = backwards;
387 srch->repeat = repeat;
388 srch->replace = replace;
389 srch->rest = rest;
390 srch->entire = NULL;
391 srch->flg = 0;
392 srch->addr = -1;
393 srch->markb = NULL;
394 srch->markk = NULL;
395 srch->wrap_p = NULL;
396 srch->wrap_flag = 0;
397 srch->valid = 0;
398 srch->block_restrict = 0;
399 izque(SRCHREC, link, &srch->recs);
400 for (x = 0; x != 26; ++x)
401 srch->pieces[x] = NULL;
402 return srch;
403 }
404
405 /* Eliminate a search structure */
406
rmsrch(SRCH * srch)407 void rmsrch(SRCH *srch)
408 {
409 int x;
410
411 prm(markb);
412 prm(markk);
413 prm(srch->wrap_p);
414 if (srch->markb) {
415 markb = srch->markb;
416 markb->owner = &markb;
417 markb->xcol = piscol(markb);
418 }
419 if (srch->markk) {
420 markk = srch->markk;
421 markk->owner = &markk;
422 markk->xcol = piscol(markk);
423 }
424 for (x = 0; x != 26; ++x)
425 vsrm(srch->pieces[x]);
426 frchn(&fsr, &srch->recs);
427 vsrm(srch->pattern);
428 vsrm(srch->replacement);
429 vsrm(srch->entire);
430 free(srch);
431 updall();
432 }
433
434 /* Insert a replacement string
435 * p is advanced past the inserted text
436 */
437
insert(SRCH * srch,P * p,unsigned char * s,int len)438 static P *insert(SRCH *srch, P *p, unsigned char *s, int len)
439 {
440 int x;
441
442 while (len) {
443 for (x = 0; x != len && s[x] != '\\'; ++x) ;
444 if (x) {
445 binsm(p, s, x);
446 pfwrd(p, (long) x);
447 len -= x;
448 s += x;
449 } else if (len >= 2) {
450 if (((s[1] | 0x20) >= 'a' && (s[1] | 0x20) <= 'z') &&
451 srch->pieces[(s[1] & 0x1f) - 1]) {
452 binsm(p, sv(srch->pieces[(s[1] & 0x1f) - 1]));
453 pfwrd(p, (long) sLEN(srch->pieces[(s[1] & 0x1f) - 1]));
454 s += 2;
455 len -= 2;
456 } else if (s[1] >= '0' && s[1] <= '9' && srch->pieces[s[1] - '0']) {
457 binsm(p, sv(srch->pieces[s[1] - '0']));
458 pfwrd(p, (long) sLEN(srch->pieces[s[1] - '0']));
459 s += 2;
460 len -= 2;
461 } else if (s[1] == '&' && srch->entire) {
462 binsm(p, sv(srch->entire));
463 pfwrd(p, (long) sLEN(srch->entire));
464 s += 2;
465 len -= 2;
466 } else {
467 unsigned char *a=(unsigned char *)s+x;
468 int l=len-x;
469 binsc(p,escape(p->b->o.charmap->type,&a,&l));
470 pgetc(p);
471 len -= a - (unsigned char *)s;
472 s = a;
473 }
474 } else
475 len = 0;
476 }
477 return p;
478 }
479
480 /* Search system user interface */
481
482 /* Query for search string, search options, possible replacement string,
483 * and execute first search */
484
485 /* Context sensitive help identifier */
486 const unsigned char srchstr[] = "Search";
487
pfabort(BW * bw,SRCH * srch)488 static int pfabort(BW *bw, SRCH *srch)
489 {
490 if (srch)
491 rmsrch(srch);
492 return -1;
493 }
494
495 /* always returns -1 */
pfsave(BW * bw,SRCH * srch)496 static int pfsave(BW *bw, SRCH *srch)
497 {
498 if (srch) {
499 if (globalsrch)
500 rmsrch(globalsrch);
501 globalsrch = srch;
502 srch->rest = 0;
503 srch->repeat = -1;
504 srch->flg = 0;
505
506 prm(markb);
507 prm(markk);
508 if (srch->markb) {
509 markb = srch->markb;
510 markb->owner = &markb;
511 markb->xcol = piscol(markb);
512 }
513 if (srch->markk) {
514 markk = srch->markk;
515 markk->owner = &markk;
516 markk->xcol = piscol(markk);
517 }
518 srch->markb = NULL;
519 srch->markk = NULL;
520
521 updall();
522 }
523 return -1;
524 }
525
set_replace(BW * bw,unsigned char * s,SRCH * srch,int * notify)526 static int set_replace(BW *bw, unsigned char *s, SRCH *srch, int *notify)
527 {
528 srch->replacement = s;
529 return dopfnext(bw, srch, notify);
530 }
531
set_options(BW * bw,unsigned char * s,SRCH * srch,int * notify)532 static int set_options(BW *bw, unsigned char *s, SRCH *srch, int *notify)
533 {
534 int x;
535
536 srch->ignore = icase;
537
538 for (x = 0; s[x]; ++x) {
539 switch (s[x] | 0x20) {
540 case 'r':
541 srch->replace = 1;
542 break;
543 case 'b':
544 srch->backwards = 1;
545 break;
546 case 'i':
547 srch->ignore = 1;
548 break;
549 case 's':
550 srch->ignore = 0;
551 break;
552 case 'k':
553 srch->block_restrict = 1;
554 break;
555 case '0':
556 case '1':
557 case '2':
558 case '3':
559 case '4':
560 case '5':
561 case '6':
562 case '7':
563 case '8':
564 case '9':
565 if (srch->repeat == -1)
566 srch->repeat = 0;
567 srch->repeat = srch->repeat * 10 + s[x] - '0';
568 break;
569 }
570 }
571 vsrm(s);
572 if (srch->replace) {
573 if (wmkpw(bw->parent, UC "Replace with (^C to abort): ", &replhist, set_replace, srchstr, pfabort, srch_cmplt, srch, notify, bw->b->o.charmap))
574 return 0;
575 else
576 return -1;
577 } else
578 return dopfnext(bw, srch, notify);
579 }
580
set_pattern(BW * bw,unsigned char * s,SRCH * srch,int * notify)581 static int set_pattern(BW *bw, unsigned char *s, SRCH *srch, int *notify)
582 {
583 BW *pbw;
584 const unsigned char *p;
585
586 if (icase)
587 p = UC "case (S)ensitive (R)eplace (B)ackwards Bloc(K) NNN (^C to abort): ";
588 else
589 p = UC "(I)gnore (R)eplace (B)ackwards Bloc(K) NNN (^C to abort): ";
590
591 vsrm(srch->pattern);
592 srch->pattern = s;
593 if ((pbw = wmkpw(bw->parent, p, NULL, set_options, srchstr, pfabort, utypebw, srch, notify, bw->b->o.charmap)) != NULL) {
594 unsigned char buf[12];
595
596 if (srch->ignore)
597 binsc(pbw->cursor, 'i');
598 if (srch->replace)
599 binsc(pbw->cursor, 'r');
600 if (srch->backwards)
601 binsc(pbw->cursor, 'b');
602 if (srch->repeat >= 0) {
603 joe_snprintf_1((char *)buf, sizeof(buf), "%d", srch->repeat);
604 binss(pbw->cursor, buf);
605 }
606 pset(pbw->cursor, pbw->b->eof);
607 pbw->cursor->xcol = piscol(pbw->cursor);
608 srch->ignore = 0;
609 srch->replace = 0;
610 srch->backwards = 0;
611 srch->repeat = -1;
612 return 0;
613 } else {
614 rmsrch(srch);
615 return -1;
616 }
617 }
618
dofirst(BW * bw,int back,int repl)619 static int dofirst(BW *bw, int back, int repl)
620 {
621 SRCH *srch;
622
623 if (smode && globalsrch) {
624 globalsrch->backwards = back;
625 globalsrch->replace = repl;
626 return pfnext(bw);
627 }
628 if (bw->parent->huh == srchstr) {
629 long byte;
630 jobject jO;
631
632 p_goto_eol(bw->cursor);
633 byte = bw->cursor->byte;
634 p_goto_bol(bw->cursor);
635 if (byte == bw->cursor->byte)
636 prgetc(bw->cursor);
637 jO.bw = bw;
638 return urtn(jO, -1);
639 }
640 srch = setmark(mksrch(NULL, NULL, 0, back, -1, repl, 0));
641 srch->addr = bw->cursor->byte;
642 srch->wrap_p = pdup(bw->cursor);
643 srch->wrap_p->owner = &srch->wrap_p;
644 if (wmkpw(bw->parent, UC "Find (^C to abort): ", &findhist, set_pattern, srchstr, pfabort, srch_cmplt, srch, NULL, bw->b->o.charmap))
645 return 0;
646 else {
647 rmsrch(srch);
648 return -1;
649 }
650 }
651
pffirst(BW * bw)652 int pffirst(BW *bw)
653 {
654 return dofirst(bw, 0, 0);
655 }
656
prfirst(BW * bw)657 int prfirst(BW *bw)
658 {
659 return dofirst(bw, 1, 0);
660 }
661
pqrepl(BW * bw)662 int pqrepl(BW *bw)
663 {
664 return dofirst(bw, 0, 1);
665 }
666
667 /* Execute next search */
668
doreplace(BW * bw,SRCH * srch)669 static int doreplace(BW *bw, SRCH *srch)
670 {
671 P *q;
672
673 if (bw->b->rdonly) {
674 msgnw(bw->parent, UC "Read only");
675 return -1;
676 }
677 if (markk)
678 markk->end = 1;
679 if (srch->markk)
680 srch->markk->end = 1;
681 q = pdup(bw->cursor);
682 if (srch->backwards) {
683 q = pfwrd(q, (long) sLEN(srch->entire));
684 bdel(bw->cursor, q);
685 prm(q);
686 } else {
687 q = pbkwd(q, (long) sLEN(srch->entire));
688 bdel(q, bw->cursor);
689 prm(q);
690 }
691 insert(srch, bw->cursor, sv(srch->replacement));
692 srch->addr = bw->cursor->byte;
693 if (markk)
694 markk->end = 0;
695 if (srch->markk)
696 srch->markk->end = 0;
697 return 0;
698 }
699
visit(SRCH * srch,BW * bw,int yn)700 static void visit(SRCH *srch, BW *bw, int yn)
701 {
702 SRCHREC *r = (SRCHREC *) alitem(&fsr, sizeof(SRCHREC));
703
704 r->addr = bw->cursor->byte;
705 r->yn = yn;
706 r->wrap_flag = srch->wrap_flag;
707 enqueb(SRCHREC, link, &srch->recs, r);
708 }
709
goback(SRCH * srch,BW * bw)710 static void goback(SRCH *srch, BW *bw)
711 {
712 SRCHREC *r = srch->recs.link.prev;
713
714 if (r != &srch->recs) {
715 if (r->yn)
716 uundo(bw);
717 if (bw->cursor->byte != r->addr)
718 pgoto(bw->cursor, r->addr);
719 srch->wrap_flag = r->wrap_flag;
720 demote(SRCHREC, link, &fsr, r);
721 }
722 }
723
dopfrepl(BW * bw,int c,SRCH * srch,int * notify)724 static int dopfrepl(BW *bw, int c, SRCH *srch, int *notify)
725 {
726 srch->addr = bw->cursor->byte;
727 if ((c | 0x20) == 'n')
728 return dopfnext(bw, srch, notify);
729 else if ((c | 0x20) == 'y' || (c | 0x20) == 'l' || c == ' ') {
730 srch->recs.link.prev->yn = 1;
731 /* why do I return -1 on 'L' here? */
732 return ((doreplace(bw, srch) || (c | 0x20) == 'l') ?
733 pfsave(bw, srch) : dopfnext(bw, srch, notify));
734 } else if ((c | 0x20) == 'r') {
735 if (doreplace(bw, srch))
736 return -1;
737 srch->rest = 1;
738 return dopfnext(bw, srch, notify);
739 } else if (c == 8 || c == 127 || (c | 0x20) == 'b') {
740 goback(srch, bw);
741 goback(srch, bw);
742 return dopfnext(bw, srch, notify);
743 } else if (c != -1) {
744 if (notify)
745 *notify = 1;
746 pfsave(bw, srch);
747 nungetc(c);
748 return 0;
749 }
750 if (mkqwnsr(bw->parent, sc("Replace (Y)es (N)o (L)ast (R)est (B)ackup (^C to abort)?"), dopfrepl, pfsave, srch, notify))
751 return 0;
752 else
753 return pfsave(bw, srch);
754 }
755
756 /* Test if found text is within region
757 * return 0 if it is,
758 * -1 if we should keep searching
759 * 1 if we're done
760 */
761
restrict_to_block(BW * bw,SRCH * srch)762 static int restrict_to_block(BW *bw, SRCH *srch)
763 {
764 if (!srch->block_restrict)
765 return 0;
766 bw->cursor->xcol = piscol(bw->cursor);
767 if (srch->backwards)
768 if (!square) {
769 if (bw->cursor->byte < srch->markb->byte)
770 return 1;
771 else if (bw->cursor->byte + sLEN(srch->entire) > srch->markk->byte)
772 return -1;
773 } else {
774 if (bw->cursor->line < srch->markb->line)
775 return 1;
776 else if (bw->cursor->line > srch->markk->line)
777 return -1;
778 else if (piscol(bw->cursor) + sLEN(srch->entire) > srch->markk->xcol || piscol(bw->cursor) < srch->markb->xcol)
779 return -1;
780 } else if (!square) {
781 if (bw->cursor->byte > srch->markk->byte)
782 return 1;
783 else if (bw->cursor->byte - sLEN(srch->entire) < srch->markb->byte)
784 return -1;
785 } else {
786 if (bw->cursor->line > srch->markk->line)
787 return 1;
788 if (bw->cursor->line < srch->markb->line)
789 return -1;
790 if (piscol(bw->cursor) > srch->markk->xcol || piscol(bw->cursor) - sLEN(srch->entire) < srch->markb->xcol)
791 return -1;
792 }
793 return 0;
794 }
795
796 /* Possible results:
797 * 0) Search or search & replace is finished.
798 * 1) Search string was not found.
799 * 2) Search string was found.
800 */
801
fnext(BW * bw,SRCH * srch)802 static int fnext(BW *bw, SRCH *srch)
803 {
804 P *sta;
805
806 next:
807 if (srch->repeat != -1) {
808 if (!srch->repeat)
809 return 0;
810 else
811 --srch->repeat;
812 }
813 again:
814 if (srch->backwards)
815 sta = searchb(bw, srch, bw->cursor);
816 else
817 sta = searchf(bw, srch, bw->cursor);
818 if (!sta) {
819 srch->repeat = -1;
820 return 1;
821 } else if (srch->rest || (srch->repeat != -1 && srch->replace)) {
822 if (srch->valid)
823 switch (restrict_to_block(bw, srch)) {
824 case -1:
825 goto again;
826 case 1:
827 if (srch->addr >= 0)
828 pgoto(bw->cursor, srch->addr);
829 return !srch->rest;
830 }
831 if (doreplace(bw, srch))
832 return 0;
833 goto next;
834 } else if (srch->repeat != -1) {
835 if (srch->valid)
836 switch (restrict_to_block(bw, srch)) {
837 case -1:
838 goto again;
839 case 1:
840 if (srch->addr >= 0)
841 pgoto(bw->cursor, srch->addr);
842 return 1;
843 }
844 srch->addr = bw->cursor->byte;
845 goto next;
846 } else
847 return 2;
848 }
849
dopfnext(BW * bw,SRCH * srch,int * notify)850 int dopfnext(BW *bw, SRCH *srch, int *notify)
851 {
852 int orgmid = mid; /* Original mid status */
853 int ret = 0;
854
855 mid = 1; /* Screen recenters mode during search */
856 if (csmode)
857 smode = 2; /* We have started a search mode */
858 if (srch->replace)
859 visit(srch, bw, 0);
860 again:
861 switch (fnext(bw, srch)) {
862 case 0:
863 break;
864 case 1:
865 bye:
866 if (!srch->flg && !srch->rest) {
867 if (srch->valid && srch->block_restrict)
868 msgnw(bw->parent, UC "Not found (search restricted to marked block)");
869 else
870 msgnw(bw->parent, UC "Not found");
871 ret = -1;
872 }
873 break;
874 case 2:
875 if (srch->valid)
876 switch (restrict_to_block(bw, srch)) {
877 case -1:
878 goto again;
879 case 1:
880 if (srch->addr >= 0)
881 pgoto(bw->cursor, srch->addr);
882 goto bye;
883 }
884 srch->addr = bw->cursor->byte;
885
886 /* Make sure found text is fully on screen */
887 if(srch->backwards) {
888 bw->offset=0;
889 pfwrd(bw->cursor,sLEN(srch->entire));
890 bw->cursor->xcol = piscol(bw->cursor);
891 dofollows();
892 pbkwd(bw->cursor,sLEN(srch->entire));
893 } else {
894 bw->offset=0;
895 pbkwd(bw->cursor,sLEN(srch->entire));
896 bw->cursor->xcol = piscol(bw->cursor);
897 dofollows();
898 pfwrd(bw->cursor,sLEN(srch->entire));
899 }
900
901 if (srch->replace) {
902 if (square)
903 bw->cursor->xcol = piscol(bw->cursor);
904 if (srch->backwards) {
905 pdupown(bw->cursor, &markb);
906 markb->xcol = piscol(markb);
907 pdupown(markb, &markk);
908 pfwrd(markk, (long) sLEN(srch->entire));
909 markk->xcol = piscol(markk);
910 } else {
911 pdupown(bw->cursor, &markk);
912 markk->xcol = piscol(markk);
913 pdupown(bw->cursor, &markb);
914 pbkwd(markb, (long) sLEN(srch->entire));
915 markb->xcol = piscol(markb);
916 }
917 srch->flg = 1;
918 if (dopfrepl(bw, -1, srch, notify))
919 ret = -1;
920 notify = 0;
921 srch = 0;
922 }
923 break;
924 }
925 bw->cursor->xcol = piscol(bw->cursor);
926 dofollows();
927 mid = orgmid;
928 if (notify)
929 *notify = 1;
930 if (srch)
931 pfsave(bw, srch);
932 else
933 updall();
934 return ret;
935 }
936
pfnext(BW * bw)937 int pfnext(BW *bw)
938 {
939 SRCH *srch;
940
941 if (!globalsrch) {
942 /* Query for search string if there isn't any */
943 return pffirst(bw);
944 }
945
946 srch = globalsrch;
947 globalsrch = NULL;
948 srch->addr = bw->cursor->byte;
949 if (!srch->wrap_p || srch->wrap_p->b!=bw->b) {
950 prm(srch->wrap_p);
951 srch->wrap_p = pdup(bw->cursor);
952 srch->wrap_p->owner = &srch->wrap_p;
953 srch->wrap_flag = 0;
954 }
955 srch->valid = 0;
956 return dopfnext(bw, setmark(srch), NULL);
957 }
958