Start converting to GPL v3+ (ref: ticket #23900)
[screen-lua.git] / src / search.c
blob997fc0bd90ff3e139bdf679f632b034d52e2367f
1 /* Copyright (c) 1993-2002
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, see
18 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
21 ****************************************************************
24 #include <sys/types.h>
26 #include "config.h"
27 #include "screen.h"
28 #include "mark.h"
29 #include "extern.h"
31 #define INPUTLINE (flayer->l_height - 1)
33 extern struct layer *flayer;
34 extern struct win *fore;
36 #ifdef COPY_PASTE
38 int search_ic;
40 /********************************************************************
41 * VI style Search
44 static int matchword __P((char *, int, int, int));
45 static void searchend __P((char *, int, char *));
46 static void backsearchend __P((char *, int, char *));
48 void
49 Search(dir)
50 int dir;
52 struct markdata *markdata;
53 if (dir == 0)
55 markdata = (struct markdata *)flayer->l_data;
56 if (markdata->isdir > 0)
57 searchend(0, 0, NULL);
58 else if (markdata->isdir < 0)
59 backsearchend(0, 0, NULL);
60 else
61 LMsg(0, "No previous pattern");
63 else
64 Input((dir > 0 ? "/" : "?"), sizeof(markdata->isstr)-1, INP_COOKED,
65 (dir > 0 ? searchend : backsearchend), NULL, 0);
68 static void
69 searchend(buf, len, data)
70 char *buf;
71 int len;
72 char *data; /* dummy */
74 int x = 0, sx, ex, y;
75 struct markdata *markdata;
76 struct win *p;
78 markdata = (struct markdata *)flayer->l_data;
79 p = markdata->md_window;
80 markdata->isdir = 1;
81 if (len)
82 strcpy(markdata->isstr, buf);
83 sx = markdata->cx + 1;
84 ex = flayer->l_width - 1;
85 for (y = markdata->cy; y < p->w_histheight + flayer->l_height; y++, sx = 0)
87 if ((x = matchword(markdata->isstr, y, sx, ex)) >= 0)
88 break;
90 if (y >= p->w_histheight + flayer->l_height)
92 LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
93 LMsg(0, "Pattern not found");
95 else
96 revto(x, y);
99 static void
100 backsearchend(buf, len, data)
101 char *buf;
102 int len;
103 char *data; /* dummy */
105 int sx, ex, x = -1, y;
106 struct markdata *markdata;
108 markdata = (struct markdata *)flayer->l_data;
109 markdata->isdir = -1;
110 if (len)
111 strcpy(markdata->isstr, buf);
112 ex = markdata->cx - 1;
113 for (y = markdata->cy; y >= 0; y--, ex = flayer->l_width - 1)
115 sx = 0;
116 while ((sx = matchword(markdata->isstr, y, sx, ex)) >= 0)
117 x = sx++;
118 if (x >= 0)
119 break;
121 if (y < 0)
123 LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
124 LMsg(0, "Pattern not found");
126 else
127 revto(x, y);
130 static int
131 matchword(pattern, y, sx, ex)
132 char *pattern;
133 int y, sx, ex;
135 unsigned char *ip, *ipe, *cp, *pp;
136 struct mline *ml;
138 /* *sigh* to make WIN work */
139 fore = ((struct markdata *)flayer->l_data)->md_window;
141 ml = WIN(y);
142 ip = ml->image + sx;
143 ipe = ml->image + flayer->l_width;
144 for (;sx <= ex; sx++)
146 cp = ip++;
147 pp = (unsigned char *)pattern;
148 for (;;)
150 if (*cp != *pp)
151 if (!search_ic || ((*cp ^ *pp) & 0xdf) || (*cp | 0x20) < 'a' || (*cp | 0x20) > 'z')
152 break;
153 cp++;
154 pp++;
155 if (*pp == 0)
156 return sx;
157 if (cp == ipe)
158 break;
161 return -1;
165 /********************************************************************
166 * Emacs style ISearch
169 static char *isprompts[] = {
170 "I-search backward: ", "failing I-search backward: ",
171 "I-search: ", "failing I-search: "
175 static int is_redo __P((struct markdata *));
176 static void is_process __P((char *, int, char *));
177 static int is_bm __P((char *, int, int, int, int));
180 static int
181 is_bm(str, l, p, end, dir)
182 char *str;
183 int l, p, end, dir;
185 int tab[256];
186 int i, q;
187 unsigned char *s, c;
188 int w = flayer->l_width;
190 /* *sigh* to make WIN work */
191 fore = ((struct markdata *)flayer->l_next->l_data)->md_window;
192 debug2("is_bm: searching for %s len %d\n", str, l);
193 debug3("start at %d end %d dir %d\n", p, end, dir);
194 if (p < 0 || p + l > end)
195 return -1;
196 if (l == 0)
197 return p;
198 if (dir < 0)
199 str += l - 1;
200 for (i = 0; i < 256; i++)
201 tab[i] = l * dir;
202 for (i = 0; i < l - 1; i++, str += dir)
204 q = *(unsigned char *)str;
205 tab[q] = (l - 1 - i) * dir;
206 if (search_ic && (q | 0x20) >= 'a' && ((q | 0x20) <= 'z'))
207 tab[q ^ 0x20] = (l - 1 - i) * dir;
209 if (dir > 0)
210 p += l - 1;
211 debug1("first char to match: %c\n", *str);
212 while (p >= 0 && p < end)
214 q = p;
215 s = (unsigned char *)str;
216 for (i = 0;;)
218 c = (WIN(q / w))->image[q % w];
219 if (i == 0)
220 p += tab[(int)(unsigned char) c];
221 if (c != *s)
222 if (!search_ic || ((c ^ *s) & 0xdf) || (c | 0x20) < 'a' || (c | 0x20) > 'z')
223 break;
224 q -= dir;
225 s -= dir;
226 if (++i == l)
227 return q + (dir > 0 ? 1 : -l);
230 return -1;
234 /*ARGSUSED*/
235 static void
236 is_process(p, n, data) /* i-search */
237 char *p;
238 int n;
239 char *data; /* dummy */
241 int pos, x, y, dir;
242 struct markdata *markdata;
244 if (n == 0)
245 return;
246 ASSERT(p);
247 markdata = (struct markdata *)flayer->l_next->l_data;
249 pos = markdata->cx + markdata->cy * flayer->l_width;
250 LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
252 switch (*p)
254 case '\007': /* CTRL-G */
255 pos = markdata->isstartpos;
256 /*FALLTHROUGH*/
257 case '\033': /* ESC */
258 *p = 0;
259 break;
260 case '\013': /* CTRL-K */
261 case '\027': /* CTRL-W */
262 markdata->isistrl = 1;
263 /*FALLTHROUGH*/
264 case '\b':
265 case '\177':
266 if (markdata->isistrl == 0)
267 return;
268 markdata->isistrl--;
269 pos = is_redo(markdata);
270 *p = '\b';
271 break;
272 case '\023': /* CTRL-S */
273 case '\022': /* CTRL-R */
274 if (markdata->isistrl >= (int)sizeof(markdata->isistr))
275 return;
276 dir = (*p == '\023') ? 1 : -1;
277 pos += dir;
278 if (markdata->isdir == dir && markdata->isistrl == 0)
280 strcpy(markdata->isistr, markdata->isstr);
281 markdata->isistrl = markdata->isstrl = strlen(markdata->isstr);
282 break;
284 markdata->isdir = dir;
285 markdata->isistr[markdata->isistrl++] = *p;
286 break;
287 default:
288 if (*p < ' ' || markdata->isistrl >= (int)sizeof(markdata->isistr)
289 || markdata->isstrl >= (int)sizeof(markdata->isstr) - 1)
290 return;
291 markdata->isstr[markdata->isstrl++] = *p;
292 markdata->isistr[markdata->isistrl++] = *p;
293 markdata->isstr[markdata->isstrl] = 0;
294 debug2("New char: %c - left %d\n", *p, (int)sizeof(markdata->isistr) - markdata->isistrl);
296 if (*p && *p != '\b')
297 pos = is_bm(markdata->isstr, markdata->isstrl, pos, flayer->l_width * (markdata->md_window->w_histheight + flayer->l_height), markdata->isdir);
298 if (pos >= 0)
300 x = pos % flayer->l_width;
301 y = pos / flayer->l_width;
302 LAY_CALL_UP
304 LayRedisplayLine(INPUTLINE, 0, flayer->l_width - 1, 0);
305 revto(x, y);
306 if (W2D(markdata->cy) == INPUTLINE)
307 revto_line(markdata->cx, markdata->cy, INPUTLINE > 0 ? INPUTLINE - 1 : 1);
310 if (*p)
311 inp_setprompt(isprompts[markdata->isdir + (pos < 0) + 1], markdata->isstrl ? markdata->isstr : "");
312 flayer->l_x = markdata->cx;
313 flayer->l_y = W2D(markdata->cy);
314 LGotoPos(flayer, flayer->l_x, flayer->l_y);
315 if (!*p)
317 /* we are about to finish, keep cursor position */
318 flayer->l_next->l_x = markdata->cx;
319 flayer->l_next->l_y = W2D(markdata->cy);
323 static int
324 is_redo(markdata)
325 struct markdata *markdata;
327 int i, pos, npos, dir;
328 char c;
330 npos = pos = markdata->isstartpos;
331 dir = markdata->isstartdir;
332 markdata->isstrl = 0;
333 for (i = 0; i < markdata->isistrl; i++)
335 c = markdata->isistr[i];
336 if (c == '\022') /* ^R */
337 pos += (dir = -1);
338 else if (c == '\023') /* ^S */
339 pos += (dir = 1);
340 else
341 markdata->isstr[markdata->isstrl++] = c;
342 if (pos >= 0)
344 npos = is_bm(markdata->isstr, markdata->isstrl, pos, flayer->l_width * (markdata->md_window->w_histheight + flayer->l_height), dir);
345 if (npos >= 0)
346 pos = npos;
349 markdata->isstr[markdata->isstrl] = 0;
350 markdata->isdir = dir;
351 return npos;
354 void
355 ISearch(dir)
356 int dir;
358 struct markdata *markdata;
360 markdata = (struct markdata *)flayer->l_data;
361 markdata->isdir = markdata->isstartdir = dir;
362 markdata->isstartpos = markdata->cx + markdata->cy * flayer->l_width;
363 markdata->isistrl = markdata->isstrl = 0;
364 if (W2D(markdata->cy) == INPUTLINE)
365 revto_line(markdata->cx, markdata->cy, INPUTLINE > 0 ? INPUTLINE - 1 : 1);
366 Input(isprompts[dir + 1], sizeof(markdata->isstr) - 1, INP_RAW,
367 is_process, NULL, 0);
368 LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
369 flayer->l_x = markdata->cx;
370 flayer->l_y = W2D(markdata->cy);
373 #endif /* COPY_PASTE */