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