1 /* $Id: search.c,v 1.31 2004/03/23 16:44:02 ukai Exp $ */
2 #include "fm.h"
3 #include "regex.h"
4 #include <signal.h>
5 #include <errno.h>
6 #include <unistd.h>
7 
8 static void
set_mark(Line * l,int pos,int epos)9 set_mark(Line *l, int pos, int epos)
10 {
11     for (; pos < epos && pos < l->size; pos++)
12 	l->propBuf[pos] |= PE_MARK;
13 }
14 
15 #ifdef USE_MIGEMO
16 /* Migemo: romaji --> kana+kanji in regexp */
17 static FILE *migemor = NULL, *migemow = NULL;
18 static int migemo_running;
19 static int migemo_pid = 0;
20 
21 void
init_migemo()22 init_migemo()
23 {
24     migemo_active = migemo_running = use_migemo;
25     if (migemor != NULL)
26 	fclose(migemor);
27     if (migemow != NULL)
28 	fclose(migemow);
29     migemor = migemow = NULL;
30     if (migemo_pid)
31 	kill(migemo_pid, SIGKILL);
32     migemo_pid = 0;
33 }
34 
35 static int
open_migemo(char * migemo_command)36 open_migemo(char *migemo_command)
37 {
38     migemo_pid = open_pipe_rw(&migemor, &migemow);
39     if (migemo_pid < 0)
40 	goto err0;
41     if (migemo_pid == 0) {
42 	/* child */
43 	setup_child(FALSE, 2, -1);
44 	myExec(migemo_command);
45 	/* XXX: ifdef __EMX__, use start /f ? */
46     }
47     return 1;
48   err0:
49     migemo_pid = 0;
50     migemo_active = migemo_running = 0;
51     return 0;
52 }
53 
54 static char *
migemostr(char * str)55 migemostr(char *str)
56 {
57     Str tmp = NULL;
58     if (migemor == NULL || migemow == NULL)
59 	if (open_migemo(migemo_command) == 0)
60 	    return str;
61     fprintf(migemow, "%s\n", conv_to_system(str));
62   again:
63     if (fflush(migemow) != 0) {
64 	switch (errno) {
65 	case EINTR:
66 	    goto again;
67 	default:
68 	    goto err;
69 	}
70     }
71     tmp = Str_conv_from_system(Strfgets(migemor));
72     Strchop(tmp);
73     if (tmp->length == 0)
74 	goto err;
75     return conv_search_string(tmp->ptr, SystemCharset);
76   err:
77     /* XXX: backend migemo is not working? */
78     init_migemo();
79     migemo_active = migemo_running = 0;
80     return str;
81 }
82 #endif				/* USE_MIGEMO */
83 
84 #ifdef USE_M17N
85 /* normalize search string */
86 char *
conv_search_string(char * str,wc_ces f_ces)87 conv_search_string(char *str, wc_ces f_ces)
88 {
89     if (SearchConv && !WcOption.pre_conv &&
90 	Currentbuf->document_charset != f_ces)
91 	str = wtf_conv_fit(str, Currentbuf->document_charset);
92     return str;
93 }
94 #endif
95 
96 int
forwardSearch(Buffer * buf,char * str)97 forwardSearch(Buffer *buf, char *str)
98 {
99     char *p, *first, *last;
100     Line *l, *begin;
101     int wrapped = FALSE;
102     int pos;
103 
104 #ifdef USE_MIGEMO
105     if (migemo_active > 0) {
106 	if (((p = regexCompile(migemostr(str), IgnoreCase)) != NULL)
107 	    && ((p = regexCompile(str, IgnoreCase)) != NULL)) {
108 	    message(p, 0, 0);
109 	    return SR_NOTFOUND;
110 	}
111     }
112     else
113 #endif
114     if ((p = regexCompile(str, IgnoreCase)) != NULL) {
115 	message(p, 0, 0);
116 	return SR_NOTFOUND;
117     }
118     l = buf->currentLine;
119     if (l == NULL) {
120 	return SR_NOTFOUND;
121     }
122     pos = buf->pos;
123     if (l->bpos) {
124 	pos += l->bpos;
125 	while (l->bpos && l->prev)
126 	    l = l->prev;
127     }
128     begin = l;
129 #ifdef USE_M17N
130     while (pos < l->size && l->propBuf[pos] & PC_WCHAR2)
131 	pos++;
132 #endif
133     if (pos < l->size && regexMatch(&l->lineBuf[pos], l->size - pos, 0) == 1) {
134 	matchedPosition(&first, &last);
135 	pos = first - l->lineBuf;
136 	while (pos >= l->len && l->next && l->next->bpos) {
137 	    pos -= l->len;
138 	    l = l->next;
139 	}
140 	buf->pos = pos;
141 	if (l != buf->currentLine)
142 	    gotoLine(buf, l->linenumber);
143 	arrangeCursor(buf);
144 	set_mark(l, pos, pos + last - first);
145 	return SR_FOUND;
146     }
147     for (l = l->next;; l = l->next) {
148 	if (l == NULL) {
149 	    if (buf->pagerSource) {
150 		l = getNextPage(buf, 1);
151 		if (l == NULL) {
152 		    if (WrapSearch && !wrapped) {
153 			l = buf->firstLine;
154 			wrapped = TRUE;
155 		    }
156 		    else {
157 			break;
158 		    }
159 		}
160 	    }
161 	    else if (WrapSearch) {
162 		l = buf->firstLine;
163 		wrapped = TRUE;
164 	    }
165 	    else {
166 		break;
167 	    }
168 	}
169 	if (l->bpos)
170 	    continue;
171 	if (regexMatch(l->lineBuf, l->size, 1) == 1) {
172 	    matchedPosition(&first, &last);
173 	    pos = first - l->lineBuf;
174 	    while (pos >= l->len && l->next && l->next->bpos) {
175 		pos -= l->len;
176 		l = l->next;
177 	    }
178 	    buf->pos = pos;
179 	    buf->currentLine = l;
180 	    gotoLine(buf, l->linenumber);
181 	    arrangeCursor(buf);
182 	    set_mark(l, pos, pos + last - first);
183 	    return SR_FOUND | (wrapped ? SR_WRAPPED : 0);
184 	}
185 	if (wrapped && l == begin)	/* no match */
186 	    break;
187     }
188     return SR_NOTFOUND;
189 }
190 
191 int
backwardSearch(Buffer * buf,char * str)192 backwardSearch(Buffer *buf, char *str)
193 {
194     char *p, *q, *found, *found_last, *first, *last;
195     Line *l, *begin;
196     int wrapped = FALSE;
197     int pos;
198 
199 #ifdef USE_MIGEMO
200     if (migemo_active > 0) {
201 	if (((p = regexCompile(migemostr(str), IgnoreCase)) != NULL)
202 	    && ((p = regexCompile(str, IgnoreCase)) != NULL)) {
203 	    message(p, 0, 0);
204 	    return SR_NOTFOUND;
205 	}
206     }
207     else
208 #endif
209     if ((p = regexCompile(str, IgnoreCase)) != NULL) {
210 	message(p, 0, 0);
211 	return SR_NOTFOUND;
212     }
213     l = buf->currentLine;
214     if (l == NULL) {
215 	return SR_NOTFOUND;
216     }
217     pos = buf->pos;
218     if (l->bpos) {
219 	pos += l->bpos;
220 	while (l->bpos && l->prev)
221 	    l = l->prev;
222     }
223     begin = l;
224     if (pos > 0) {
225 	pos--;
226 #ifdef USE_M17N
227 	while (pos > 0 && l->propBuf[pos] & PC_WCHAR2)
228 	    pos--;
229 #endif
230 	p = &l->lineBuf[pos];
231 	found = NULL;
232 	found_last = NULL;
233 	q = l->lineBuf;
234 	while (regexMatch(q, &l->lineBuf[l->size] - q, q == l->lineBuf) == 1) {
235 	    matchedPosition(&first, &last);
236 	    if (first <= p) {
237 		found = first;
238 		found_last = last;
239 	    }
240 	    if (q - l->lineBuf >= l->size)
241 		break;
242 	    q++;
243 #ifdef USE_M17N
244 	    while (q - l->lineBuf < l->size
245 		   && l->propBuf[q - l->lineBuf] & PC_WCHAR2)
246 		q++;
247 #endif
248 	    if (q > p)
249 		break;
250 	}
251 	if (found) {
252 	    pos = found - l->lineBuf;
253 	    while (pos >= l->len && l->next && l->next->bpos) {
254 		pos -= l->len;
255 		l = l->next;
256 	    }
257 	    buf->pos = pos;
258 	    if (l != buf->currentLine)
259 		gotoLine(buf, l->linenumber);
260 	    arrangeCursor(buf);
261 	    set_mark(l, pos, pos + found_last - found);
262 	    return SR_FOUND;
263 	}
264     }
265     for (l = l->prev;; l = l->prev) {
266 	if (l == NULL) {
267 	    if (WrapSearch) {
268 		l = buf->lastLine;
269 		wrapped = TRUE;
270 	    }
271 	    else {
272 		break;
273 	    }
274 	}
275 	found = NULL;
276 	found_last = NULL;
277 	q = l->lineBuf;
278 	while (regexMatch(q, &l->lineBuf[l->size] - q, q == l->lineBuf) == 1) {
279 	    matchedPosition(&first, &last);
280 	    found = first;
281 	    found_last = last;
282 	    if (q - l->lineBuf >= l->size)
283 		break;
284 	    q++;
285 #ifdef USE_M17N
286 	    while (q - l->lineBuf < l->size
287 		   && l->propBuf[q - l->lineBuf] & PC_WCHAR2)
288 		q++;
289 #endif
290 	}
291 	if (found) {
292 	    pos = found - l->lineBuf;
293 	    while (pos >= l->len && l->next && l->next->bpos) {
294 		pos -= l->len;
295 		l = l->next;
296 	    }
297 	    buf->pos = pos;
298 	    gotoLine(buf, l->linenumber);
299 	    arrangeCursor(buf);
300 	    set_mark(l, pos, pos + found_last - found);
301 	    return SR_FOUND | (wrapped ? SR_WRAPPED : 0);
302 	}
303 	if (wrapped && l == begin)	/* no match */
304 	    break;
305     }
306     return SR_NOTFOUND;
307 }
308