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