Fix a Gtk warning when checking path input in the log viewer.
[anjuta-git-plugin.git] / plugins / search / search-replace_backend.c
blob93c1db4b5bc9859967e49f786c3296612ac052c2
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
3 /*
4 ** search-replace_backend.c: Generic Search and Replace
5 ** Author: Biswapesh Chattopadhyay
6 */
8 /*
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Library General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <ctype.h>
33 #include <string.h>
34 #include <dirent.h>
35 #include <fnmatch.h>
36 #include <fcntl.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
40 #include <gnome.h>
41 #include <glade/glade.h>
42 #include <libgnomevfs/gnome-vfs.h>
44 #include <libanjuta/anjuta-utils.h>
45 #include <libanjuta/anjuta-shell.h>
46 #include <libanjuta/anjuta-plugin.h>
47 #include <libanjuta/anjuta-debug.h>
48 #include <libanjuta/anjuta-encodings.h>
49 #include <libanjuta/anjuta-convert.h>
50 #include <libanjuta/interfaces/ianjuta-editor.h>
51 #include <libanjuta/interfaces/ianjuta-document.h>
52 #include <libanjuta/interfaces/ianjuta-file.h>
53 #include <libanjuta/interfaces/ianjuta-editor-selection.h>
54 #include <libanjuta/interfaces/ianjuta-project-manager.h>
57 #define GTK
58 #undef PLAT_GTK
59 #define PLAT_GTK 1
60 #include "Scintilla.h"
61 #include "SciLexer.h"
62 #include "ScintillaWidget.h"
65 #include "search-replace_backend.h"
66 #include "tm_tagmanager.h"
68 /* Information about a matched substring */
69 typedef struct _MatchSubStr
71 gint start;
72 gint len;
73 } MatchSubStr;
75 static SearchReplace *sr = NULL;
77 void clear_search_replace_instance(void);
79 static void match_substr_free(MatchSubStr *ms)
81 g_free(ms);
85 void
86 match_info_free (MatchInfo *mi)
88 if (mi)
90 if (mi->subs)
92 GList *tmp;
93 for (tmp = mi->subs; tmp; tmp = g_list_next(tmp))
94 match_substr_free((MatchSubStr *) tmp->data);
95 g_list_free(mi->subs);
97 g_free(mi);
102 void
103 file_buffer_free (FileBuffer *fb)
105 if (fb)
107 if (fb->path)
108 g_free(fb->path);
109 if (fb->uri)
110 g_free (fb->uri);
111 if (fb->buf)
112 g_free(fb->buf);
113 if (fb->lines)
114 g_list_free(fb->lines);
115 g_free(fb);
119 /* Create a file buffer structure from a TextEditor structure */
120 FileBuffer *
121 file_buffer_new_from_te (IAnjutaEditor *te)
123 FileBuffer *fb;
124 GFile* file;
125 gchar* path;
127 g_return_val_if_fail(te, NULL);
128 fb = g_new0(FileBuffer, 1);
129 fb->type = FB_EDITOR;
130 fb->te = te;
132 file = ianjuta_file_get_file(IANJUTA_FILE(te), NULL);
133 path = g_file_get_path (file);
134 if (path)
136 fb->path = tm_get_real_path(path);
137 g_free (path);
139 fb->uri = g_file_get_uri (file);
140 fb->len = ianjuta_editor_get_length(te, NULL);
141 fb->buf = ianjuta_editor_get_text_all (fb->te, NULL);
142 fb->pos = ianjuta_editor_get_offset(fb->te, NULL);
143 fb->line = ianjuta_editor_get_lineno(fb->te, NULL);
145 g_object_unref (file);
147 return fb;
150 /* Only use the first 500 chars for validating (yes, I feel lucky...) */
151 #define MAX_VALIDATE 500
153 FileBuffer *
154 file_buffer_new_from_path (const char *path, const char *buf, int len, int pos)
156 FileBuffer *fb;
157 IAnjutaEditor *te;
158 IAnjutaDocument* doc;
159 char *real_path;
160 GFile* file;
161 char *uri;
162 int i;
163 int lineno;
165 g_return_val_if_fail(path, NULL);
166 real_path = tm_get_real_path(path);
168 /* There might be an already open TextEditor with this path */
169 file = g_file_new_for_path (real_path);
170 uri = g_file_get_uri (file);
171 doc = ianjuta_document_manager_find_document_with_file (sr->docman,
172 file, NULL);
173 g_object_unref (file);
175 if (doc && IANJUTA_IS_EDITOR (doc))
177 te = IANJUTA_EDITOR (doc);
178 g_free(real_path);
179 return file_buffer_new_from_te(te);
181 fb = g_new0(FileBuffer, 1);
182 fb->type = FB_FILE;
183 fb->path = real_path;
184 fb->uri = uri;
185 fb->name = strrchr(path, '/');
186 if (fb->name)
187 ++ fb->name;
188 else
189 fb->name = fb->path;
190 if (buf && len > 0)
192 fb->buf = g_new(char, len + 1);
193 memcpy(fb->buf, buf, len);
194 fb->buf[len] = '\0';
195 fb->len = len;
197 else
199 struct stat s;
201 if ((0 == stat(fb->path, &s)) && (S_ISREG(s.st_mode)))
203 if ((fb->len = s.st_size) < 0) return NULL;
204 fb->buf = g_new(char, s.st_size + 1);
206 int total_bytes = 0, bytes_read, fd;
207 if (0 > (fd = open(fb->path, O_RDONLY)))
209 perror(fb->path);
210 file_buffer_free(fb);
211 return NULL;
213 while (total_bytes < s.st_size)
215 if (0 > (bytes_read = read(fd, fb->buf + total_bytes
216 , s.st_size - total_bytes)))
218 perror(fb->path);
219 close(fd);
220 file_buffer_free(fb);
221 return NULL;
223 total_bytes += bytes_read;
225 close(fd);
226 fb->buf[fb->len] = '\0';
230 if (!g_utf8_validate (fb->buf, MIN(MAX_VALIDATE, fb->len), NULL))
232 const AnjutaEncoding *encoding_used = NULL;
233 gchar* converted_text;
234 guint converted_len;
235 converted_text = anjuta_convert_to_utf8 (fb->buf,
236 fb->len,
237 &encoding_used,
238 &converted_len,
239 NULL);
240 if (converted_text == NULL)
242 /* Last change, let's try 8859-15 */
243 encoding_used =
244 anjuta_encoding_get_from_charset("ISO-8859-15");
246 converted_text = anjuta_convert_to_utf8 (fb->buf,
247 fb->len,
248 &encoding_used,
249 &converted_len,
250 NULL);
252 if (converted_text == NULL)
254 /* Give up */
255 file_buffer_free(fb);
256 return NULL;
258 else
260 g_free (fb->buf);
261 fb->buf = converted_text;
262 fb->len = converted_len;
266 if (pos <= 0 || pos > fb->len)
268 fb->pos = 0;
269 fb->line = 0;
271 else
273 fb->pos = pos;
274 fb->line = 0;
276 /* First line starts at column 0 */
277 fb->lines = g_list_prepend(fb->lines, GINT_TO_POINTER(0));
278 lineno = 0;
279 for (i=0; i < fb->len; ++i)
281 if ('\n' == fb->buf[i] && '\0' != fb->buf[i+1])
283 fb->lines = g_list_prepend(fb->lines, GINT_TO_POINTER(i + 1));
284 if (0 == fb->line && fb->pos > i)
285 fb->line = lineno;
286 ++ lineno;
289 fb->lines = g_list_reverse(fb->lines);
290 return fb;
293 static long
294 file_buffer_line_from_pos(FileBuffer *fb, int pos)
296 GList *tmp;
297 int lineno = -1;
298 g_return_val_if_fail(fb && pos >= 0, 1);
299 if (FB_FILE == fb->type)
301 for (tmp = fb->lines; tmp; tmp = g_list_next(tmp))
303 if (pos < GPOINTER_TO_INT(tmp->data))
304 return lineno;
305 ++ lineno;
307 return lineno;
309 else if (FB_EDITOR == fb->type)
311 IAnjutaIterable *position;
312 position = ianjuta_editor_get_position_from_offset (fb->te, pos, NULL);
313 lineno = ianjuta_editor_get_line_from_position (fb->te, position, NULL);
314 g_object_unref (position);
315 return lineno;
317 else
318 return -1;
321 gchar *
322 file_match_line_from_pos(FileBuffer *fb, int pos)
324 gint length=1;
325 gint i;
326 g_return_val_if_fail(fb && pos >= 0, NULL);
328 for (i= pos+1; ((fb->buf[i] != '\n') && (fb->buf[i] != '\0')); i++, length++);
329 for (i= pos-1; (fb->buf[i] != '\n') && (i >= 0); i--, length++);
331 return g_strndup (fb->buf + i + 1, length);
334 /* Generate a list of files to search in. Call with start = TRUE and
335 ** top_dir = sf->top_dir. This is used when the search range is specified as
336 SR_FILES */
337 static GList *
338 create_search_files_list(SearchFiles *sf, const char *top_dir)
340 TMFileEntry *entry;
341 GList *files;
343 g_return_val_if_fail(sf && top_dir, NULL);
344 entry = tm_file_entry_new(top_dir, NULL, sf->recurse, sf->match_files
345 , sf->ignore_files, sf->match_dirs, sf->ignore_dirs
346 , sf->ignore_hidden_files, sf->ignore_hidden_dirs);
347 if (!entry)
348 return NULL;
349 files = tm_file_entry_list(entry, NULL);
350 tm_file_entry_free(entry);
351 return files;
354 /* Get a list of all project files */
355 static GList *
356 get_project_file_list(void)
358 GList* list = NULL;
359 GList *files = NULL;
360 gchar *project_root_uri = NULL;
362 anjuta_shell_get (ANJUTA_PLUGIN(sr->docman)->shell,
363 "project_root_uri", G_TYPE_STRING,
364 &project_root_uri, NULL);
366 if (project_root_uri)
368 IAnjutaProjectManager* prjman;
369 prjman = anjuta_shell_get_interface(ANJUTA_PLUGIN(sr->docman)->shell,
370 IAnjutaProjectManager , NULL);
372 list = ianjuta_project_manager_get_elements (prjman,
373 IANJUTA_PROJECT_MANAGER_SOURCE,
374 NULL);
375 if (list)
377 const gchar *uri;
378 GList *node;
379 node = list;
381 while (node)
383 gchar *file_path;
385 uri = (const gchar *)node->data;
386 file_path = gnome_vfs_get_local_path_from_uri (uri);
387 if (file_path)
388 files = g_list_prepend (files, file_path);
389 node = g_list_next (node);
391 files = g_list_reverse (files);
392 g_list_free(list);
395 g_free (project_root_uri);
396 return files;
400 static gboolean
401 isawordchar (gunichar c)
403 return (g_unichar_isalnum(c) || '_' == c);
406 static gboolean
407 extra_match (FileBuffer *fb, gchar* begin, gchar* end, SearchExpression *s)
409 gunichar b, e;
411 b = g_utf8_get_char (g_utf8_prev_char (begin));
412 e = g_utf8_get_char (end);
414 if (s->whole_line)
415 if ((fb->pos == 0 || b == '\n' || b == '\r') &&
416 (e == '\0' || e == '\n' || e == '\r'))
417 return TRUE;
418 else
419 return FALSE;
420 else if (s->whole_word)
421 if ((fb->pos ==0 || !isawordchar(b)) &&
422 (e=='\0' || !isawordchar(e)))
423 return TRUE;
424 else
425 return FALSE;
426 else if (s->word_start)
427 if (fb->pos ==0 || !isawordchar(b))
428 return TRUE;
429 else
430 return FALSE;
431 else
432 return TRUE;
435 /* Returns the next match in the passed buffer. The search expression should
436 be pre-compiled. The returned pointer should be freed with match_info_free()
437 when no longer required. */
438 MatchInfo *
439 get_next_match(FileBuffer *fb, SearchDirection direction, SearchExpression *s)
441 MatchInfo *mi = NULL;
443 g_return_val_if_fail(fb && s, NULL);
445 if (s->regex)
447 GMatchInfo* match_info;
448 if (s->regex_info == NULL)
450 GError* error = NULL;
451 GRegexCompileFlags compile_flags = 0;
452 GRegexMatchFlags match_flags = 0;
454 match_flags |= G_REGEX_MATCH_NOTEMPTY;
455 if (s->ignore_case)
457 compile_flags |= G_REGEX_CASELESS;
459 if (!s->greedy)
461 compile_flags |= G_REGEX_UNGREEDY;
463 s->regex_info = g_regex_new (s->search_str, compile_flags,
464 match_flags, &error);
465 if (error)
467 anjuta_util_dialog_error (NULL, error->message);
468 g_error_free(error);
469 s->regex_info = NULL;
470 return NULL;
474 g_regex_match_full (s->regex_info, fb->buf, fb->len,
475 g_utf8_offset_to_pointer (fb->buf, fb->pos) - fb->buf,
476 G_REGEX_MATCH_NOTEMPTY, &match_info, NULL);
478 if (g_match_info_matches (match_info))
480 gint start;
481 gint end;
482 int i;
483 mi = g_new0(MatchInfo, 1);
484 if (g_match_info_fetch_pos (match_info, 0, &start, &end))
486 DEBUG_PRINT ("Regex: %d %d", start, end);
487 mi->pos = g_utf8_pointer_to_offset (fb->buf, fb->buf + start);
488 mi->len = g_utf8_pointer_to_offset (fb->buf, fb->buf + end) - mi->pos;
489 mi->line = file_buffer_line_from_pos(fb, mi->pos);
491 for (i = 1; i < g_match_info_get_match_count(match_info); i++) /* Captured subexpressions */
493 MatchSubStr *ms;
494 ms = g_new0(MatchSubStr, 1);
495 if (g_match_info_fetch_pos (match_info, i, &start, &end))
497 ms->start = g_utf8_pointer_to_offset (fb->buf, fb->buf + start);
498 ms->len = g_utf8_pointer_to_offset (fb->buf, fb->buf + end) - ms->start;
500 mi->subs = g_list_prepend(mi->subs, ms);
502 mi->subs = g_list_reverse(mi->subs);
503 fb->pos = g_utf8_pointer_to_offset (fb->buf, fb->buf + end);
506 else
508 /* Simple string search - this needs to be performance-tuned */
509 gboolean found;
510 gint match_len;
512 match_len = strlen (s->search_str);
513 if (match_len == 0)
514 return NULL;
516 found = FALSE;
517 if (SD_BACKWARD == direction)
519 /* Backward matching. */
520 if (s->ignore_case)
522 gchar* current = g_utf8_offset_to_pointer (fb->buf, fb->pos);
523 gint len = g_utf8_strlen (s->search_str, -1);
524 gchar* search_caseless = g_utf8_casefold (s->search_str, len);
525 for (; fb->pos >= len; --fb->pos)
527 gchar* current_caseless = g_utf8_casefold (current, len);
528 if (g_utf8_collate (current_caseless, search_caseless) == 0 &&
529 extra_match (fb, current, current + strlen (search_caseless),
532 found = TRUE;
533 g_free (current_caseless);
534 break;
536 else
537 current = g_utf8_prev_char (current);
539 g_free (search_caseless);
541 else
543 gchar* current = g_utf8_offset_to_pointer (fb->buf, fb->pos);
544 gint len = g_utf8_strlen (s->search_str, -1);
545 gchar* search_key = g_utf8_collate_key (s->search_str, len);
546 for (; fb->pos >= len; --fb->pos)
548 gchar* current_key = g_utf8_collate_key (current, len);
549 if (g_str_equal (current_key, search_key) &&
550 extra_match (fb, current, current + strlen (s->search_str),
553 found = TRUE;
554 g_free (current_key);
555 break;
557 else
558 current = g_utf8_prev_char (current);
560 g_free (search_key);
563 else
565 /* Forward match */
566 if (s->ignore_case)
568 gchar* current = g_utf8_offset_to_pointer (fb->buf, fb->pos);
569 gint len = g_utf8_strlen (s->search_str, -1);
570 gchar* search_caseless = g_utf8_casefold (s->search_str, len);
571 gint buf_len = g_utf8_strlen (fb->buf, fb->len);
572 for (; fb->pos < buf_len; ++fb->pos)
574 gchar* current_caseless = g_utf8_casefold (current, len);
575 if (g_utf8_collate (current_caseless, search_caseless) == 0 &&
576 extra_match (fb, current, current + strlen (search_caseless),
579 found = TRUE;
580 g_free (current_caseless);
581 break;
583 else
584 current = g_utf8_next_char (current);
586 g_free (search_caseless);
588 else
590 gchar* current = g_utf8_offset_to_pointer (fb->buf, fb->pos);
591 gint len = g_utf8_strlen (s->search_str, -1);
592 gint buf_len = g_utf8_strlen (fb->buf, fb->len);
593 gchar* search_key = g_utf8_collate_key (s->search_str, len);
594 for (; fb->pos < buf_len; ++fb->pos)
596 gchar* current_key = g_utf8_collate_key (current, len);
597 if (g_str_equal (current_key, search_key) &&
598 extra_match (fb, current, current + strlen (s->search_str),
601 found = TRUE;
602 g_free (current_key);
603 break;
605 else
606 current = g_utf8_next_char (current);
608 g_free (search_key);
611 if (found)
613 mi = g_new0 (MatchInfo, 1); //better to abort than silently fail to report match ?
614 // mi = g_try_new0 (MatchInfo, 1);
615 // if (mi)
616 // {
617 mi->pos = fb->pos;
618 mi->len = match_len;
619 mi->line = file_buffer_line_from_pos (fb, fb->pos);
620 // }
621 // else
622 // WARN USER ABOUT MEMORY ERROR
623 if (direction == SD_BACKWARD)
624 fb->pos -= match_len;
625 else
626 fb->pos += match_len;
629 return mi;
632 /* Create list of search entries */
633 GList *
634 create_search_entries (Search *s)
636 GList *entries = NULL;
637 GList *tmp;
638 GList *editors;
639 IAnjutaDocument *doc;
640 SearchEntry *se;
641 gint tmp_pos;
642 gint selstart;
644 switch (s->range.type)
646 case SR_BUFFER:
647 doc = ianjuta_document_manager_get_current_document (sr->docman, NULL);
648 if (doc && IANJUTA_IS_EDITOR (doc))
650 se = g_new0 (SearchEntry, 1);
651 se->type = SE_BUFFER;
652 se->te = IANJUTA_EDITOR (doc);
653 se->direction = s->range.direction;
654 if (SD_BEGINNING == se->direction)
656 se->start_pos = 0;
657 se->end_pos = -1;
658 se->direction = SD_FORWARD;
660 else
662 IAnjutaIterable *start;
663 /* forward-search from after beginning of selection, if any
664 backwards-search from before beginning of selection, if any
665 treat -ve positions except -1 as high +ve */
666 start = ianjuta_editor_selection_get_start
667 (IANJUTA_EDITOR_SELECTION (se->te), NULL);
668 if (start)
670 selstart =
671 ianjuta_iterable_get_position (start, NULL);
672 if (se->direction == SD_BACKWARD)
674 se->start_pos = (selstart != 0) ?
675 selstart - 1 : selstart;
677 else
679 se->start_pos =
680 (selstart != -2 &&
681 selstart < ianjuta_editor_get_length (IANJUTA_EDITOR (se->te), NULL)) ?
682 selstart + 1 : selstart;
684 g_object_unref (start);
686 else
688 se->start_pos = ianjuta_editor_get_offset (se->te, NULL);
690 se->end_pos = -1; /* not actually used when backward searching */
692 entries = g_list_prepend(entries, se);
694 break;
695 case SR_SELECTION:
696 case SR_BLOCK:
697 case SR_FUNCTION:
698 doc = ianjuta_document_manager_get_current_document (sr->docman, NULL);
699 if (doc && IANJUTA_IS_EDITOR (doc))
701 gint selend;
703 se = g_new0 (SearchEntry, 1);
704 se->type = SE_BUFFER;
705 se->te = IANJUTA_EDITOR (doc);
706 se->direction = s->range.direction;
707 if (se->direction == SD_BEGINNING)
708 se->direction = SD_FORWARD;
710 if (s->range.type == SR_SELECTION)
712 selstart = selend = 0; /* warning prevention only */
714 else
716 IAnjutaIterable* end =
717 ianjuta_editor_selection_get_end (IANJUTA_EDITOR_SELECTION (se->te), NULL);
718 if (end)
720 selstart = selend = ianjuta_iterable_get_position (end, NULL);
721 g_object_unref (end);
723 else
725 selstart = selend = 0; /* warning prevention only */
726 g_assert ("No selection end position");
730 if (s->range.type == SR_BLOCK)
731 ianjuta_editor_selection_select_block(IANJUTA_EDITOR_SELECTION (se->te), NULL);
732 if (s->range.type == SR_FUNCTION)
733 ianjuta_editor_selection_select_function(IANJUTA_EDITOR_SELECTION (se->te), NULL);
735 IAnjutaIterable *start, *end;
736 start = ianjuta_editor_selection_get_start (IANJUTA_EDITOR_SELECTION (se->te), NULL);
737 end = ianjuta_editor_selection_get_end(IANJUTA_EDITOR_SELECTION (se->te), NULL);
738 se->start_pos = ianjuta_iterable_get_position (start, NULL);
739 se->end_pos = ianjuta_iterable_get_position (end, NULL);
740 g_object_unref (start);
741 g_object_unref (end);
743 if (se->direction == SD_BACKWARD)
745 tmp_pos = se->start_pos;
746 se->start_pos = se->end_pos;
747 se->end_pos = tmp_pos;
749 entries = g_list_prepend (entries, se);
750 if (s->range.type != SR_SELECTION)
752 IAnjutaIterable *start, *end;
753 start = ianjuta_editor_get_position_from_offset (se->te, selstart, NULL);
754 end = ianjuta_editor_get_position_from_offset (se->te, selend, NULL);
755 ianjuta_editor_selection_set(IANJUTA_EDITOR_SELECTION (se->te),
756 start, end, NULL);
757 g_object_unref (start);
758 g_object_unref (end);
761 break;
762 case SR_OPEN_BUFFERS:
763 editors = ianjuta_document_manager_get_doc_widgets (sr->docman, NULL);
764 for (tmp = editors; tmp; tmp = g_list_next(tmp))
766 if (IANJUTA_IS_EDITOR (tmp->data))
768 se = g_new0 (SearchEntry, 1);
769 se->type = SE_BUFFER;
770 se->te = IANJUTA_EDITOR (tmp->data);
771 se->direction = SD_FORWARD;
772 se->start_pos = 0;
773 se->end_pos = -1;
774 entries = g_list_prepend(entries, se);
777 entries = g_list_reverse(entries);
778 g_list_free (editors);
779 break;
780 case SR_FILES:
781 case SR_PROJECT:
783 GList *files = NULL;
784 gchar *dir = NULL;
785 gchar *dir_uri = NULL;
787 anjuta_shell_get (ANJUTA_PLUGIN(sr->docman)->shell,
788 "project_root_uri", G_TYPE_STRING,
789 &dir_uri, NULL);
790 // FIXME : Replace Standard UNIX IO functions by gnome-vfs
791 if (dir_uri)
792 dir = gnome_vfs_get_local_path_from_uri(dir_uri);
794 if (!dir)
796 if (SR_PROJECT == s->range.type)
797 s->range.type = SR_FILES;
798 dir = g_get_current_dir();
801 if (SR_FILES == s->range.type)
802 files = create_search_files_list(&(s->range.files), dir);
803 else /* if (SR_PROJECT == s->range.type) */
804 files = get_project_file_list();
806 if (files)
808 for (tmp = files; tmp; tmp = g_list_next(tmp))
810 se = g_new0(SearchEntry, 1);
811 se->type = SE_FILE;
812 se->path = (char *) tmp->data;
813 se->direction = SD_FORWARD;
814 se->type = SE_FILE;
815 se->start_pos = 0;
816 se->end_pos = -1;
817 entries = g_list_prepend(entries, se);
819 g_list_free(files);
820 entries = g_list_reverse(entries);
822 g_free(dir);
823 g_free(dir_uri);
824 break;
827 return entries;
830 gchar *
831 regex_backref (MatchInfo *mi, FileBuffer *fb)
833 #define REGX_BUFSIZE 1024
834 gint i, j, k;
835 gint nb_backref;
836 gint i_backref;
837 gint plen;
838 gint start, len;
839 gint backref[10] [2]; /* backref [0][2] unused */
840 gchar buf [REGX_BUFSIZE + 4]; /* usable space + word-sized space for trailing 0 */
841 GList *tmp;
843 i = 1;
844 /* Extract back references */
845 tmp = mi->subs;
846 while (tmp && i < 10)
848 backref[i] [0] = ((MatchSubStr*)tmp->data)->start;
849 backref[i] [1] = ((MatchSubStr*)tmp->data)->len;
850 tmp= g_list_next(tmp);
851 i++;
853 nb_backref = i;
854 plen = strlen (sr->replace.repl_str);
855 for(i=0, j=0; i < plen && j < REGX_BUFSIZE; i++)
857 if (sr->replace.repl_str[i] == '\\')
859 i++;
860 if (sr->replace.repl_str[i] > '0' && sr->replace.repl_str[i] <= '9')
862 i_backref = sr->replace.repl_str[i] - '0';
863 if (i_backref < nb_backref)
865 start = backref[i_backref] [0];
866 len = backref[i_backref] [1];
867 for (k=0; k < len && j < REGX_BUFSIZE; k++)
868 buf[j++] = fb->buf[start + k];
872 else
873 buf[j++] = sr->replace.repl_str[i];
875 buf[j] = '\0';
877 return g_strdup (buf);
880 #define FREE_FN(fn, v) if (v) { fn(v); v = NULL; }
882 void
883 clear_search_replace_instance(void)
885 g_free (sr->search.expr.search_str);
886 if (sr->search.expr.regex_info)
888 g_regex_unref (sr->search.expr.regex_info);
889 sr->search.expr.regex_info = NULL;
891 if (SR_FILES == sr->search.range.type)
893 FREE_FN(anjuta_util_glist_strings_free, sr->search.range.files.match_files);
894 FREE_FN(anjuta_util_glist_strings_free, sr->search.range.files.ignore_files);
895 FREE_FN(anjuta_util_glist_strings_free, sr->search.range.files.match_dirs);
896 FREE_FN(anjuta_util_glist_strings_free, sr->search.range.files.ignore_dirs);
898 FREE_FN(anjuta_util_glist_strings_free, sr->search.expr_history);
899 g_free (sr->replace.repl_str);
900 FREE_FN(anjuta_util_glist_strings_free, sr->replace.expr_history);
903 SearchReplace *
904 create_search_replace_instance(IAnjutaDocumentManager *docman)
906 /* Create a new SearchReplace instance */
907 if (NULL == sr)
909 sr = g_new0(SearchReplace, 1);
910 sr->search.expr.regex_info = NULL;
912 else
913 clear_search_replace_instance ();
914 if (docman)
915 sr->docman = docman;
916 return sr;