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