another update from CVS HEAD, for QA
[alioth/jupp.git] / uisrch.c
1 /*
2  *      Incremental search
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/uisrch.c,v 1.15 2017/12/08 02:28:08 tg Exp $");
12
13 #include <stdlib.h>
14
15 #include "b.h"
16 #include "bw.h"
17 #include "main.h"
18 #include "queue.h"
19 #include "qw.h"
20 #include "tty.h"
21 #include "uisrch.h"
22 #include "usearch.h"
23 #include "utils.h"
24 #include "charmap.h"
25 #include "vs.h"
26
27 extern int smode;
28 extern int dobeep;
29 extern int icase;
30 struct isrch *lastisrch = NULL; /* Previous search */
31
32 unsigned char *lastpat = NULL;  /* Previous pattern */
33
34 extern SRCH *globalsrch;        /* Existing SRCH structure */
35
36 IREC fri = { {&fri, &fri}, 0, 0, 0, 0 };        /* Free-list of irecs */
37
38 static IREC *alirec(void)
39 {                               /* Allocate an IREC */
40         return alitem(&fri, sizeof(IREC));
41 }
42
43 static void frirec(IREC *i)
44 {                               /* Free an IREC */
45         enquef(IREC, link, &fri, i);
46 }
47
48 static void rmisrch(struct isrch *isrch)
49 {                               /* Eliminate a struct isrch */
50         if (isrch) {
51                 vsrm(isrch->pattern);
52                 vsrm(isrch->prompt);
53                 frchn(&fri, &isrch->irecs);
54                 free(isrch);
55         }
56 }
57
58 static int iabrt(BW *bw, struct isrch *isrch)
59 {                               /* User hit ^C */
60         rmisrch(isrch);
61         return -1;
62 }
63
64 static void iappend(BW *bw, struct isrch *isrch, unsigned char *s, int len)
65 {                               /* Append text and search */
66         /* Append char and search */
67         IREC *i = alirec();
68         SRCH *srch;
69
70         i->what = len;
71         i->disp = bw->cursor->byte;
72         isrch->pattern = vsncpy(sv(isrch->pattern), s, len);
73         if (!qempty(IREC, link, &isrch->irecs)) {
74                 pgoto(bw->cursor, isrch->irecs.link.prev->start);
75         }
76         i->start = bw->cursor->byte;
77
78         if (!globalsrch)
79                 srch = mksrch(NULL,NULL,icase,isrch->dir,-1,0,0);
80         else {
81                 srch = globalsrch;
82                 globalsrch = 0;
83         }
84
85         srch->addr = bw->cursor->byte;
86
87         if (!srch->wrap_p || srch->wrap_p->b!=bw->b) {
88                 prm(srch->wrap_p);
89                 srch->wrap_p = pdup(bw->cursor);
90                 srch->wrap_p->owner = &srch->wrap_p;
91                 srch->wrap_flag = 0;
92         }
93
94         i->wrap_flag = srch->wrap_flag;
95
96         vsrm(srch->pattern);
97         srch->pattern = vsncpy(NULL, 0, isrch->pattern, sLen(isrch->pattern));
98         srch->backwards = isrch->dir;
99
100         if (dopfnext(bw, srch, NULL)) {
101                 if(dobeep)
102                         ttputc(7);
103         }
104         enqueb(IREC, link, &isrch->irecs, i);
105 }
106
107 /* Main user interface */
108 /* When called with c==-1, it just creates the prompt */
109 static int itype(BW *bw, int c, struct isrch *isrch, int *notify)
110 {
111         IREC *i;
112         int omid;
113         int tc;
114
115         if (isrch->quote) {
116                 goto in;
117         }
118         if (c == 8 || c == 127) {       /* Backup */
119                 if ((i = isrch->irecs.link.prev) != &isrch->irecs) {
120                         pgoto(bw->cursor, i->disp);
121                         if (globalsrch)
122                                 globalsrch->wrap_flag = i->wrap_flag;
123                         omid = mid;
124                         mid = 1;
125                         dofollows();
126                         mid = omid;
127                         isrch->pattern = vstrunc(isrch->pattern, sLEN(isrch->pattern) - i->what);
128                         frirec(deque_f(IREC, link, i));
129                 } else {
130                         if(dobeep)
131                                 ttputc(7);
132                 }
133         } else if (c == 'Q' - '@' || c == '`') {
134                 isrch->quote = 1;
135         } else if (c == 'S' - '@' || c == '\\' - '@' || c == 'L' - '@' || c == 'R' - '@') {
136                 /* Repeat */
137                 if (c == 'R' - '@') {
138                         isrch->dir = 1;
139                 } else {
140                         isrch->dir = 0;
141                 }
142                 if (qempty(IREC, link, &isrch->irecs)) {
143                         if (lastpat && lastpat[0]) {
144                                 iappend(bw, isrch, sv(lastpat));
145                         }
146                 } else {
147                         SRCH *srch;
148                         i = alirec();
149                         i->disp = i->start = bw->cursor->byte;
150                         i->what = 0;
151
152                         if (!globalsrch)
153                                 srch = mksrch(NULL,NULL,icase,isrch->dir,-1,0,0);
154                         else {
155                                 srch = globalsrch;
156                                 globalsrch = 0;
157                         }
158
159                         srch->addr = bw->cursor->byte;
160
161                         if (!srch->wrap_p || srch->wrap_p->b!=bw->b) {
162                                 prm(srch->wrap_p);
163                                 srch->wrap_p = pdup(bw->cursor);
164                                 srch->wrap_p->owner = &srch->wrap_p;
165                                 srch->wrap_flag = 0;
166                         }
167
168                         i->wrap_flag = srch->wrap_flag;
169
170                         vsrm(srch->pattern);
171                         srch->pattern = vsncpy(NULL, 0, isrch->pattern, sLen(isrch->pattern));
172                         srch->backwards = isrch->dir;
173
174                         if (dopfnext(bw, srch, NULL)) {
175                                 if(dobeep)
176                                         ttputc(7);
177                                 frirec(i);
178                         } else {
179                                 enqueb(IREC, link, &isrch->irecs, i);
180                         }
181                 }
182         } else if (c >= 0 && c < 32) {
183                 /* Done when a control character is received */
184                 nungetc(c);
185                 if (notify) {
186                         *notify = 1;
187                 }
188                 smode = 2;
189                 if (lastisrch) {
190                         lastpat = vstrunc(lastpat, 0);
191                         lastpat = vsncpy(lastpat, 0, lastisrch->pattern, sLen(lastisrch->pattern));
192                         rmisrch(lastisrch);
193                 }
194                 lastisrch = isrch;
195                 return 0;
196         } else if (c != -1) {
197                 unsigned char buf[16];
198                 int buf_len;
199                 /* Search */
200  in:
201                 /* Convert to/from utf-8 */
202                 if (locale_map->type && !bw->b->o.charmap->type) {
203                         utf8_encode(buf,c);
204                         c = from_utf8(bw->b->o.charmap,buf);
205                 } else if(!locale_map->type && bw->b->o.charmap->type) {
206                         to_utf8(locale_map,buf,c);
207                         c = utf8_decode_string(buf);
208                 }
209
210                 if (bw->b->o.charmap->type) {
211                         buf_len = utf8_encode(buf,c);
212                 } else {
213                         buf[0] = c;
214                         buf_len = 1;
215                 }
216
217                 isrch->quote = 0;
218                 iappend(bw, isrch, buf, buf_len);
219         }
220         omid = mid;
221         mid = 1;
222         bw->cursor->xcol = piscol(bw->cursor);
223         dofollows();
224         mid = omid;
225
226         isrch->prompt = vstrunc(isrch->prompt, isrch->ofst);
227
228         if (locale_map->type && !bw->b->o.charmap->type) {
229                 /* Translate bytes to utf-8 */
230                 unsigned char buf[16];
231                 int x;
232
233                 for (x = 0; x != sLEN(isrch->pattern); ++x) {
234                         tc = to_uni(bw->b->o.charmap, isrch->pattern[x]);
235                         utf8_encode(buf, tc);
236                         isrch->prompt = vsncpy(sv(isrch->prompt), sz(buf));
237                 }
238         } else if (!locale_map->type && bw->b->o.charmap->type) {
239                 /* Translate utf-8 to bytes */
240                 unsigned char *p = isrch->pattern;
241                 int len = sLEN(isrch->pattern);
242
243                 while (len) {
244                         if ((tc = utf8_decode_fwrd(&p, &len)) >= 0) {
245                                 tc = from_uni(locale_map, tc);
246                                 isrch->prompt = vsadd(isrch->prompt, tc);
247                         }
248                 }
249         } else {
250                 /* FIXME: translate when charmaps do not match */
251                 isrch->prompt = vsncpy(sv(isrch->prompt),sv(isrch->pattern));
252         }
253
254         if (mkqwnsr(bw->parent, sv(isrch->prompt), itype, iabrt, isrch, notify)) {
255                 return 0;
256         } else {
257                 rmisrch(isrch);
258                 return -1;
259         }
260 }
261
262 /* Create a struct isrch */
263 static int
264 doisrch(BW *bw, int dir)
265 {
266         struct isrch *isrch = malloc(sizeof(struct isrch));
267
268         izque(IREC, link, &isrch->irecs);
269         isrch->pattern = vsncpy(NULL, 0, NULL, 0);
270         isrch->dir = dir;
271         isrch->quote = 0;
272         isrch->prompt = vsncpy(NULL, 0, sc("I-find: "));
273         isrch->ofst = sLen(isrch->prompt);
274         return itype(bw, -1, isrch, NULL);
275 }
276
277 int uisrch(BW *bw)
278 {
279         if (smode && lastisrch) {
280                 struct isrch *isrch = lastisrch;
281
282                 lastisrch = 0;
283                 return itype(bw, 'S' - '@', isrch, NULL);
284         } else {
285                 if (globalsrch) {
286                         rmsrch(globalsrch);
287                         globalsrch = 0;
288                 }
289                 if (lastisrch) {
290                         lastpat = vstrunc(lastpat, 0);
291                         lastpat = vsncpy(lastpat, 0, lastisrch->pattern, sLen(lastisrch->pattern));
292                         rmisrch(lastisrch);
293                         lastisrch = 0;
294                 }
295                 return doisrch(bw, 0);
296         }
297 }
298
299 int ursrch(BW *bw)
300 {
301         if (smode && lastisrch) {
302                 struct isrch *isrch = lastisrch;
303
304                 lastisrch = 0;
305                 return itype(bw, 'R' - '@', isrch, NULL);
306         } else {
307                 if (globalsrch) {
308                         rmsrch(globalsrch);
309                         globalsrch = 0;
310                 }
311                 if (lastisrch) {
312                         lastpat = vstrunc(lastpat, 0);
313                         lastpat = vsncpy(lastpat, 0, lastisrch->pattern, sLen(lastisrch->pattern));
314                         rmisrch(lastisrch);
315                         lastisrch = 0;
316                 }
317                 return doisrch(bw, 1);
318         }
319 }