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
5 *
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 2, or (at your option)
9 * any later version.
10 *
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.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
20 *
21 ****************************************************************
22 */
23
24#include <sys/types.h>
25
26#include "config.h"
27#include "screen.h"
28#include "mark.h"
29#include "extern.h"
30
31#define INPUTLINE (flayer->l_height - 1)
32
33extern struct layer *flayer;
34extern struct win *fore;
35
36#ifdef COPY_PASTE
37
38int search_ic;
39
40/********************************************************************
41 *  VI style Search
42 */
43
44static int  matchword __P((char *, int, int, int));
45static void searchend __P((char *, int, char *));
46static void backsearchend __P((char *, int, char *));
47
48void
49Search(dir)
50int dir;
51{
52  struct markdata *markdata;
53  if (dir == 0)
54    {
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");
62    }
63  else
64    Input((dir > 0 ? "/" : "?"), sizeof(markdata->isstr)-1, INP_COOKED,
65          (dir > 0 ? searchend : backsearchend), NULL);
66}
67
68static void
69searchend(buf, len, data)
70char *buf;
71int len;
72char *data;	/* dummy */
73{
74  int x = 0, sx, ex, y;
75  struct markdata *markdata;
76  struct win *p;
77
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)
86    {
87      if ((x = matchword(markdata->isstr, y, sx, ex)) >= 0)
88        break;
89    }
90  if (y >= p->w_histheight + flayer->l_height)
91    {
92      LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
93      LMsg(0, "Pattern not found");
94    }
95  else
96    revto(x, y);
97}
98
99static void
100backsearchend(buf, len, data)
101char *buf;
102int len;
103char *data;	/* dummy */
104{
105  int sx, ex, x = -1, y;
106  struct markdata *markdata;
107
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)
114    {
115      sx = 0;
116      while ((sx = matchword(markdata->isstr, y, sx, ex)) >= 0)
117	x = sx++;
118      if (x >= 0)
119	break;
120    }
121  if (y < 0)
122    {
123      LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
124      LMsg(0, "Pattern not found");
125    }
126  else
127    revto(x, y);
128}
129
130static int
131matchword(pattern, y, sx, ex)
132char *pattern;
133int y, sx, ex;
134{
135  unsigned char *ip, *ipe, *cp, *pp;
136  struct mline *ml;
137
138  /* *sigh* to make WIN work */
139  fore = ((struct markdata *)flayer->l_data)->md_window;
140
141  ml = WIN(y);
142  ip = ml->image + sx;
143  ipe = ml->image + flayer->l_width;
144  for (;sx <= ex; sx++)
145    {
146      cp = ip++;
147      pp = (unsigned char *)pattern;
148      for (;;)
149	{
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;
159	}
160    }
161  return -1;
162}
163
164
165/********************************************************************
166 *  Emacs style ISearch
167 */
168
169static char *isprompts[] = {
170  "I-search backward: ", "failing I-search backward: ",
171  "I-search: ", "failing I-search: "
172};
173
174
175static int  is_redo __P((struct markdata *));
176static void is_process __P((char *, int, char *));
177static int  is_bm __P((char *, int, int, int, int));
178
179
180static int
181is_bm(str, l, p, end, dir)
182char *str;
183int l, p, end, dir;
184{
185  int tab[256];
186  int i, q;
187  unsigned char *s, c;
188  int w = flayer->l_width;
189
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)
203    {
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;
208    }
209  if (dir > 0)
210    p += l - 1;
211  debug1("first char to match: %c\n", *str);
212  while (p >= 0 && p < end)
213    {
214      q = p;
215      s = (unsigned char *)str;
216      for (i = 0;;)
217	{
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);
228	}
229    }
230  return -1;
231}
232
233
234/*ARGSUSED*/
235static void
236is_process(p, n, data)	/* i-search */
237char *p;
238int n;
239char *data;	/* dummy */
240{
241  int pos, x, y, dir;
242  struct markdata *markdata;
243
244  if (n == 0)
245    return;
246  ASSERT(p);
247  markdata = (struct markdata *)flayer->l_next->l_data;
248
249  pos = markdata->cx + markdata->cy * flayer->l_width;
250  LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
251
252  switch (*p)
253    {
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)
279	{
280	  strcpy(markdata->isistr, markdata->isstr);
281	  markdata->isistrl = markdata->isstrl = strlen(markdata->isstr);
282	  break;
283	}
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);
295    }
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)
299    {
300      x = pos % flayer->l_width;
301      y = pos / flayer->l_width;
302      LAY_CALL_UP
303	(
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);
308        );
309    }
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)
316    {
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);
320    }
321}
322
323static int
324is_redo(markdata)
325struct markdata *markdata;
326{
327  int i, pos, npos, dir;
328  char c;
329
330  npos = pos = markdata->isstartpos;
331  dir = markdata->isstartdir;
332  markdata->isstrl = 0;
333  for (i = 0; i < markdata->isistrl; i++)
334    {
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)
343	{
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;
347	}
348    }
349  markdata->isstr[markdata->isstrl] = 0;
350  markdata->isdir = dir;
351  return npos;
352}
353
354void
355ISearch(dir)
356int dir;
357{
358  struct markdata *markdata;
359
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);
368  LGotoPos(flayer, markdata->cx, W2D(markdata->cy));
369  flayer->l_x = markdata->cx;
370  flayer->l_y = W2D(markdata->cy);
371}
372
373#endif /* COPY_PASTE */
374