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