1 /*  Copyright (C) 2001-2004  Kenichi Suto
2  *
3  *  This program is free software; you can redistribute it and/or modify
4  *  it under the terms of the GNU General Public License as published by
5  *  the Free Software Foundation; either version 2 of the License, or
6  *  (at your option) any later version.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 */
17 
18 #include <sys/types.h>
19 
20 #ifndef __WIN32__
21 #include <sys/wait.h>
22 #endif
23 
24 #include "defs.h"
25 
26 #include "bmh.h"
27 #include "eb.h"
28 #include "dialog.h"
29 #include "dirtree.h"
30 #include "external.h"
31 #include "filter.h"
32 #include "global.h"
33 #include "headword.h"
34 #include "history.h"
35 #include "jcode.h"
36 #include "mainwindow.h"
37 #include "misc.h"
38 #include "pref_io.h"
39 #include "reg.h"
40 #include "textview.h"
41 #include "thread_search.h"
42 
43 
44 #include <pthread.h>
45 
46 #define EBOOK_MAX_KEYWORDS 256
47 
48 void grep_file(gchar *file, gchar *word, gint method);
49 static void *grep_search_thread(void *arg);
50 static void list_file_recursive(gchar *dirname, gint depth, gchar *pat);
51 
52 static GList *grep_file_list=NULL;
53 static gchar *gword=NULL;
54 
55 static GtkWidget *grep_bar=NULL;
56 GtkWidget *combo_dirgroup=NULL;
57 
58 extern GtkTextBuffer *text_buffer;
59 extern GtkWidget *main_view;
60 extern GtkWidget *directory_view;
61 extern GtkWidget *note_tree;
62 
grep_search(gchar * word)63 void grep_search(gchar *word){
64 	LOG(LOG_DEBUG, "IN : grep_search()");
65 
66 	clear_search_result();
67 /*
68 	grep_search_thread(word);
69 	show_result_tree();
70 	return;
71 */
72 	if(gword != NULL)
73 		g_free(gword);
74 
75 	gword = strdup(word);
76 
77 	thread_search(TRUE, _("File Search"), grep_search_thread, gword);
78 
79 	LOG(LOG_DEBUG, "OUT : grep_search()");
80 }
81 
remove_non_ascii(gchar * str)82 gchar *remove_non_ascii(gchar *str)
83 {
84 	gchar *ret;
85 	gchar *p;
86 
87 	p = ret = g_strdup(str);
88 
89 	while(*p != '\0') {
90 		if(!isascii(*p))
91 			*p = 0x20;
92 		p ++;
93 	}
94 	return(ret);
95 }
96 
97 
remember_line(gchar * file,gint page,gint line,gint offset,gchar * heading,gchar * word,gint code)98 void remember_line(gchar *file, gint page, gint line, gint offset, gchar *heading, gchar *word, gint code){
99 	RESULT *rp;
100 	gchar *tmp;
101 	gchar *p;
102 	gchar *start;
103 	gint i;
104 	gchar buff[512];
105 	gchar *here;
106 
107 	LOG(LOG_DEBUG, "IN : remember_line(%s, %d, %s, %s, %d)", file, line, heading, word, code);
108 
109 	rp = g_new0(RESULT,1);
110 
111 	p = heading;
112 	while((*p == ' ') || (*p == '\t'))
113 		p++;
114 
115 	switch(code){
116 
117 	case KCODE_EUC:
118 		tmp = iconv_convert2("euc-jp", "utf-8", p);
119 		break;
120 	case KCODE_JIS:
121 		tmp = iconv_convert2("iso-2022-jp", "utf-8", p);
122 		break;
123 	case KCODE_SJIS:
124 		tmp = iconv_convert2("Shift_JIS", "utf-8", p);
125 		break;
126 	case KCODE_ASCII:
127 		tmp = remove_non_ascii(heading);
128 		break;
129 	default:
130 		g_free(rp->word);
131 		g_free(rp);
132 		return;
133 		break;
134 	}
135 
136 	rp->word = iconv_convert("euc-jp", "utf-8", word);
137 
138 	// Extract 10 characters before/ after keyword
139 
140 	here = simple_search(rp->word, tmp, strlen(tmp), bignore_case);
141 	if(here != NULL){
142 		p = here;
143 		for(i=0; i < additional_chars ; i ++){
144 			p = g_utf8_find_prev_char(tmp, p);
145 			if(p == NULL) {
146 				p = tmp;
147 				break;
148 			}
149 		}
150 		start = p;
151 
152 		if(start != tmp){
153 			strcpy(buff, "....");
154 			g_utf8_strncpy(&buff[4], start, additional_chars*2+g_utf8_strlen(word, -1));
155 		} else {
156 			g_utf8_strncpy(buff, start, additional_chars + i + g_utf8_strlen(word, -1));
157 		}
158 
159 		if(g_utf8_strlen(buff, -1) == additional_chars*2+g_utf8_strlen(word, -1))
160 			strcat(buff, "....");
161 
162 		rp->heading = strdup(buff);
163 		g_free(tmp);
164 	} else {
165 		rp->heading = tmp;
166 	}
167 
168 	rp->type = RESULT_TYPE_GREP;
169 	rp->data.grep.filename = native_to_generic(file);
170 //	rp->data.grep.filename = strdup(file);
171 	rp->data.grep.page = page;
172 	rp->data.grep.line = line;
173 	rp->data.grep.offset = offset;
174 
175 	add_result(rp);
176 
177 	LOG(LOG_DEBUG, "OUT : remember_line()");
178 }
179 
180 enum {
181 	METHOD_REGEX,
182 	METHOD_BMH,
183 	METHOD_SIMPLE
184 };
185 
186 BMH_TABLE *bmh_euc[EBOOK_MAX_KEYWORDS];
187 BMH_TABLE *bmh_sjis[EBOOK_MAX_KEYWORDS];
188 REG_TABLE *reg_euc=NULL;
189 REG_TABLE *reg_sjis=NULL;
190 
grep_file(gchar * file,gchar * word,gint method)191 void grep_file(gchar *file, gchar *word, gint method){
192 	gchar *contents;
193 	gchar *p, *pp;
194 	gint page;
195 	gint line;
196 	guchar c1;
197 	gchar *r=NULL;
198 	gint i;
199 	gint code;
200 	BMH_TABLE **bmh=NULL;
201 	REG_TABLE *reg=NULL;
202 	gchar *utf_filename;
203 
204 	LOG(LOG_DEBUG, "IN : grep_file(%s, %s %d)", file, word, method);
205 
206 	utf_filename = fs_to_unicode(file);
207 	push_message(utf_filename);
208 	g_free(utf_filename);
209 
210 	contents = get_cache_file(file);
211 	if(contents == NULL) {
212 		LOG(LOG_DEBUG, "OUT : grep_file() : NOP");
213 		return;
214 	}
215 
216 	// For higher performance, specially handle EUC and SJIS
217 
218 	code = guess_kanji(max_bytes_to_guess, contents);
219 
220 	switch(code){
221 		gchar *tmp;
222 	case KCODE_EUC:
223 		push_message(" (EUC)");
224 		LOG(LOG_DEBUG, "EUC");
225 		bmh = bmh_euc;
226 		reg = reg_euc;
227 		break;
228 
229 	case KCODE_JIS:
230 		push_message(" (JIS)");
231 		LOG(LOG_DEBUG, "JIS");
232 		tmp = iconv_convert2("iso-2022-jp", "euc-jp", contents);
233 		g_free(contents);
234 		contents = tmp;
235 
236 		bmh = bmh_euc;
237 		reg = reg_euc;
238 
239 		code = KCODE_EUC;
240 		break;
241 
242 	case KCODE_SJIS:
243 		push_message(" (SJIS)");
244 		LOG(LOG_DEBUG, "SJIS");
245 		bmh = bmh_sjis;
246 		reg = reg_sjis;
247 		break;
248 
249 	case KCODE_ASCII:
250 		push_message(" (ASCII)");
251 		LOG(LOG_DEBUG, "ASCII");
252 		bmh = bmh_euc;
253 		reg = reg_euc;
254 		break;
255 
256 	default:
257 		push_message(" (Unknown code) ... skipped.");
258 		LOG(LOG_INFO, "Unknown kanji code  : %s", file);
259 		g_free(contents);
260 		return;
261 		break;
262 	}
263 
264 	push_message(" ... ");
265 
266 	// Split into lines
267 	p = contents;
268 	pp = contents;
269 	line = 1;
270 	page = 1;
271 	while(1){
272 		if(*pp == '\0'){
273 			if(method == METHOD_BMH) {
274 				for(i=0; i < EBOOK_MAX_KEYWORDS; i++) {
275 					if(bmh[i] == NULL)
276 						break;
277 					r = bmh_search(bmh[i], p, pp - p);
278 					if(r == NULL)
279 						break;
280 				}
281 			} else if (method == METHOD_REGEX)
282 				r = regex_search(reg, p);
283 			else
284 				r = simple_search(word, p, pp - p, bignore_case);
285 
286 			if(r != NULL)
287 				remember_line(file, page, line, p - contents, p, word, code);
288 			break;
289 		} else if((*pp == 0x0a) || (*pp == 0x0d)) {
290 			c1 = *pp;
291 			*pp = '\0';
292 
293 			if(method == METHOD_BMH)
294 				for(i=0; i < EBOOK_MAX_KEYWORDS; i++) {
295 					if(bmh[i] == NULL)
296 						break;
297 					r = bmh_search(bmh[i], p, pp - p);
298 					if(r == NULL)
299 						break;
300 				}
301 			else if (method == METHOD_REGEX)
302 				r = regex_search(reg, p);
303 			else
304 				r = simple_search(word, p, pp - p, bignore_case);
305 
306 			if(r != NULL)
307 				remember_line(file, page, line, p - contents, p, word, code);
308 
309 			*pp = c1;
310 
311 			if((*pp == 0x0d) && (*(pp+1) == 0x0a)) {
312 				p = pp = pp + 2;
313 			} else {
314 				p = pp = pp + 1;
315 			}
316 
317 			line ++;
318 		} else if(*pp == 0x0c){
319 			page++;
320 			pp++;
321 		} else {
322 			pp++;
323 		}
324 
325 	}
326 
327 	g_free(contents);
328 
329 	push_message("OK\n");
330 
331 	pthread_testcancel();
332 
333 	LOG(LOG_DEBUG, "OUT : grep_file()");
334 }
335 
list_file_recursive(gchar * dirname,gint depth,gchar * pat)336 static void list_file_recursive(gchar *dirname, gint depth, gchar *pat)
337 {
338 	GDir *dir;
339 	const gchar *name;
340 	gchar fullpath[512];
341 
342 	//LOG(LOG_DEBUG, "IN : list_file_recursive(%s, %d, %s)", dirname, depth, pat);
343 
344 	if((dir = g_dir_open(dirname, 0, NULL)) == NULL){
345 		if(g_file_test(dirname, G_FILE_TEST_IS_REGULAR) == TRUE){
346 
347 			if(pat != NULL) {
348 				// If it matches the pattern ?
349 				if((strstr(dirname, pat) != NULL) &&
350 				   (strlen(strstr(dirname, pat))== strlen(pat)))
351 					grep_file_list = g_list_append(grep_file_list, strdup(dirname));
352 			} else {
353 				grep_file_list = g_list_append(grep_file_list, strdup(dirname));
354 			}
355 			return;
356 		}
357 //		LOG(LOG_CRITICAL, "Failed to determine the type of %s.", dirname);
358 		LOG(LOG_DEBUG, "OUT : list_file_recursive()");
359 		return;
360 	}
361 
362 	while((name = g_dir_read_name(dir)) != NULL){
363 		if(strcmp(dirname,"/")==0){
364 			sprintf(fullpath,"/%s",name);
365 		} else if ((dirname[strlen(dirname) -1] == '\\') ||
366 			   (dirname[strlen(dirname) -1] == '/')){
367 			sprintf(fullpath,"%s%s",dirname, name);
368 		} else {
369 			sprintf(fullpath,"%s%s%s",dirname, DIR_DELIMITER, name);
370 		}
371 
372 		if(g_file_test(fullpath, G_FILE_TEST_IS_REGULAR) == TRUE){
373 			if(pat != NULL) {
374 
375 				// If it matches the pattern ?
376 				if((strstr(fullpath, pat) != NULL) &&
377 				   (strlen(strstr(fullpath, pat))== strlen(pat)))
378 					grep_file_list = g_list_append(grep_file_list, strdup(fullpath));
379 			} else {
380 				grep_file_list = g_list_append(grep_file_list, strdup(fullpath));
381 			}
382 
383 		} else if(g_file_test(fullpath, G_FILE_TEST_IS_DIR) == TRUE){
384 //			if(depth < 10)
385 				list_file_recursive(fullpath, depth+1, pat);
386 		}
387 	}
388 	g_dir_close(dir);
389 
390 	//LOG(LOG_DEBUG, "OUT : list_file_recursive()");
391 }
392 
compare_func(gconstpointer a,gconstpointer b)393 static gint compare_func(gconstpointer a, gconstpointer b){
394 	return(strcmp(a,b));
395 }
396 
includes_meta_char(guchar * word)397 static gboolean includes_meta_char(guchar *word)
398 {
399 	if((strchr(word, '^') != NULL) ||
400 	   (strchr(word, '$') != NULL) ||
401 	   (strchr(word, '[') != NULL) ||
402 	   //(strchr(word, ']') != NULL) || // Because there must be '['
403 	   //(strchr(word, '-') != NULL) || // Because there must be '['
404 	   (strchr(word, '.') != NULL) ||
405 	   (strchr(word, '*') != NULL) ||
406 	   (strchr(word, '+') != NULL) ||
407 	   (strchr(word, '?') != NULL) ||
408 	   (strchr(word, '|') != NULL) ||
409 	   (strchr(word, '{') != NULL) ||
410 	   (strchr(word, '}') != NULL) ||
411 	   //(strchr(word, ',') != NULL) || // Because there must be '{'
412 	   (strchr(word, '(') != NULL) ||
413 	   (strchr(word, ')') != NULL)){
414 		return(TRUE);
415 	} else {
416 		return(FALSE);
417 	}
418 }
419 
grep_search_thread(void * arg)420 static void *grep_search_thread(void *arg)
421 {
422 	gint state;
423 	GList *l;
424 	gint i, j;
425 	gint filecount;
426 	gchar *word = (gchar *)arg;
427 	gint method;
428 	gchar *l_word=NULL;
429 	gchar *dirname=NULL;
430 	gchar *p;
431 	char *keywords[EBOOK_MAX_KEYWORDS + 1];
432 	gchar *sjis_word;
433 	GList *dir_list=NULL;
434 	const gchar *group;
435 
436 	LOG(LOG_DEBUG, "IN : grep_search_thread()");
437 
438 	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &state);
439 	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &state);
440 
441 	// Create file list
442 	push_message(_("Listing files..."));
443 
444 	// Clear first
445 	l = g_list_first(grep_file_list);
446 	while(l != NULL){
447 		g_free(l->data);
448 		l = g_list_next(l);
449 	}
450 	if(grep_file_list) {
451 		g_list_free(grep_file_list);
452 	}
453 	grep_file_list = NULL;
454 
455 	group = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_dirgroup)->entry));
456 	if(strcmp(group, _("Manual Select")) == 0) {
457 		dir_list = get_active_dir_list();
458 
459 		g_list_sort(dir_list, compare_func);
460 
461 		l = g_list_first(dir_list);
462 		while(l){
463 			// Find recursively
464 			dirname = generic_to_native(l->data);
465 			list_file_recursive(dirname, 0, NULL);
466 			g_free(dirname);
467 			l = g_list_next(l);
468 		}
469 
470 		// Sort by name (full path)
471 		g_list_sort(grep_file_list, compare_func);
472 
473 		// Remove duplicate file
474 		l = g_list_first(grep_file_list);
475 		while(l){
476 			GList *next = l->next;
477 			if((next != NULL) && (strcmp(l->data, next->data) == 0)){
478 				g_free(next->data);
479 				grep_file_list = g_list_delete_link(grep_file_list, next);
480 				continue;
481 			}
482 			l = g_list_next(l);
483 		}
484 
485 	} else {
486 		GtkTreeIter iter;
487 
488 		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dirgroup_store), &iter) == TRUE){
489 			do {
490 				gchar *title;
491 				gchar *list;
492 				gboolean active;
493 				gchar *p, *pp;
494 
495 				gtk_tree_model_get(GTK_TREE_MODEL(dirgroup_store),
496 					   &iter,
497 					   DIRGROUP_TITLE_COLUMN, &title,
498 					   DIRGROUP_LIST_COLUMN, &list,
499 					   DIRGROUP_ACTIVE_COLUMN, &active,
500 					   -1);
501 				if(active == TRUE){
502 					p = list;
503 					pp = NULL;
504 					while(1){
505 						pp = strchr(p, '\n');
506 						if(pp == NULL){
507 							dir_list = g_list_append(dir_list, g_strdup(p));
508 							break;
509 						} else {
510 							*pp = '\0';
511 							if(strlen(p) != 0)
512 								dir_list = g_list_append(dir_list, g_strdup(p));
513 							*pp = '\n';
514 							p = pp + 1;
515 						}
516 					}
517 				}
518 				g_free(title);
519 				g_free(list);
520 			} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(dirgroup_store), &iter) == TRUE);
521 		}
522 
523 		l = g_list_first(dir_list);
524 		while(l){
525 			gchar *p;
526 			// Find recursively
527 			dirname = unicode_to_fs(l->data);
528 			p = strchr(dirname, ',');
529 			if(p == NULL) {
530 				list_file_recursive(dirname, 0, NULL);
531 			} else {
532 				*p = '\0';
533 				p ++;
534 				list_file_recursive(dirname, 0, p);
535 			}
536 			g_free(dirname);
537 			g_free(l->data);
538 			l = g_list_next(l);
539 		}
540 
541 		// Sort by name (full path)
542 		g_list_sort(grep_file_list, compare_func);
543 	}
544 
545 	push_message(_("done\n"));
546 
547 	g_list_free(dir_list);
548 
549 
550 	// Determine if it is a regular expression
551 	if ((word[0] == '\"') && (word[strlen(word) -1] == '\"')){
552 		method = METHOD_BMH;
553 		l_word = g_strndup(&word[1], strlen(word) - 2);
554 
555 		push_message(_("Force ordinary text.\n"));
556 	} else if(includes_meta_char(word) == TRUE){
557 		method = METHOD_REGEX;
558 		l_word = g_strdup(word);
559 
560 		push_message(_("Seems like regular expression.\n"));
561 
562 	// If the word is between / and /, it is a regular expression
563 	} else if ((word[0] == '/') && (word[strlen(word) -1] == '/')){
564 		method = METHOD_REGEX;
565 		l_word = g_strndup(&word[1], strlen(word) - 2);
566 
567 		push_message(_("Force regular expression.\n"));
568 	} else {
569 		method = METHOD_BMH;
570 		l_word = g_strdup(word);
571 
572 		push_message(_("Seems like ordinary text.\n"));
573 	}
574 
575 	if(method == METHOD_BMH) {
576 		for(i=0; i < EBOOK_MAX_KEYWORDS; i++) {
577 			bmh_euc[i] = NULL;
578 			bmh_sjis[i] = NULL;
579 		}
580 
581 		split_word(l_word, keywords);
582 		for(i=0, j=0; i < EBOOK_MAX_KEYWORDS; i++){
583 			if(keywords[i] == NULL)
584 				break;
585 			if(keywords[i][0] != '\0'){
586 				bmh_euc[j] = bmh_prepare(keywords[i], bignore_case);
587 				sjis_word = iconv_convert("euc-jp", "Shift_JIS", keywords[i]);
588 				bmh_sjis[j] = bmh_prepare(sjis_word, bignore_case);
589 				g_free(sjis_word);
590 				j++;
591 			}
592 		}
593 		free_words(keywords);
594 	}
595 	else if (method == METHOD_REGEX) {
596 		reg_euc = regex_prepare(l_word, bignore_case);
597 		sjis_word = iconv_convert("euc-jp", "Shift_JIS", l_word);
598 		reg_sjis = regex_prepare(sjis_word, bignore_case);
599 		g_free(sjis_word);
600 		if((reg_euc == NULL) || (reg_sjis == NULL)){
601 			push_message(_("Failed to compile pattern.\n"));
602 			goto END;
603 		}
604 	}
605 
606 
607 
608 	push_message(_("\nSearching following files...\n"));
609 
610 	// g_list_length() does not work. Why ?
611 	//filecount = g_list_length(grep_file_list);
612 
613 	l = g_list_first(grep_file_list);
614 	i=0;
615 	while(l != NULL){
616 		l = g_list_next(l);
617 		i++;
618 	}
619 	filecount = i;
620 
621 	l = g_list_first(grep_file_list);
622 	i=0;
623 	while(l != NULL){
624 #ifdef __WIN32__
625 		p = strrchr(l->data, '\\');
626 #else
627 		p = strrchr(l->data, '/');
628 #endif
629 		if(p == NULL){
630 			set_cancel_dlg_text(l->data);
631 		} else {
632 			set_cancel_dlg_text(p+1);
633 		}
634 
635 		grep_file(l->data, l_word, method);
636 
637 		set_progress((gfloat)(i+1) / filecount);
638 		l = g_list_next(l);
639 		i++;
640 	}
641 
642 	if(method == METHOD_BMH) {
643 		for(i=0; i < EBOOK_MAX_KEYWORDS; i++) {
644 			if(bmh_euc[i] != NULL)
645 				bmh_free(bmh_euc[i]);
646 			if(bmh_sjis[i] != NULL)
647 				bmh_free(bmh_sjis[i]);
648 		}
649 	}
650 	else if (method == METHOD_REGEX){
651 		regex_free(reg_euc);
652 		regex_free(reg_sjis);
653 	}
654 
655 	push_message(_("\nFile search completed.\n"));
656 
657  END:
658 	if(l_word)
659 		g_free(l_word);
660 
661 	thread_end();
662 
663 	LOG(LOG_DEBUG, "OUT : grep_search_thread()");
664 
665 	return(NULL);
666 }
667 
show_file(RESULT * rp)668 void show_file(RESULT *rp)
669 {
670 	gchar *contents;
671 	gchar *utf_str;
672 	GtkTextIter iter;
673 	GtkTextMark *mark = NULL;
674 	GtkTextIter *bow, *eow;
675 	gchar *filename;
676 	GtkTextIter *bol, *eol;
677 
678 	gchar *p;
679 	gchar *line_text;
680 	gchar *r;
681 	GtkTextIter start, end;
682 	gchar *segment;
683 	gint segment_start, segment_end;
684 	gint i;
685 	gint line_no=0;
686 	gint count;
687 	char *keywords[EBOOK_MAX_KEYWORDS + 1];
688 	gint code;
689 
690 	g_assert(rp->type == RESULT_TYPE_GREP);
691 
692 	LOG(LOG_DEBUG, "IN : show_file(%s, %d)", rp->data.grep.filename, rp->data.grep.line);
693 
694 	filename = generic_to_native(rp->data.grep.filename);
695 	contents = get_cache_file(filename);
696 	if(contents == NULL)
697 		return;
698 
699 	code = guess_kanji(max_bytes_to_guess, contents);
700 
701 	switch(code){
702 		gchar *tmp;
703 	case KCODE_EUC:
704 		break;
705 	case KCODE_JIS:
706 		tmp = iconv_convert2("iso-2022-jp", "euc-jp", contents);
707 		g_free(contents);
708 		contents = tmp;
709 		break;
710 	case KCODE_SJIS:
711 		break;
712 	case KCODE_ASCII:
713 		break;
714 	default:
715 		LOG(LOG_INFO, "Unknown kanji code  : %s", filename);
716 		g_free(contents);
717 		g_free(filename);
718 		return;
719 		break;
720 	}
721 
722 	g_free(filename);
723 
724 	// Extract several lines before and after the matched line
725 	for(i=rp->data.grep.offset, count = 0 ; i > 0 ; i --){
726 		if(contents[i] == 0x0a) {
727 			count++;
728 			if((i != 0) && (contents[i -1] == 0x0d)) {
729 				i --;
730 			}
731 		} else if (contents[i] == 0x0d) {
732 			count++;
733 		}
734 		if(count > additional_lines){
735 			if((contents[i] == 0x0d) && (contents[i] == 0x0d))
736 				i += 2;
737 			else
738 				i += 1;
739 
740 			line_no = count-1;
741 			break;
742 		}
743 	}
744 	if(i <= 0)
745 		line_no = count;
746 
747 	segment_start = i;
748 
749 	if(segment_start < 0)
750 		segment_start = 0;
751 
752 	for(i=rp->data.grep.offset, count = 0 ; contents[i] != '\0' ; i ++){
753 		if(contents[i] == 0x0a) {
754 			count++;
755 		} else if (contents[i] == 0x0d) {
756 			count++;
757 			if(contents[i + 1] == 0x0a) {
758 				i ++;
759 			}
760 		}
761 
762 		if(count > additional_lines){
763 			break;
764 		}
765 	}
766 	segment_end = i;
767 
768 	segment = g_strndup(&contents[segment_start], segment_end - segment_start);
769 
770 	if(code == KCODE_SJIS){
771 		utf_str = iconv_convert("Shift_JIS", "utf-8", segment);
772 	} else {
773 		utf_str = iconv_convert("euc-jp", "utf-8", segment);
774 	}
775 
776 	// Clear text buffer
777 	gtk_text_buffer_get_bounds (text_buffer, &start, &end);
778 	gtk_text_buffer_delete(text_buffer, &start, &end);
779 
780 	gtk_text_buffer_get_start_iter (text_buffer, &iter);
781 	gtk_text_buffer_insert_with_tags(
782 		text_buffer, &iter,
783 		utf_str, -1,
784 		tag_plain, NULL);
785 
786 	g_free(contents);
787 	g_free(segment);
788 	g_free(utf_str);
789 
790 /*
791 	gtk_text_buffer_get_start_iter (text_buffer, &iter);
792 	gtk_text_iter_set_line(&iter, line - 1);
793 */
794 	gtk_text_buffer_get_iter_at_line(text_buffer, &iter, line_no);
795 
796 	mark = gtk_text_buffer_create_mark(text_buffer, "mark", &iter, TRUE);
797 
798 	gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(main_view), mark,
799 				     0.0,
800 				     TRUE,
801 				     0.0, 0.1);
802 
803 	gtk_text_buffer_delete_mark(text_buffer, mark);
804 
805 
806 	bol = gtk_text_iter_copy(&iter);
807 	gtk_text_iter_forward_line(&iter);
808 	eol = gtk_text_iter_copy(&iter);
809 	gtk_text_buffer_apply_tag(text_buffer, tag_reverse, bol, eol);
810 	gtk_text_iter_free(bol);
811 	gtk_text_iter_free(eol);
812 
813 	// Emphasize keyword
814 
815 	if((includes_meta_char(rp->word) == TRUE) ||
816 	   ((rp->word[0] == '/') && (rp->word[strlen(rp->word) -1] == '/'))){
817 		goto END;
818 	}
819 
820 	split_word(rp->word, keywords);
821 	for(i=0; i < EBOOK_MAX_KEYWORDS; i++){
822 		if(keywords[i] == NULL)
823 			break;
824 		if(keywords[i][0] != '\0'){
825 			gtk_text_buffer_get_start_iter (text_buffer, &iter);
826 			while(1){
827 				bol = gtk_text_iter_copy(&iter);
828 				if(gtk_text_iter_forward_line(&iter) == FALSE)
829 					break;
830 				eol = gtk_text_iter_copy(&iter);
831 				line_text = gtk_text_buffer_get_text(text_buffer, bol, eol, FALSE);
832 
833 				p = line_text;
834 				while(1){
835 					r = simple_search(keywords[i], (guchar *)p, strlen(p), bignore_case);
836 					if(r == NULL)
837 						break;
838 					gtk_text_iter_set_line_index(bol, r - line_text);
839 					bow = gtk_text_iter_copy(bol);
840 					gtk_text_iter_set_line_index(bol, r - line_text + strlen(keywords[i]));
841 					eow = gtk_text_iter_copy(bol);
842 					gtk_text_buffer_apply_tag(text_buffer, tag_colored, bow, eow);
843 
844 					gtk_text_iter_free(bow);
845 					gtk_text_iter_free(eow);
846 
847 					p = r + strlen(keywords[i]);
848 				}
849 				g_free(line_text);
850 				gtk_text_iter_free(bol);
851 				gtk_text_iter_free(eol);
852 			}
853 
854 
855 
856 		}
857 	}
858 	free_words(keywords);
859 
860 	gtk_text_buffer_get_start_iter(text_buffer, &iter);
861 	gtk_text_buffer_place_cursor(text_buffer, &iter);
862 
863  END:
864 
865 	LOG(LOG_DEBUG, "OUT : show_file()");
866 }
867 
open_file(RESULT * rp)868 void open_file(RESULT *rp)
869 {
870 	GtkTreeIter   iter;
871 	gchar *p;
872 	gint found = 0;
873 	gchar *ext;
874 	gchar *open_command=NULL;
875 
876 	gchar buff[512];
877 	gchar tmp[512];
878 	gint i;
879 	gint r;
880 	gchar *filename;
881 
882 
883 	g_assert(rp->type == RESULT_TYPE_GREP);
884 
885 	LOG(LOG_DEBUG, "IN : open_file(%s)", rp->data.grep.filename);
886 
887 	filename = generic_to_native(rp->data.grep.filename);
888 
889 	if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filter_store), &iter) == TRUE){
890 		do {
891 			gtk_tree_model_get(GTK_TREE_MODEL(filter_store),
892 					   &iter,
893 					   FILTER_EXT_COLUMN, &ext,
894 					   FILTER_OPEN_COMMAND_COLUMN, &open_command,
895 					   -1);
896 
897 			if(match_extension(filename, ext) == TRUE){
898 				found = 1;
899 				break;
900 			} else {
901 				g_free(open_command);
902 				open_command = NULL;
903 			}
904 			g_free(ext);
905 		} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(filter_store), &iter) == TRUE);
906 	}
907 
908 	if((found == 0) ||
909 	   (open_command == NULL) ||
910 	   (strlen(open_command) == 0))	{
911 #ifdef __WIN32__
912 		HINSTANCE hi;
913 		hi = ShellExecute(NULL, "open", filename, NULL, NULL, SW_SHOWNORMAL);
914 		if((int)hi > 32){
915 			LOG(LOG_DEBUG, "OUT : open_file() = ShellExecute");
916 			return;
917 		}
918 #endif
919 
920 		LOG(LOG_DEBUG, "use default command");
921 		g_free(open_command);
922 		if((open_template == NULL) ||
923 		   (strlen(open_template) == 0)){
924 			LOG(LOG_DEBUG, "OUT : open_file() : failed");
925 			return;
926 		}
927 		open_command = strdup(open_template);
928 	}
929 
930 	p = open_command;
931 	i = 0;
932 	while(1){
933 		if (*p == '\0'){
934 			buff[i] = '\0';
935 			break;
936 		}
937 		if(*p == '%'){
938 			switch (*(p+1)){
939 			case 'f':
940 #ifdef __WIN32__
941 				buff[i] = '\"';
942 				i++;
943 #endif
944 				strcpy(&buff[i], filename);
945 				i = i + strlen(filename);
946 #ifdef __WIN32__
947 				buff[i] = '\"';
948 				i++;
949 #endif
950 				p = p + 2;
951 				break;
952 			case 'p':
953 				sprintf(tmp, "%d", rp->data.grep.page);
954 				strcpy(&buff[i], tmp);
955 				i = i + strlen(tmp);
956 				p = p + 2;
957 				break;
958 			case 'l':
959 				sprintf(tmp, "%d", rp->data.grep.line);
960 				strcpy(&buff[i], tmp);
961 				i = i + strlen(tmp);
962 				p = p + 2;
963 				break;
964 			}
965 		} else {
966 			buff[i] = *p;
967 			p++;
968 			i++;
969 		}
970 	}
971 	g_free(open_command);
972 	g_free(filename);
973 
974 	r = launch_external(buff, FALSE);
975 
976 	if(r == 0){
977 		LOG(LOG_DEBUG, "OUT : open_file()");
978 		return;
979 	} else {
980 		LOG(LOG_DEBUG, "OUT : open_file() : failed");
981 		return;
982 	}
983 
984 
985 }
986 
ignore_case_toggled(GtkWidget * widget,gpointer data)987 static gint ignore_case_toggled(GtkWidget *widget, gpointer data)
988 {
989 	LOG(LOG_DEBUG, "IN : ignore_case_toggled()");
990 
991 	bignore_case = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
992 
993 	LOG(LOG_DEBUG, "OUT : ignore_case_toggled(%d)", bignore_case);
994 
995 	return(FALSE);
996 }
997 
suppress_hidden_toggled(GtkWidget * widget,gpointer data)998 static gint suppress_hidden_toggled(GtkWidget *widget, gpointer data)
999 {
1000 	LOG(LOG_DEBUG, "IN : suppress_hidden_toggled()");
1001 
1002 	bsuppress_hidden_files = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
1003 	refresh_directory_tree();
1004 
1005 	LOG(LOG_DEBUG, "OUT : suppress_hidden_toggled(%d)", bignore_case);
1006 
1007 	return(FALSE);
1008 }
1009 
dirgroup_changed(GtkWidget * combo)1010 static gint dirgroup_changed (GtkWidget *combo){
1011 	const gchar *text;
1012 	GtkTreeIter   iter;
1013 
1014 	LOG(LOG_DEBUG, "IN : dirgroup_changed()");
1015 
1016 	text = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_dirgroup)->entry));
1017 
1018 	if(strcmp(text, _("Manual Select")) == 0) {
1019 	    if((note_tree != NULL) &&
1020 	       ( ebook_search_method() == SEARCH_METHOD_GREP) &&
1021 	       (gtk_notebook_get_current_page(GTK_NOTEBOOK(note_tree)) != 3))
1022 			gtk_notebook_set_current_page(GTK_NOTEBOOK(note_tree), 3);
1023 
1024 		if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dirgroup_store), &iter) == TRUE){
1025 			do {
1026 				gtk_list_store_set (dirgroup_store, &iter,
1027 						    DIRGROUP_ACTIVE_COLUMN, FALSE,
1028 						    -1);
1029 			} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(dirgroup_store), &iter) == TRUE);
1030 		}
1031 
1032 		goto END;
1033 
1034 //		gtk_widget_set_sensitive(directory_view, TRUE);
1035 	} else {
1036 //		gtk_widget_set_sensitive(directory_view, FALSE);
1037 	}
1038 
1039 	if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dirgroup_store), &iter) == TRUE){
1040 		do {
1041 			gchar *title;
1042 			gtk_tree_model_get (GTK_TREE_MODEL(dirgroup_store),
1043 					    &iter,
1044 					    DIRGROUP_TITLE_COLUMN, &title,
1045 					    -1);
1046 
1047 			if(strcmp(title, text) == 0){
1048 				gtk_list_store_set (dirgroup_store, &iter,
1049 						    DIRGROUP_ACTIVE_COLUMN, TRUE,
1050 						    -1);
1051 			} else {
1052 				gtk_list_store_set (dirgroup_store, &iter,
1053 						    DIRGROUP_ACTIVE_COLUMN, FALSE,
1054 						    -1);
1055 			}
1056 
1057 
1058 	       } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(dirgroup_store), &iter) == TRUE);
1059 	}
1060 
1061  END:
1062 	save_dirgroup();
1063 
1064 	LOG(LOG_DEBUG, "OUT : dirgroup_changed()");
1065 
1066 	return(FALSE);
1067 }
1068 
1069 
create_grep_bar()1070 GtkWidget *create_grep_bar()
1071 {
1072 	GtkWidget *button;
1073 
1074 	GList *list=NULL;
1075 	gchar *old_group=NULL;
1076 	gboolean active_found;
1077 	gboolean old_found;
1078 	GtkTreeIter active_iter;
1079 	GtkTreeIter old_iter;
1080 	GtkTreeIter iter;
1081 	gchar *title;
1082 	GList *children;
1083 	GtkBoxChild *child;
1084 
1085 
1086 	LOG(LOG_DEBUG, "IN : create_grep_bar()");
1087 
1088 	if(grep_bar){
1089 	        old_group = strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo_dirgroup)->entry)));
1090 	        children = GTK_BOX(grep_bar)->children;
1091 		while(children){
1092 		        child = children->data;
1093 			children = children->next;
1094 			gtk_widget_destroy(child->widget);
1095 		}
1096 	} else {
1097 	        grep_bar = gtk_hbox_new(FALSE, 0);
1098 	}
1099 
1100 	gtk_container_set_border_width(GTK_CONTAINER(grep_bar), 1);
1101 
1102 	combo_dirgroup = gtk_combo_new();
1103 	gtk_widget_set_size_request(GTK_WIDGET(combo_dirgroup), 120, 10);
1104 	gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(combo_dirgroup)->entry), FALSE);
1105 
1106 	g_signal_connect(G_OBJECT (GTK_COMBO(combo_dirgroup)->entry), "changed",
1107 			 G_CALLBACK(dirgroup_changed),
1108 			 NULL);
1109 
1110 	gtk_box_pack_start(GTK_BOX(grep_bar), combo_dirgroup, FALSE, FALSE, 0);
1111 
1112 
1113 	button = gtk_check_button_new_with_label(_("Suppress Hidden Files"));
1114 	gtk_box_pack_start(GTK_BOX (grep_bar), button, FALSE, FALSE, 5);
1115 	g_signal_connect(G_OBJECT(button), "toggled",
1116 			 G_CALLBACK(suppress_hidden_toggled),
1117 			 NULL);
1118 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), bsuppress_hidden_files);
1119 	gtk_tooltips_set_tip(tooltip, button, _("Suppress files whose name start with dot."),"Private");
1120 
1121 	button = gtk_check_button_new_with_label(_("Ignore Case"));
1122 	gtk_box_pack_start(GTK_BOX (grep_bar), button, FALSE, FALSE, 5);
1123 	g_signal_connect(G_OBJECT(button), "toggled",
1124 			 G_CALLBACK(ignore_case_toggled),
1125 			 NULL);
1126 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), bignore_case);
1127 	gtk_tooltips_set_tip(tooltip, button, _("When checked, uppercase letters and lowercase letters are regarded as identical."),"Private");
1128 
1129 	active_found = FALSE;
1130 	old_found = FALSE;
1131 
1132 	if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dirgroup_store), &iter) == TRUE){
1133 		do {
1134 			gchar *title;
1135 			gboolean active;
1136 			gtk_tree_model_get(GTK_TREE_MODEL(dirgroup_store),
1137 					   &iter,
1138 					   DIRGROUP_TITLE_COLUMN, &title,
1139 					   DIRGROUP_ACTIVE_COLUMN, &active,
1140 					   -1);
1141 
1142 			if(active == TRUE){
1143 				active_found = TRUE;
1144 				active_iter = iter;
1145 			}
1146 			if(old_group && (strcmp(title, old_group) == 0)){
1147 				old_found = TRUE;
1148 				old_iter = iter;
1149 			}
1150 			list = g_list_append(list, g_strdup(title));
1151 			g_free(title);
1152 	       } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(dirgroup_store), &iter) == TRUE);
1153 	}
1154 
1155 	list = g_list_append(list, g_strdup(_("Manual Select")));
1156 
1157 	if(g_list_length(list) != 0)
1158 	        gtk_combo_set_popdown_strings( GTK_COMBO(combo_dirgroup), list) ;
1159 
1160 	if(active_found == TRUE){
1161 		gtk_tree_model_get(GTK_TREE_MODEL(dirgroup_store),
1162 				   &active_iter,
1163 				   DIRGROUP_TITLE_COLUMN, &title,
1164 				   -1);
1165 		gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo_dirgroup)->entry), title);
1166 		g_free(title);
1167 	} else if (old_found == TRUE){
1168 		gtk_tree_model_get(GTK_TREE_MODEL(dirgroup_store),
1169 				   &old_iter,
1170 				   DIRGROUP_TITLE_COLUMN, &title,
1171 				   -1);
1172 		gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo_dirgroup)->entry), title);
1173 		g_free(title);
1174 
1175 		gtk_tree_store_set(GTK_TREE_STORE(dirgroup_store),
1176 				   &old_iter,
1177 				   DIRGROUP_ACTIVE_COLUMN, TRUE,
1178 				   -1);
1179 
1180 	} else {
1181 		gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo_dirgroup)->entry),
1182 				   _("Manual Select"));
1183 	}
1184 
1185 
1186 	LOG(LOG_DEBUG, "OUT : create_grep_bar()");
1187 
1188 	return(grep_bar);
1189 }
1190 
update_grep_bar()1191 void update_grep_bar()
1192 {
1193 
1194 	LOG(LOG_DEBUG, "IN : update_grep_bar()");
1195 
1196 	gtk_widget_hide(grep_bar);
1197 	create_grep_bar();
1198 	gtk_widget_show_all(grep_bar);
1199 
1200 	LOG(LOG_DEBUG, "OUT : update_grep_bar()");
1201 
1202 }
1203