~ubuntu-branches/ubuntu/natty/bluefish/natty-proposed

« back to all changes in this revision

Viewing changes to src/snr2.c

  • Committer: Bazaar Package Importer
  • Author(s): Davide Puricelli (evo)
  • Date: 2005-04-23 17:05:18 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 warty)
  • Revision ID: james.westby@ubuntu.com-20050423170518-pb8zi3vg32cm6g04
Tags: 1.0-1
* Acknowledge NMU, thanks Leo; closes: #291222.
* Updated debian/ files, thanks Daniel Leidert. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* Bluefish HTML Editor
2
2
 * snr2.c - rewrite of search 'n replace functions
3
3
 *
4
 
 * Copyright (C) 2000 Olivier Sessink
 
4
 * Copyright (C) 2000-2004 Olivier Sessink
5
5
 *
6
6
 * This program is free software; you can redistribute it and/or modify
7
7
 * it under the terms of the GNU General Public License as published by
20
20
/*
21
21
 * THIS IS THE BACKEND FLOW DIAGRAM
22
22
 *
23
 
 *                         snr2_run
24
 
 *         ________________/ | \  \___________________________
25
 
 *        /        |         |  \                   \  \      \
26
 
 *       /         |         |  replace_prompt_all  |   \      \
27
 
 *      /          |         |         /           /     \      \
28
 
 *   search_all    |   _____replace_prompt_doc    /       \    replace_all
29
 
 *     \           |  /          /               /         \     /
30
 
 *      \   doc_show_result     /  replace_doc_once   replace_doc_multiple
31
 
 *       \                   __/                  \         /
32
 
 *     search_doc           /                   replace_backend
33
 
 *           \             / ___________________________/
34
 
 *            \           / /
35
 
 *             search_backend
 
23
 *                              snr2_run
 
24
 *              ________________/ | \  \___________________________
 
25
 *             /      / |         |  \                   \  \      \
 
26
 *  search_bookmark  |  |         |  replace_prompt_all  |   \      \
 
27
 *     |            /   |         |         /           /     \      \
 
28
 *     |   search_all   |   _____replace_prompt_doc    /       \    replace_all
 
29
 *     |     |          |  /          /               /         \     /
 
30
 *     |     \   doc_show_result     /  replace_doc_once   replace_doc_multiple
 
31
 *     |      \                   __/                  \         /
 
32
 *     |  search_doc             /                   replace_backend
 
33
 *      \________ \             /  ___________________________/
 
34
 *               \ \           /  /
 
35
 *                 search_backend
36
36
 */
37
37
/*****************************************************/
38
 
#include "default_include.h"
39
 
 
 
38
/* #define DEBUG */
 
39
 
 
40
#include <gtk/gtk.h>
 
41
 
 
42
#include "config.h"
 
43
 
 
44
#ifdef HAVE_STRINGS_H
 
45
#include <strings.h>
 
46
#endif /* HAVE_STRINGS_H */
40
47
#include <stdio.h>
41
48
#include <string.h>
42
49
#include <sys/types.h>  /* _before_ regex.h for freeBSD */
43
50
#include <regex.h>                              /* regcomp() */
 
51
#include <pcre.h>       /* pcre_compile */
 
52
#include <gdk/gdkkeysyms.h> /* GDK_Return */
44
53
 
45
54
#include "bluefish.h"
 
55
#include "bookmark.h" /* bmark_add_extern() */
46
56
#include "bf_lib.h"
47
 
 
48
 
#ifdef UNDO2
49
 
#include "undo2.h" /* doc_unre_new_group */
50
 
#endif
51
 
 
 
57
#include "undo_redo.h" /* doc_unre_new_group */
52
58
#include "document.h"                   /* doc_replace_text() */
53
 
#include "interface.h"                  /* g */
 
59
#include "gui.h" /* switch_to_document_by_pointer() */
54
60
#include "gtk_easy.h"         /* a lot of GUI functions */
55
61
#include "snr2.h"
56
 
 
57
 
typedef enum { string, upcase, lowcase }replacetypes;
58
 
 
59
 
typedef struct {
60
 
        /* span of characters */
61
 
        gint start;
62
 
        gint end;
63
 
 
64
 
        /* span of byte-data in buffer */
65
 
        gint bstart;
66
 
        gint bend;
67
 
        
68
 
        /* these data are only used (and alloc'ed) if want_submatches is set in the search backend,
69
 
        they should be freed by the calling function! */
70
 
        regmatch_t *pmatch;
71
 
        gint nmatch;
72
 
} Tsearch_result;
73
 
 
74
 
/* Note:
75
 
    If Gtk's multibyte text support was enabled, a byte-offset
76
 
    of a string can not be used as a character-offset of GtkText.
77
 
    The member "start" and "end" are character-offset.
78
 
    The member "bstart" and "bend" are byte-offset in the source
79
 
    buffer.
80
 
    These values are set in search_backend().
81
 
    In single-byte text mode,
82
 
        start == bstart, end == bend .
83
 
 
84
 
    iwasa
85
 
*/
86
 
 
 
62
#include "highlight.h" /* doc_highlight_full() */
 
63
#include "stringlist.h" /* add_to_history_stringlist */
 
64
 
 
65
/* Updates, May 2003, by Ruben Dorta */
 
66
 
 
67
typedef enum { string, uppercase, lowercase } Treplace_types;
 
68
typedef enum { match_normal, match_posix, match_perl } Tmatch_types;
 
69
typedef enum { beginning, cursor, selection, opened_files } Tplace_types;
87
70
 
88
71
typedef struct {
89
72
        gint start;
92
75
} Tsearch_all_result;
93
76
 
94
77
typedef struct {
 
78
        Tbfwin *bfwin;
95
79
        Tdocument *doc;
96
80
        Tsearch_result result;
97
 
        gchar *pattern;
98
 
        gint region_from_beginning;
99
 
        gint region_from_cursor;
100
 
        gint region_selection;
101
 
        gint region_all_open_files;
102
 
        gint is_regex;
103
 
        gint is_case_sens;
 
81
        gint replace;
 
82
        gchar *search_pattern;
 
83
        gchar *replace_pattern;
 
84
        gint unescape;
104
85
        gint overlapping_search;
105
 
        gint replace;
106
 
        gchar *replace_string;
107
 
        gint prompt_before_replacing;
 
86
        gint prompt_before_replace;
 
87
        gint is_case_sens;
108
88
        gint replace_once;
109
 
        gint replacetype_string;
110
 
        gint replacetype_upcase;
111
 
        gint replacetype_lowcase;
 
89
        gint bookmark_results;
 
90
        Treplace_types replacetype_option;
 
91
        Tmatch_types matchtype_option;
 
92
        Tplace_types placetype_option;
112
93
} Tlast_snr2;
113
94
 
114
95
typedef struct {
 
96
        gint replace;
 
97
        Tbfwin *bfwin;
115
98
        GtkWidget *window;
116
 
        GtkWidget *pattern;
117
 
        GtkWidget *region_from_beginning;
118
 
        GtkWidget *region_from_cursor;
119
 
        GtkWidget *region_selection;
120
 
        GtkWidget *region_all_open_files;
121
 
        GtkWidget *is_regex;
 
99
        GtkWidget *search_combo;
 
100
        /*GtkWidget *search_entry;*/
 
101
        GtkWidget *search_label;
 
102
        /*GtkWidget *search_scrollbox;*/
 
103
        GtkWidget *replace_combo;
 
104
        /*GtkWidget *replace_entry;*/
 
105
        GtkWidget *replace_label;
 
106
        /*GtkWidget *replace_scrollbox;*/
 
107
        GtkWidget *subpat_help;
 
108
        GtkWidget *overlapping_search;
 
109
        GtkWidget *prompt_before_replace;
122
110
        GtkWidget *is_case_sens;
123
 
        GtkWidget *overlapping_search;
124
 
        gint replace;
125
 
        GtkWidget *replace_string;
126
 
        GtkWidget *prompt_before_replacing;
127
111
        GtkWidget *replace_once;
128
 
        GtkWidget *replacetype_string;
129
 
        GtkWidget *replacetype_upcase;
130
 
        GtkWidget *replacetype_lowcase;
 
112
        GtkWidget *unescape;
 
113
        GtkWidget *replacetype_option;
 
114
        GtkWidget *matchtype_option;
 
115
        GtkWidget *placetype_option;
 
116
        GtkWidget *bookmark_results;
131
117
} Tsnr2_win;
132
 
 
133
 
/***********************************************************/
134
 
 
135
 
static Tlast_snr2 last_snr2;
136
 
 
137
 
 
138
 
void snr2_run(void);
139
 
 
140
 
/***********************************************************/
141
 
 
142
 
static void reset_last_snr2(void) {
143
 
        if (last_snr2.pattern) {
144
 
                g_free(last_snr2.pattern);
145
 
        }
146
 
        if (last_snr2.replace_string) {
147
 
                g_free(last_snr2.replace_string);
148
 
        }
149
 
        memset(&last_snr2, 0, sizeof(Tlast_snr2));
150
 
        last_snr2.replacetype_string = 1;
151
 
}
152
 
 
153
 
/***********************************************************/
154
 
 
155
 
/* for multibyte-text support.
156
 
   wchar_len() returns -1 if it failed to convert.
157
 
        
158
 
        src_len -1 means the complete string
159
 
*/
160
 
gint wchar_len(gchar *src, gint src_len)
161
 
{
162
 
        gchar *tmpbuf;
163
 
        GdkWChar *tmpwbuf;
164
 
        gint convlen = -1;
165
 
 
166
 
        if (src_len == -1) {
167
 
                src_len = strlen(src);
168
 
        }
169
 
        if (src_len == 0) return 0;
170
 
 
171
 
        tmpbuf = g_strndup(src, src_len);
172
 
        if (tmpbuf) {
173
 
                tmpwbuf = g_new(GdkWChar, src_len);
174
 
                if (tmpwbuf) {
175
 
                        convlen = gdk_mbstowcs(tmpwbuf, tmpbuf, src_len);
176
 
                        g_free(tmpwbuf);
177
 
                }
178
 
                g_free(tmpbuf);
179
 
        }
180
 
        return convlen;
181
 
}
182
 
 
183
 
/***********************************************************/
184
 
 
185
 
Tsearch_result search_backend(gchar *pattern, gint is_regex, gint is_case_sens, gchar *buf, gboolean use_mb, gboolean want_submatches) {
186
 
 
 
118
#define LASTSNR2(var) ((Tlast_snr2 *)(var))
 
119
/***********************************************************/
 
120
 
 
121
void snr2_run(Tbfwin *bfwin,Tdocument *doc);
 
122
 
 
123
/***********************************************************/
 
124
 
 
125
void snr2_init(Tbfwin *bfwin) {
 
126
        Tlast_snr2 *lsnr2 = g_new0(Tlast_snr2,1);
 
127
        lsnr2->bfwin = bfwin;
 
128
        bfwin->snr2 = lsnr2;
 
129
}
 
130
 
 
131
static void reset_last_snr2(Tbfwin *bfwin) {
 
132
        if (LASTSNR2(bfwin->snr2)->search_pattern) {
 
133
                g_free(LASTSNR2(bfwin->snr2)->search_pattern);
 
134
        }
 
135
        if (LASTSNR2(bfwin->snr2)->replace_pattern) {
 
136
                g_free(LASTSNR2(bfwin->snr2)->replace_pattern);
 
137
        }
 
138
        memset(LASTSNR2(bfwin->snr2), 0, sizeof(Tlast_snr2));
 
139
}
 
140
 
 
141
/***********************************************************/
 
142
 
 
143
/**
 
144
 * search_backend:
 
145
 * @bfwin: #Tbfwin* 
 
146
 * @search_pattern: #gchar* to search pattern
 
147
 * @matchtype: see #Tmatch_types
 
148
 * @is_case_sens: If the search is case sensitive, #gint
 
149
 * @buf: #gchar* to the document buffer
 
150
 * @byte_offset: #guint where in the buffer the search should start, in bytes, not characters
 
151
 * @want_submatches: #gint
 
152
 * 
 
153
 * Performs an actual search in a supplied buffer (#gchar*, aka string).
 
154
 * NOTE: If want_submatches is set, tsearch_result->pmatch should be free`ed by the calling function!
 
155
 *
 
156
 * Return value: #Tsearch_result, contains both character and byte offsets, for wide-char-compatibility. Note values for start/end are set to -1 on error.
 
157
 **/
 
158
Tsearch_result search_backend(Tbfwin *bfwin, gchar *search_pattern, Tmatch_types matchtype, gint is_case_sens, gchar *buf, guint byte_offset, gboolean want_submatches) {
187
159
        Tsearch_result returnvalue;
188
160
        int (*f) ();
189
161
        gint buflen, patlen, match, i;
194
166
        returnvalue.bend = -1;
195
167
        returnvalue.pmatch = NULL;
196
168
        returnvalue.nmatch = 0;
197
 
        if ((!pattern) || (!buf)) {
198
 
                DEBUG_MSG("search_backend, pattern or buf is NULL\n");
 
169
        if ((!search_pattern) || (!buf)) {
 
170
                DEBUG_MSG("search_backend, search_pattern or buf is NULL\n");
199
171
                return returnvalue;
200
172
        }
201
 
        
202
 
        if (is_regex) {
 
173
        DEBUG_MSG("search_backend, starting for byte_offset=%u\n",byte_offset);
 
174
        if (matchtype == match_posix) {
203
175
                /* regex part start */
204
176
                regex_t reg_pat;
205
177
                regmatch_t *pmatch;
206
178
                gint nmatch, retval;
207
179
 
208
 
                if (is_case_sens) {
209
 
                        retval = regcomp(&reg_pat, pattern, REG_EXTENDED);
210
 
                } else {
211
 
                        retval = regcomp(&reg_pat, pattern, REG_EXTENDED | REG_ICASE);
212
 
                }
 
180
                retval = regcomp(&reg_pat, search_pattern, (is_case_sens ? REG_EXTENDED : REG_EXTENDED | REG_ICASE));
213
181
                DEBUG_MSG("search_backend, regcomp retval=%d\n", retval);
214
182
                if (retval != 0) {
215
183
#define ERRORSTR_SIZE 300
217
185
                        
218
186
                        regerror(retval,  &reg_pat, errorstr, ERRORSTR_SIZE);
219
187
                        errorstr2 = g_strconcat(_("Regular expression error: "), errorstr, NULL);
220
 
                        error_dialog(_("Bluefish warning: regular expression error"), errorstr2);
 
188
                        warning_dialog(bfwin->main_window,_("Search failed"), errorstr2);
221
189
                        g_free(errorstr2);
222
 
                        /* error compiling the pattern, returning the default result set,
 
190
                        /* error compiling the search_pattern, returning the default result set,
223
191
                        which is the 'nothing found' set */
224
192
                        return returnvalue;
225
193
                }
226
194
                nmatch = (want_submatches) ? reg_pat.re_nsub+1 : 1;
227
 
                DEBUG_MSG("search_backend, expr. contains %d sub patterns\n", reg_pat.re_nsub );
 
195
                DEBUG_MSG("search_backend, expr. contains %d sub search_patterns\n", reg_pat.re_nsub );
228
196
                pmatch = g_malloc(nmatch*sizeof(regmatch_t));
229
 
                retval = regexec(&reg_pat, buf, nmatch, pmatch, 0);
 
197
                retval = regexec(&reg_pat, buf+byte_offset, nmatch, pmatch, 0);
230
198
                DEBUG_MSG("search_backend, regexec retval=%d\n", retval);
231
199
                if (retval != 0) {
232
 
                        pmatch[0].rm_so = -1;
233
 
                        pmatch[0].rm_eo = -1;
 
200
                        returnvalue.bstart = -1;
 
201
                        returnvalue.bend = -1;
 
202
                } else {
 
203
                        returnvalue.bstart = pmatch[0].rm_so + byte_offset;
 
204
                        returnvalue.bend = pmatch[0].rm_eo + byte_offset;
234
205
                }
235
206
#ifdef DEBUG
236
207
                {       int i;
237
208
                        for (i=0;i<nmatch;i++) {
238
 
                                DEBUG_MSG("search_backend, sub pattern %d so=%d, eo=%d\n", i, pmatch[i].rm_so, pmatch[i].rm_eo);
 
209
                                DEBUG_MSG("search_backend, sub search_pattern %d so=%d, eo=%d\n", i, pmatch[i].rm_so, pmatch[i].rm_eo);
239
210
                        }
240
211
                }
241
212
#endif
242
 
                returnvalue.bstart = pmatch[0].rm_so;
243
 
                returnvalue.bend = pmatch[0].rm_eo;
244
213
                regfree(&reg_pat);
245
214
                if (want_submatches) {
246
215
                        returnvalue.pmatch = pmatch;
251
220
                        g_free(pmatch);
252
221
                }
253
222
                /* regex part end */
 
223
        } else if (matchtype == match_perl) {
 
224
                pcre *pcre_c;
 
225
                const char *err=NULL;
 
226
                int erroffset=0;
 
227
                int ovector[30];
 
228
                gint retval;
 
229
                pcre_c = pcre_compile(search_pattern, (is_case_sens ? PCRE_DOTALL|PCRE_MULTILINE : PCRE_DOTALL|PCRE_CASELESS|PCRE_MULTILINE),&err,&erroffset,NULL);
 
230
                if (err) {
 
231
                        gchar *errstring;
 
232
                        errstring = g_strdup_printf(_("Regular expression error: %s at offset %d"), err, erroffset);
 
233
                        warning_dialog(bfwin->main_window,_("Search failed"), errstring);
 
234
                        g_free(errstring);
 
235
                        return returnvalue;/* error compiling the search_pattern, returning the default result set,which is the 'nothing found' set */
 
236
                }
 
237
                retval = pcre_exec(pcre_c,NULL,buf+byte_offset,strlen(buf+byte_offset),0,0,ovector,30);
 
238
                if (retval > 0) {
 
239
                        returnvalue.bstart = ovector[0] + byte_offset;
 
240
                        returnvalue.bend = ovector[1] + byte_offset;
 
241
                } else {
 
242
                        returnvalue.bstart = -1;
 
243
                        returnvalue.bend = -1;
 
244
                }
 
245
                if (want_submatches) {
 
246
                        int nmatch,i;
 
247
                        regmatch_t *pmatch;
 
248
                        pcre_fullinfo(pcre_c, NULL, PCRE_INFO_CAPTURECOUNT, &nmatch);
 
249
                        DEBUG_MSG("search_backend, nmatch=%d, retval=%d\n", nmatch, retval);
 
250
                        pmatch = g_malloc((nmatch+1)*sizeof(regmatch_t));
 
251
                        for (i=0;i<=nmatch;i++) { /* nmatch==1 means 1 subsearch_pattern, so 2 search_patterns in total*/
 
252
                                pmatch[i].rm_so = ovector[i*2] + byte_offset;
 
253
                                pmatch[i].rm_eo = ovector[i*2+1] + byte_offset;
 
254
                        }
 
255
                        returnvalue.pmatch = pmatch;
 
256
                        returnvalue.nmatch = retval;
 
257
#ifdef DEBUG
 
258
                        {       int i;
 
259
                                for (i=0;i<returnvalue.nmatch;i++) {
 
260
                                        DEBUG_MSG("search_backend, sub search_pattern %d so=%d, eo=%d\n", i, returnvalue.pmatch[i].rm_so, returnvalue.pmatch[i].rm_eo);
 
261
                                }
 
262
                        }
 
263
#endif
 
264
                        /* if want_submatches is set, pmatch should be 
 
265
                        free`ed by the calling function! */
 
266
                }
 
267
                pcre_free(pcre_c);
254
268
        } else {
255
269
                /* non regex part start */
256
270
                if (!is_case_sens) {
259
273
                        f = strncmp;
260
274
                }
261
275
                buflen = strlen(buf);
262
 
                patlen = strlen(pattern);
 
276
                patlen = strlen(search_pattern);
263
277
                
264
 
                for (i = 0; i <= (buflen - patlen); i++) {
265
 
                        match = f(&buf[i], pattern, patlen);
 
278
                for (i = byte_offset; i <= (buflen - patlen); i++) {
 
279
                        match = f(&buf[i], search_pattern, patlen);
266
280
                        if (match == 0) {
267
281
                                returnvalue.bstart = i;
268
282
                                returnvalue.bend = i + patlen;
271
285
                }
272
286
                /* non regex part end */        
273
287
        }
274
 
 
275
 
        if (use_mb) {
 
288
        
 
289
        /* if we have a valid result, we now calculate the character offsets for this result */
 
290
        if (returnvalue.bstart >= 0 && returnvalue.bend >= 0) {
 
291
                /* utf8_offset_cache_reset(); */
276
292
                if (returnvalue.bstart >= 0) {
277
 
                        returnvalue.start = wchar_len(buf, returnvalue.bstart);
 
293
                        returnvalue.start = utf8_byteoffset_to_charsoffset_cached(buf, returnvalue.bstart);
278
294
                }
279
295
                if (returnvalue.bend >= 0) {
280
 
                        returnvalue.end = wchar_len(buf, returnvalue.bend);
 
296
                        returnvalue.end = utf8_byteoffset_to_charsoffset_cached(buf, returnvalue.bend);
281
297
                }
282
 
                if (returnvalue.start < 0 || returnvalue.end < 0) {
283
 
                        returnvalue.start = -1;
284
 
                        returnvalue.end = -1;
285
 
                        returnvalue.bstart = -1;
286
 
                        returnvalue.bend = -1;
 
298
                if (want_submatches) {
 
299
                        int i;
 
300
                        for (i=0;i<returnvalue.nmatch;i++) {
 
301
                                returnvalue.pmatch[i].rm_so = utf8_byteoffset_to_charsoffset_cached(buf, returnvalue.pmatch[i].rm_so);
 
302
                                returnvalue.pmatch[i].rm_eo = utf8_byteoffset_to_charsoffset_cached(buf, returnvalue.pmatch[i].rm_eo);
 
303
                        }
287
304
                }
288
305
        } else {
289
 
                returnvalue.start = returnvalue.bstart;
290
 
                returnvalue.end = returnvalue.bend;
 
306
                returnvalue.start = -1;
 
307
                returnvalue.end = -1;
 
308
                returnvalue.bstart = -1;
 
309
                returnvalue.bend = -1;
291
310
        }
292
 
        DEBUG_MSG("search_backend, returning result.start=%d, result.end=%d\n", returnvalue.start, returnvalue.end);
 
311
 
 
312
        DEBUG_MSG("search_backend, returning result.start=%d, result.end=%d, bstart=%d, bend=%d\n", returnvalue.start, returnvalue.end, returnvalue.bstart, returnvalue.bend);
293
313
        return returnvalue;
294
314
}
295
315
 
296
316
/*****************************************************/
297
317
 
298
 
Tsearch_result search_doc(Tdocument *document, gchar *pattern, gint is_regex, gint is_case_sens, gint startpos) {
299
 
        gchar *fulltext;
 
318
/**
 
319
 * search_doc:
 
320
 * @bfwin: #Tbfwin*
 
321
 * @document: a #Tdocument to search
 
322
 * @search_pattern: a #gchar* to the search pattern.
 
323
 * @matchtype: see #Tmatch_types
 
324
 * @is_case_sens: #gint
 
325
 * @startpos: #gint offset in document buffer
 
326
 *
 
327
 * Perform search by calling search_backend.
 
328
 * Updates last_snr2-values, but doesn't use them -- that is the callers duty.
 
329
 *
 
330
 * Return value: #Tsearch_result
 
331
 **/
 
332
Tsearch_result search_doc(Tbfwin *bfwin,Tdocument *document, gchar *search_pattern, Tmatch_types matchtype, gint is_case_sens, gint startpos, gboolean unescape) {
 
333
        gchar *fulltext, *realpat;
300
334
        Tsearch_result result;
301
335
        
302
336
        DEBUG_MSG("search_doc, started on document %p, startpos=%d\n", document, startpos);
303
 
        fulltext = gtk_editable_get_chars(GTK_EDITABLE(document->textbox), startpos, -1);
304
 
        DEBUG_MSG("search_doc, fulltext=%p, pattern=%p\n", fulltext, pattern);
305
 
        result = search_backend(pattern, is_regex, is_case_sens, fulltext, GTK_TEXT(document->textbox)->use_wchar, 0);
 
337
        utf8_offset_cache_reset();
 
338
        fulltext = doc_get_chars(document, startpos, -1);
 
339
        DEBUG_MSG("search_doc, fulltext=%p, search_pattern=%p\n", fulltext, search_pattern);
 
340
        if (unescape) {
 
341
                realpat = unescape_string(search_pattern, FALSE);
 
342
        } else {
 
343
                realpat = search_pattern;
 
344
        }
 
345
        result = search_backend(bfwin,realpat, matchtype, is_case_sens, fulltext, 0, FALSE);
 
346
        if (unescape) {
 
347
                g_free(realpat);
 
348
        }
306
349
        g_free(fulltext);
307
350
        if (result.end > 0) {
308
351
                DEBUG_MSG("search_doc, received a result (start=%d), adding startpos (%d) to it\n", result.start, startpos);
309
352
                result.start += startpos;
310
353
                result.end += startpos;
311
 
                last_snr2.result.start = result.start;
312
 
                last_snr2.result.end = result.end;
313
 
                last_snr2.doc = document;
 
354
                LASTSNR2(bfwin->snr2)->result.start = result.start;
 
355
                LASTSNR2(bfwin->snr2)->result.end = result.end;
 
356
                LASTSNR2(bfwin->snr2)->doc = document;
314
357
        } else {
315
 
                last_snr2.result.start = -1;
316
 
                last_snr2.result.end =  -1;
317
 
                last_snr2.doc = document;
 
358
                LASTSNR2(bfwin->snr2)->result.start = -1;
 
359
                LASTSNR2(bfwin->snr2)->result.end =  -1;
 
360
                LASTSNR2(bfwin->snr2)->doc = document;
318
361
        }
319
362
        DEBUG_MSG("search_doc, result.start=%d, result.end=%d\n", result.start, result.end);
320
363
        return result;
322
365
 
323
366
/*****************************************************/
324
367
 
 
368
/**
 
369
 * doc_show_result:
 
370
 * @document: a #Tdocument
 
371
 * @start: Selection start.
 
372
 * @end: Selection end.
 
373
 *
 
374
 * Focus a document and select the supplied range.
 
375
 *
 
376
 * Return value: void
 
377
 **/
325
378
void doc_show_result(Tdocument *document, gint start, gint end) {
326
 
        gint linenum;
327
 
        if (end > 0) {
328
 
                DEBUG_MSG("search_show_doc, start=%d, end=%d\n",start, end);
329
 
                if (document != main_v->current_document) {
330
 
                        switch_to_document_by_pointer(document);
331
 
                }
332
 
                linenum = position_to_linenum(end);
333
 
                go_to_line(linenum + 1, 0);
334
 
                gtk_editable_select_region(GTK_EDITABLE(document->textbox), start, end);
 
379
        DEBUG_MSG("doc_show_result, select from start=%d to end=%d\n",start, end);
 
380
        if (document != BFWIN(document->bfwin)->current_document) {
 
381
                switch_to_document_by_pointer(BFWIN(document->bfwin),document);
335
382
        }
 
383
        doc_select_region(document, start, end, TRUE);
336
384
}
337
385
 
338
386
/*****************************************************/
339
387
 
340
 
Tsearch_all_result search_all(gchar *pattern, gint is_regex, gint is_case_sens) {
 
388
/**
 
389
 * search_all:
 
390
 * @bfwin: #Tbfwin*
 
391
 * @search_pattern: #gchar to search pattern
 
392
 * @matchtype: see #Tmatch_types
 
393
 * is_case_sens: #gint set to 0 or 1.
 
394
 *
 
395
 * Perform a specified search, spanning all open documents.
 
396
 *
 
397
 * When called several times, the search continues from where it left off last time.
 
398
 * The current 'search-position' is stored in the internal last_snr2 structure.
 
399
 *
 
400
 * Return value: #Tsearch_all_result
 
401
 **/
 
402
Tsearch_all_result search_all(Tbfwin *bfwin,gchar *search_pattern, Tmatch_types matchtype, gint is_case_sens, gboolean unescape) {
341
403
        GList *tmplist;
342
404
        Tsearch_all_result result_all;
343
 
        Tsearch_result result;
344
405
 
345
406
        DEBUG_MSG("search_all, started\n");
346
407
        result_all.start = -1;
347
408
        result_all.end = -1;
348
409
        result_all.doc = NULL;
349
410
        
350
 
        if (last_snr2.doc) {
351
 
                tmplist = g_list_find(main_v->documentlist, last_snr2.doc);
 
411
        if (LASTSNR2(bfwin->snr2)->doc) {
 
412
                tmplist = g_list_find(bfwin->documentlist, LASTSNR2(bfwin->snr2)->doc);
352
413
        } else {
353
 
                last_snr2.result.end = 0;
354
 
                tmplist = g_list_first(main_v->documentlist);
 
414
                LASTSNR2(bfwin->snr2)->result.end = 0;
 
415
                tmplist = g_list_first(bfwin->documentlist);
355
416
        }
356
417
        while (tmplist) {
357
 
                result = search_doc((Tdocument *)tmplist->data, pattern, is_regex, is_case_sens, last_snr2.result.end);
 
418
                Tsearch_result result;
 
419
 
 
420
                result = search_doc(bfwin,(Tdocument *)tmplist->data, search_pattern, matchtype, is_case_sens, LASTSNR2(bfwin->snr2)->result.end, unescape);
358
421
                if (result.end > 0) {
359
422
                        result_all.start = result.start;
360
423
                        result_all.end = result.end;
364
427
                }
365
428
                tmplist = g_list_next(tmplist);
366
429
                if (tmplist) {
367
 
                        last_snr2.result.end = 0;
 
430
                        LASTSNR2(bfwin->snr2)->result.end = 0;
368
431
                }
369
432
        }
370
433
        DEBUG_MSG("search_all, not found..\n");
372
435
}
373
436
 
374
437
/*****************************************************/
 
438
 
 
439
static gchar *reg_replace(gchar *replace_pattern, gint offset, Tsearch_result result, Tdocument *doc, gboolean standardescape) {
 
440
        Tconvert_table * tct;
 
441
        gchar *retval;
 
442
        gint i, size;
 
443
        DEBUG_MSG("reg_replace, started for pattern='%s',standardescape=%d\n",replace_pattern,standardescape);
 
444
        size = (result.nmatch <= 10) ? (result.nmatch == 0 ) ? 0 : result.nmatch -1 : 10;
 
445
        tct = new_convert_table(size, standardescape);
 
446
        for (i=0;i<size;i++) {
 
447
                tct[i].my_int = i+48;
 
448
                tct[i].my_char = doc_get_chars(doc, offset+result.pmatch[i+1].rm_so, offset+result.pmatch[i+1].rm_eo);
 
449
        }
 
450
        retval = expand_string(replace_pattern, '\\', tct);
 
451
        free_convert_table(tct);
 
452
        return retval;
 
453
}
 
454
 
375
455
/*
376
 
this function will parse the replace string and substitute the \0, \1 etc. with 
377
 
the subpattern matches from regexec()
378
 
*/
379
 
static gchar *reg_replace(gchar *replace_string, gint offset, Tsearch_result result, Tdocument *doc) {
 
456
 * this function will parse the replace string and substitute the \0, \1 etc. with 
 
457
 * the subsearch_pattern matches from regexec()
 
458
 */
 
459
/*static gchar *oldreg_replace(gchar *replace_pattern, gint offset, Tsearch_result result, Tdocument *doc) {
380
460
        gchar *tmp1, *newstring;
381
461
        gchar *tmpstr1, *tmpstr2, *tmpstr3;
382
462
        gboolean escaped=0;
383
463
        guint from=0, to=0;
384
464
 
385
465
        newstring = g_strdup("");
386
 
        tmp1 = replace_string;
 
466
        tmp1 = replace_pattern;
387
467
        while (*tmp1 != '\0') {
388
468
                if (escaped) {
389
469
                        if (*tmp1 == '\\') {
390
470
                                to++;
391
471
                                tmpstr1 = newstring;
392
 
                                tmpstr2 = g_strndup(&replace_string[from], to-from);
 
472
                                tmpstr2 = g_strndup(&replace_pattern[from], to-from);
393
473
                                newstring = g_strconcat(tmpstr1, tmpstr2, NULL);
394
474
                                g_free(tmpstr1);
395
475
                                g_free(tmpstr2);
398
478
                        } else if ((gint)*tmp1 >= 48 && (gint)*tmp1 <= 57) {
399
479
                                gint num = (gint)*tmp1 - 48;
400
480
                                tmpstr1 = newstring;
401
 
                                tmpstr2 = g_strndup(&replace_string[from], to-from);
 
481
                                tmpstr2 = g_strndup(&replace_pattern[from], to-from);
402
482
                                DEBUG_MSG("reg_replace, from=%d, to=%d, tmpstr2='%s'\n", from, to, tmpstr2);
403
483
                                if (result.nmatch >= num+1) {
404
 
                                        DEBUG_MSG("reg_replace, wanted: sub pattern %d, offset=%d, so=%d, eo=%d\n", num, offset, result.pmatch[num+1].rm_so, result.pmatch[num+1].rm_eo);
405
 
                                        tmpstr3 = gtk_editable_get_chars(GTK_EDITABLE(doc->textbox), offset+result.pmatch[num+1].rm_so, offset+result.pmatch[num+1].rm_eo);
406
 
                                        DEBUG_MSG("reg_replace, subpattern %d = '%s'\n", num, tmpstr3);
 
484
                                        DEBUG_MSG("reg_replace, wanted: sub search_pattern %d, offset=%d, so=%d, eo=%d\n", num, offset, result.pmatch[num+1].rm_so, result.pmatch[num+1].rm_eo);
 
485
                                        tmpstr3 = doc_get_chars(doc, offset+result.pmatch[num+1].rm_so, offset+result.pmatch[num+1].rm_eo);
 
486
                                        DEBUG_MSG("reg_replace, subsearch_pattern %d = '%s'\n", num, tmpstr3);
407
487
                                } else {
408
 
                                        DEBUG_MSG("reg_replace, subpattern %d does not exist\n", num);
 
488
                                        DEBUG_MSG("reg_replace, subsearch_pattern %d does not exist, nmatch=%d\n", num, result.nmatch);
409
489
                                        tmpstr3 = g_strdup("");
410
490
                                }
411
491
                                newstring = g_strconcat(tmpstr1, tmpstr2, tmpstr3, NULL);
414
494
                                g_free(tmpstr3);
415
495
                                to += 2;
416
496
                                from = to;
417
 
                                DEBUG_MSG("reg_replace, substituted subpattern, newstring='%s'\n", newstring);
 
497
                                DEBUG_MSG("reg_replace, substituted subsearch_pattern, newstring='%s'\n", newstring);
418
498
                        } else {
419
499
                                to += 2;
420
500
                        }
429
509
                tmp1++;
430
510
        }
431
511
        tmpstr1 = newstring;
432
 
        tmpstr2 = g_strndup(&replace_string[from], to-from);
 
512
        tmpstr2 = g_strndup(&replace_pattern[from], to-from);
433
513
        newstring = g_strconcat(tmpstr1, tmpstr2, NULL);
434
514
        g_free(tmpstr1);
435
515
        g_free(tmpstr2);
436
516
        DEBUG_MSG("reg_replace, end, newstring='%s'\n", newstring);
437
517
        return newstring;
438
 
}
 
518
}*/
439
519
 
440
 
Tsearch_result replace_backend(gchar *pattern, gint is_regex, gint is_case_sens
441
 
                        , gchar *buf, gchar *replace_string, Tdocument *doc, gint offset, replacetypes replacetype
442
 
                        , gint use_mb, gint *replacelen) {
 
520
/**
 
521
 * replace_backend:
 
522
 * @bfwin: #Tbfwin with the window from this/these documents
 
523
 * @search_pattern: #gchar* to search pattern
 
524
 * @matchtype: See #Tmatch_types
 
525
 * @is_case_sens: #gint
 
526
 * @buf: #ghar* to buffer
 
527
 * @replace_pattern: The replace pattern.
 
528
 * @doc: the #Tdocument
 
529
 * @offset: The difference between the buffer and the text widget because of previous replace actions, so the first char in buf is actually number offset in the text widget.
 
530
 * @replacetype: see #Treplace_types
 
531
 * @replacelen: #gint*, set to -1 to calculate this automatically.
 
532
 * 
 
533
 * This will perform a search and the actual replacement of data in the buffer.
 
534
 * Note that *buf is probably an offset in the documents buffer.
 
535
 * 
 
536
 * Return value: #Tsearch_result
 
537
 **/
 
538
Tsearch_result replace_backend(Tbfwin *bfwin,gchar *search_pattern, Tmatch_types matchtype, gint is_case_sens
 
539
                        , gchar *buf, guint byte_offset, gchar *replace_pattern, Tdocument *doc, gint offset, Treplace_types replacetype
 
540
                        , gint *replacelen, gboolean unescape) {
443
541
/* the offset in this function is the difference between the buffer and the text widget because of previous replace 
444
542
actions, so the first char in buf is actually number offset in the text widget */
445
543
/* replacelen -1 means there is no replacelen known yet, so we have to calculate it */
446
544
        Tsearch_result result;
447
 
        gchar *tmpstr=NULL;
 
545
        gchar *tmpstr=NULL, *realpat;
448
546
        
449
 
        result = search_backend(pattern, is_regex, is_case_sens, buf, use_mb, is_regex);
 
547
        if (unescape) {
 
548
                realpat = unescape_string(search_pattern,FALSE);
 
549
                DEBUG_MSG("replace_backend, realpat='%s'\n",realpat);
 
550
        } else {
 
551
                realpat = search_pattern;
 
552
        }
 
553
        result = search_backend(bfwin,realpat, matchtype, is_case_sens, buf, byte_offset, (matchtype != match_normal));
 
554
        if (unescape) {
 
555
                DEBUG_MSG("replace_backend, free-ing realpat\n");
 
556
                g_free(realpat);
 
557
        }
450
558
        DEBUG_MSG("replace_backend, offset=%d, result.start=%d, result.end=%d\n", offset, result.start, result.end);
451
559
        if (result.end > 0) {
452
560
                switch (replacetype) {
453
561
                case string:
454
 
                        if (is_regex) {
455
 
                                tmpstr = reg_replace(replace_string, offset, result, doc);
 
562
                        if (matchtype == match_normal) {
 
563
                                if (unescape) {
 
564
                                        DEBUG_MSG("replace_backend, replace_pattern='%s'\n",replace_pattern);
 
565
                                        tmpstr = unescape_string(replace_pattern, FALSE);
 
566
                                } else {
 
567
                                        tmpstr = g_strdup(replace_pattern);
 
568
                                }
456
569
                        } else {
457
 
                                tmpstr = g_strdup(replace_string);
 
570
                                tmpstr = reg_replace(replace_pattern, offset, result, doc, unescape);
458
571
                        }
459
572
                        DEBUG_MSG("replace_backend, tmpstr='%s'\n", tmpstr);
460
573
                break;
461
 
                case upcase:
 
574
                case uppercase:
462
575
                        tmpstr = g_strndup(&buf[result.bstart], result.bend - result.bstart);
463
576
                        g_strup(tmpstr);
464
577
                break;
465
 
                case lowcase:
 
578
                case lowercase:
466
579
                        tmpstr = g_strndup(&buf[result.bstart], result.bend - result.bstart);
467
580
                        g_strdown(tmpstr);
468
581
                break;
469
582
                }
470
 
                DEBUG_MSG("replace_backend, len=%d, offset=%d, start=%d, end=%d, document=%p\n", result.end - result.start, offset, result.start + offset, result.end + offset, doc);
471
 
                doc_replace_text_backend(tmpstr, result.start + offset, result.end + offset, doc);
 
583
                DEBUG_MSG("replace_backend, len=%d, offset=%d, start=%d, end=%d, document=%p, tmpstr='%s'\n", result.end - result.start, offset, result.start + offset, result.end + offset, doc,tmpstr);
 
584
                doc_replace_text_backend(doc, tmpstr, result.start + offset, result.end + offset);
472
585
                if (*replacelen == -1) {
473
 
                        if (GTK_TEXT(doc->textbox)->use_wchar) {
474
 
                                *replacelen = strlen(tmpstr);
475
 
                        } else {
476
 
                                *replacelen = wchar_len(tmpstr, -1);
477
 
                        }
 
586
                        *replacelen = g_utf8_strlen(tmpstr, -1);
478
587
                }
479
588
                g_free(tmpstr);
480
589
        }
481
 
        if (is_regex) {
 
590
        if (matchtype == match_posix) {
482
591
                g_free(result.pmatch);
483
592
                result.pmatch = NULL;
484
593
        }
487
596
 
488
597
/*****************************************************/
489
598
 
490
 
Tsearch_result replace_doc_once(gchar *pattern, gint is_regex, gint is_case_sens, gint startpos, gint endpos, gchar *replace_string, Tdocument *doc, replacetypes replacetype) {
 
599
/**
 
600
 * replace_doc_once:
 
601
 * @search_pattern: #gchar* to search pattern
 
602
 * @matchtype: see #Tmatch_types
 
603
 * @is_case_sens: #gint
 
604
 * @startpos: #gint offset in document.
 
605
 * @endpos: #gint where to stop replacing. Set to -1 to cover the entire buffer.
 
606
 * @replace_pattern: #gchar* to replace pattern
 
607
 * @doc: a #Tdocument* to work on
 
608
 * @replacetype: see #Treplace_types
 
609
 *
 
610
 * Performs a single replace with the selected parameters, by calling replace_backend().
 
611
 * Calls doc_unre_new_group(doc) to make this action undoable.
 
612
 * Updates the internal last_snr2 struct, but the _caller_ is responsible for honouring this data.
 
613
 * 
 
614
 * Return value: #Tsearch_result
 
615
 **/
 
616
Tsearch_result replace_doc_once(Tbfwin *bfwin,gchar *search_pattern, Tmatch_types matchtype, gint is_case_sens, gint startpos, gint endpos, gchar *replace_pattern, Tdocument *doc, Treplace_types replacetype, gboolean unescape) {
491
617
/* endpos -1 means do till end */
492
618
        gchar *fulltext;
493
619
        gint replacelen = 0; /* replacelen -1 means there is no replacelen known yet
494
620
                                                                , but we don't need one, so we set it to 0 */
495
621
        Tsearch_result result;
496
622
 
497
 
#ifdef UNDO2
498
623
        doc_unre_new_group(doc);
499
 
#endif
500
 
        fulltext = gtk_editable_get_chars(GTK_EDITABLE(doc->textbox), startpos, endpos);
501
 
        result = replace_backend(pattern, is_regex, is_case_sens, fulltext, replace_string, doc, startpos, replacetype, GTK_TEXT(doc->textbox)->use_wchar, &replacelen);
 
624
        fulltext = doc_get_chars(doc, startpos, endpos);
 
625
        result = replace_backend(bfwin,search_pattern, matchtype, is_case_sens, fulltext, 0, replace_pattern, doc, startpos, replacetype, &replacelen, unescape);
502
626
        if ( result.end > 0) {
503
 
                last_snr2.result.start = result.start + startpos;
504
 
                last_snr2.result.end = result.end + startpos;
505
 
                last_snr2.doc = doc;
 
627
                LASTSNR2(bfwin->snr2)->result.start = result.start + startpos;
 
628
                LASTSNR2(bfwin->snr2)->result.end = result.end + startpos;
 
629
                LASTSNR2(bfwin->snr2)->doc = doc;
506
630
        } else {
507
 
                last_snr2.result.start = -1;
508
 
                last_snr2.result.end = -1;
509
 
                last_snr2.doc = doc;
 
631
                LASTSNR2(bfwin->snr2)->result.start = -1;
 
632
                LASTSNR2(bfwin->snr2)->result.end = -1;
 
633
                LASTSNR2(bfwin->snr2)->doc = doc;
510
634
        }
511
635
        g_free(fulltext);
512
 
#ifdef UNDO2
 
636
 
513
637
        doc_unre_new_group(doc);
514
 
#endif
 
638
 
515
639
        return result;
516
640
}
517
641
 
518
642
/*****************************************************/
519
643
 
520
 
void replace_doc_multiple(gchar *pattern, gint is_regex, gint is_case_sens, gint startpos, gint endpos, gchar *replace_string, Tdocument *doc, replacetypes replacetype) {
 
644
/**
 
645
 * replace_doc_multiple:
 
646
 * @search_pattern: #gchar* to search pattern
 
647
 * @matchtype: see #Tmatch_types
 
648
 * @is_case_sens: #gint
 
649
 * @endpos: #gint where to stop replacing. Set to -1 to cover the entire buffer.
 
650
 * @replace_pattern: #gchar* to replace pattern
 
651
 * @doc: a #Tdocument* to work on
 
652
 * @replacetype: see #Treplace_types
 
653
 * 
 
654
 * Performs a replace on all occurences of the pattern in the supplied document.
 
655
 * The doc's buffer will be modified.
 
656
 *
 
657
 * last_snr2 is reset with .start = .end = -1, and .doc = doc.
 
658
 * 
 
659
 * Return value: void
 
660
 **/
 
661
void replace_doc_multiple(Tbfwin *bfwin,gchar *search_pattern, Tmatch_types matchtype, gint is_case_sens, gint startpos, gint endpos, gchar *replace_pattern, Tdocument *doc, Treplace_types replacetype, gboolean unescape) {
521
662
/* endpos -1 means do till end */
522
 
        gchar *fulltext;
523
 
        gchar *onechar;
 
663
        gchar *fulltext, *realpats, *realpatr;
 
664
        gboolean realunesc;
524
665
        Tsearch_result result;
525
 
        gint in_buf_offset=0;
 
666
        gint buf_byte_offset=0;
526
667
        gint buf_text_offset=startpos;
527
 
        gint replacelen=-1; /* replacelen -1 means there is no replacelen known yet */
 
668
        gint replacelen; /* replacelen -1 means there is no replacelen known yet */
 
669
        doc_unre_new_group(doc);
528
670
 
529
 
#ifdef UNDO2
530
 
        doc_unre_new_group(doc);
531
 
#endif
532
671
        DEBUG_MSG("replace_doc_multiple, startpos=%d, endpos=%d\n", startpos, endpos);
533
 
        if (!is_regex || replacetype != string) {
534
 
                /* the replace string has a fixed length if it is not regex, or it is not type string */
535
 
                if (GTK_TEXT(doc->textbox)->use_wchar) {
536
 
                        replacelen = wchar_len(replace_string, -1);
 
672
        if (matchtype == match_normal || replacetype != string) {
 
673
                /* the replace string has a fixed length if it is not regex, or it is not type string
 
674
                 in this case we can also do the unescaping in this function */
 
675
                if (unescape) {
 
676
                        realpats = unescape_string(search_pattern, FALSE);
 
677
                        realpatr = unescape_string(replace_pattern, FALSE);
 
678
                        DEBUG_MSG("replace_doc_multiple, unescaped patterns, realpats='%s', realpatr='%s'\n",realpats, realpatr);
537
679
                } else {
538
 
                        replacelen = strlen(replace_string);
 
680
                        realpats = search_pattern;
 
681
                        realpatr = replace_pattern;
539
682
                }
 
683
                replacelen = g_utf8_strlen(realpatr,-1);
 
684
                realunesc = FALSE;
 
685
        } else {
 
686
                replacelen=-1;
 
687
                realpats = search_pattern;
 
688
                realpatr = replace_pattern;
 
689
                realunesc = unescape;
540
690
        }
541
 
        fulltext = gtk_editable_get_chars(GTK_EDITABLE(doc->textbox), startpos, endpos);
542
 
        result = replace_backend(pattern, is_regex, is_case_sens, fulltext, replace_string, doc, buf_text_offset, replacetype, GTK_TEXT(doc->textbox)->use_wchar, &replacelen);
 
691
        fulltext = doc_get_chars(doc, startpos, endpos);
 
692
        result = replace_backend(bfwin,realpats, matchtype, is_case_sens, fulltext, 0, realpatr, doc, buf_text_offset, replacetype, &replacelen, realunesc);
543
693
        while (result.end > 0) {
544
694
                if (replacetype == string) {
545
695
                        buf_text_offset += replacelen - (result.end - result.start);
546
696
                }
547
 
                if (last_snr2.overlapping_search) {
548
 
                        if (GTK_TEXT(doc->textbox)->use_wchar) {
549
 
                                onechar = gtk_editable_get_chars(GTK_EDITABLE(doc->textbox), startpos + result.start, startpos + result.start + 1);
550
 
                                if (onechar) {
551
 
                                        in_buf_offset += result.bstart + strlen(onechar);
552
 
                                } else {
553
 
                                        in_buf_offset += result.bstart + 1;
554
 
                                }
555
 
                                g_free(onechar);
556
 
                        } else {
557
 
                                in_buf_offset += result.bstart + 1;
558
 
                        }
559
 
                        buf_text_offset += result.start + 1;
 
697
                if (LASTSNR2(bfwin->snr2)->overlapping_search) {
 
698
                        buf_byte_offset = result.bstart + 1;
 
699
                        /* buf_text_offset += result.start + 1; */
560
700
                } else {
561
 
                        in_buf_offset += result.bend;
562
 
                        buf_text_offset += result.end;
 
701
                        buf_byte_offset = result.bend;
 
702
                        /* buf_text_offset += result.end; */
563
703
                }
564
 
                DEBUG_MSG("replace_doc_multiple, after first search, buf_text_offset=%d, in_buf_offset=%d\n", buf_text_offset, in_buf_offset);
565
 
                if (is_regex && replacetype == string) {
 
704
                DEBUG_MSG("replace_doc_multiple, after first search, buf_text_offset=%d, buf_byte_offset=%d\n", buf_text_offset, buf_byte_offset);
 
705
                if (matchtype != match_normal && replacetype == string) {
566
706
                        /* all regex replaces can have different replace lengths, so they have to be re-calculated */
567
707
                        replacelen = -1;
568
708
                }
569
 
                result = replace_backend(pattern, is_regex, is_case_sens, &fulltext[in_buf_offset], replace_string, doc, buf_text_offset, replacetype, GTK_TEXT(doc->textbox)->use_wchar, &replacelen);
570
 
 
571
 
                DEBUG_MSG("replace_doc_multiple, 1- buf_text_offset=%d, in_buf_offset=%d, result.start=%d, result.end=%d\n", buf_text_offset, in_buf_offset, result.start, result.end);
572
 
        }
573
 
#ifdef UNDO2
 
709
                result = replace_backend(bfwin,realpats, matchtype, is_case_sens, fulltext, buf_byte_offset, realpatr, doc, buf_text_offset, replacetype, &replacelen, realunesc);
 
710
 
 
711
                DEBUG_MSG("replace_doc_multiple, 1- buf_text_offset=%d, buf_byte_offset=%d, result.start=%d, result.end=%d\n", buf_text_offset, buf_byte_offset, result.start, result.end);
 
712
        }
 
713
        if (unescape && (matchtype == match_normal || replacetype != string)) {
 
714
                DEBUG_MSG("replace_doc_multiple, free-ing realpats and realpatr\n");
 
715
                g_free(realpats);
 
716
                g_free(realpatr);
 
717
        }
 
718
 
574
719
        doc_unre_new_group(doc);
575
 
#endif
576
 
        last_snr2.result.start = -1;
577
 
        last_snr2.result.end = -1;
578
 
        last_snr2.doc = doc;
 
720
 
 
721
        LASTSNR2(bfwin->snr2)->result.start = -1;
 
722
        LASTSNR2(bfwin->snr2)->result.end = -1;
 
723
        LASTSNR2(bfwin->snr2)->doc = doc;
579
724
        g_free(fulltext);
580
725
}
581
726
 
582
727
/*****************************************************/
583
728
 
584
 
void replace_all(gchar *pattern, gint is_regex, gint is_case_sens, gchar *replace_string, replacetypes replacetype) {
 
729
/**
 
730
 * replace_all:
 
731
 * @bfwin: #Tbfwin* the window with the documents to act upon
 
732
 * @search_pattern: #gchar* to search pattern
 
733
 * @matchtype: see #Tmatch_types
 
734
 * @is_case_sens: #gint
 
735
 * @replace_pattern: #gchar* to replace pattern
 
736
 * @replacetype: see #Treplace_types
 
737
 * 
 
738
 * Perform a replace_doc_multiple() with supplied data on all open documents.
 
739
 * This will replace all occurences of search_pattern in all documents.
 
740
 * 
 
741
 * Return value: void
 
742
 **/
 
743
void replace_all(Tbfwin *bfwin,gchar *search_pattern, Tmatch_types matchtype, gint is_case_sens, gchar *replace_pattern, Treplace_types replacetype, gboolean unescape) {
585
744
        GList *tmplist;
586
745
 
587
 
 
588
 
        tmplist = g_list_first(main_v->documentlist);
 
746
        tmplist = g_list_first(bfwin->documentlist);
589
747
        while (tmplist) {
590
 
                replace_doc_multiple(pattern, is_regex, is_case_sens, 0, -1, replace_string, (Tdocument *)tmplist->data, replacetype);
 
748
                replace_doc_multiple(bfwin,search_pattern, matchtype, is_case_sens, 0, -1, replace_pattern, (Tdocument *)tmplist->data, replacetype, unescape);
591
749
                tmplist = g_list_next(tmplist);
592
750
        }
593
751
}
594
752
 
595
753
/*****************************************************/
 
754
/*             Replace prompt callbacks              */
 
755
/*****************************************************/
596
756
 
597
 
static void replace_prompt_dialog_ok_lcb(GtkWidget *widget, gpointer data) {
 
757
/*
 
758
 *
 
759
 * Performs the actual replace-surgery by calls to doc_replace_text_backend() !
 
760
 * Continues the replace cycle by calling snr2_run(), unless this is a single replace.
 
761
 *
 
762
 */
 
763
static void replace_prompt_dialog_ok_lcb(GtkWidget *widget, Tbfwin *bfwin) {
598
764
        gchar *tmpstr;
599
 
 
600
 
        window_close_by_widget_cb(widget, data);
601
 
                if ((GTK_EDITABLE(main_v->current_document->textbox)->selection_start_pos == last_snr2.result.start) &&
602
 
                                        (GTK_EDITABLE(main_v->current_document->textbox)->selection_end_pos == last_snr2.result.end)) {
603
 
 
604
 
                        if (last_snr2.replacetype_string) {
605
 
                                tmpstr = g_strdup(last_snr2.replace_string);
606
 
                        } else if (last_snr2.replacetype_upcase) {
607
 
                                tmpstr = gtk_editable_get_chars(GTK_EDITABLE(main_v->current_document->textbox), last_snr2.result.start ,last_snr2.result.end);
608
 
                                g_strup(tmpstr);
609
 
                        } else {
610
 
                                tmpstr = gtk_editable_get_chars(GTK_EDITABLE(main_v->current_document->textbox), last_snr2.result.start ,last_snr2.result.end);
611
 
                                g_strdown(tmpstr);
612
 
                        }
613
 
                        doc_replace_text(tmpstr, last_snr2.result.start,last_snr2.result.end , main_v->current_document);
614
 
                        g_free(tmpstr);
615
 
                        if (!last_snr2.replace_once) {
616
 
                                snr2_run();
617
 
                        }
618
 
                }
619
 
}
620
 
 
621
 
static void replace_prompt_dialog_all_lcb(GtkWidget *widget, gpointer data) {
622
 
        window_close_by_widget_cb(widget, data);
623
 
        last_snr2.prompt_before_replacing = 0;
624
 
        last_snr2.result.start--;
625
 
        last_snr2.result.end = last_snr2.result.start;
626
 
        snr2_run();
627
 
}
628
 
 
629
 
void replace_prompt_dialog() {
 
765
        gint sel_start_pos, sel_end_pos;
 
766
 
 
767
        window_close_by_widget_cb(widget, NULL);
 
768
        
 
769
        doc_get_selection(bfwin->current_document, &sel_start_pos, &sel_end_pos);
 
770
        if ((sel_start_pos == LASTSNR2(bfwin->snr2)->result.start) &&
 
771
                                (sel_end_pos == LASTSNR2(bfwin->snr2)->result.end)) {
 
772
                gint lenadded;
 
773
                if (LASTSNR2(bfwin->snr2)->replacetype_option==string) {
 
774
                        tmpstr = g_strdup(LASTSNR2(bfwin->snr2)->replace_pattern);
 
775
                        /* if it was a regex replace we need to do the sub-search_pattern matching */
 
776
                        tmpstr = reg_replace(tmpstr, 0, LASTSNR2(bfwin->snr2)->result, bfwin->current_document, LASTSNR2(bfwin->snr2)->unescape);
 
777
                        
 
778
                } else if (LASTSNR2(bfwin->snr2)->replacetype_option==uppercase) {
 
779
                        tmpstr = doc_get_chars(bfwin->current_document, LASTSNR2(bfwin->snr2)->result.start ,LASTSNR2(bfwin->snr2)->result.end);
 
780
                        g_strup(tmpstr);
 
781
                } else {
 
782
                        tmpstr = doc_get_chars(bfwin->current_document, LASTSNR2(bfwin->snr2)->result.start ,LASTSNR2(bfwin->snr2)->result.end);
 
783
                        g_strdown(tmpstr);
 
784
                }
 
785
                /* avoid new highlighting at this stage, so call the backend directly instead of the frontend function
 
786
                this because the highlighting interferes with the selection
 
787
                the better solution is to have the highlighting handle the selection better, 
 
788
                the problem starts in document.c in get_positions() because the selection is not saved there
 
789
                I don't know why the selection is gray, but that's basically the reason why it doesn't save the selection
 
790
                 */
 
791
 
 
792
                doc_unre_new_group(bfwin->current_document);
 
793
                doc_replace_text_backend(bfwin->current_document, tmpstr, LASTSNR2(bfwin->snr2)->result.start,LASTSNR2(bfwin->snr2)->result.end);
 
794
                doc_unre_new_group(bfwin->current_document);
 
795
                doc_set_modified(bfwin->current_document, 1);
 
796
 
 
797
                lenadded = strlen(tmpstr) - (LASTSNR2(bfwin->snr2)->result.end - LASTSNR2(bfwin->snr2)->result.start);
 
798
                DEBUG_MSG("lenadded=%d (streln=%d, end-start=%d)\n",lenadded,strlen(tmpstr),(LASTSNR2(bfwin->snr2)->result.end - LASTSNR2(bfwin->snr2)->result.start));
 
799
                g_free(tmpstr);
 
800
                if (LASTSNR2(bfwin->snr2)->result.pmatch) {
 
801
                        g_free(LASTSNR2(bfwin->snr2)->result.pmatch);
 
802
                        LASTSNR2(bfwin->snr2)->result.pmatch = NULL;
 
803
                }
 
804
                if (!LASTSNR2(bfwin->snr2)->replace_once) {
 
805
                        if (!LASTSNR2(bfwin->snr2)->overlapping_search && lenadded > 0) {
 
806
                                LASTSNR2(bfwin->snr2)->result.end += lenadded;
 
807
                        }
 
808
                        snr2_run(bfwin,NULL);
 
809
                }
 
810
        }
 
811
#ifdef DEBUG
 
812
         else {
 
813
                g_print("replace_prompt_dialog_ok_lcb, selection != result, not replacing!!\n");
 
814
        }
 
815
#endif /* DEBUG */
 
816
}
 
817
 
 
818
static void replace_prompt_dialog_skip_lcb(GtkWidget *widget, Tbfwin *bfwin) {
 
819
        window_close_by_widget_cb(widget, NULL);
 
820
        if (LASTSNR2(bfwin->snr2)->result.pmatch) {
 
821
                g_free(LASTSNR2(bfwin->snr2)->result.pmatch);
 
822
                LASTSNR2(bfwin->snr2)->result.pmatch = NULL;
 
823
        }
 
824
        if (!LASTSNR2(bfwin->snr2)->replace_once) {
 
825
                snr2_run(bfwin,NULL);
 
826
        }
 
827
}
 
828
 
 
829
/* Alters last_snr2, setting no-prompt-mode, backtracking one step on the startpoint and .end = .start
 
830
 * continues by running snr2_run(). This will replace all occurrences of the string.. */
 
831
static void replace_prompt_dialog_all_lcb(GtkWidget *widget, Tbfwin *bfwin) {
 
832
        window_close_by_widget_cb(widget, NULL);
 
833
        LASTSNR2(bfwin->snr2)->prompt_before_replace = 0;
 
834
        LASTSNR2(bfwin->snr2)->result.start--;
 
835
        LASTSNR2(bfwin->snr2)->result.end = LASTSNR2(bfwin->snr2)->result.start;
 
836
        if (LASTSNR2(bfwin->snr2)->result.pmatch) {
 
837
                g_free(LASTSNR2(bfwin->snr2)->result.pmatch);
 
838
                LASTSNR2(bfwin->snr2)->result.pmatch = NULL;
 
839
        }
 
840
        snr2_run(bfwin,NULL);
 
841
}
 
842
 
 
843
 
 
844
/**
 
845
 * replace_prompt_dialog:
 
846
 * 
 
847
 * Prompt the user for a replace action. Simply creates and shows GUI.
 
848
 * Used by replace_prompt_doc().
 
849
 * 
 
850
 * Return value: void
 
851
 **/
 
852
void replace_prompt_dialog(Tbfwin *bfwin) {
630
853
        GtkWidget *win, *vbox, *hbox;
631
 
        GtkWidget *butok, *butcancel, *butall;
632
 
 
633
 
        win = window_full(_("Confirm replace"), GTK_WIN_POS_MOUSE, GTK_WINDOW_DIALOG
634
 
                        , 5, window_close_by_widget_cb, NULL);
635
 
        vbox = gtk_vbox_new(FALSE, 3);
636
 
        gtk_container_add(GTK_CONTAINER(win), vbox);
637
 
        gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(_("Are you sure you want to replace this?")), FALSE, FALSE,3);
638
 
        hbox = gtk_hbox_new(TRUE, 3);
639
 
        gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE,3);
640
 
        butok = bf_stock_ok_button(replace_prompt_dialog_ok_lcb, win);
641
 
        butcancel = bf_stock_cancel_button(window_close_by_widget_cb, NULL);
642
 
        butall = bf_stock_button(_("All"), replace_prompt_dialog_all_lcb, win);
643
 
        gtk_box_pack_start(GTK_BOX(hbox), butok, TRUE, TRUE,3);
644
 
        gtk_box_pack_start(GTK_BOX(hbox), butcancel, TRUE, TRUE,3);
645
 
        gtk_box_pack_start(GTK_BOX(hbox), butall, TRUE, TRUE,3);
 
854
        GtkWidget *butok, *butclose, *butall, *butskip;
 
855
        GtkWidget *image, *label;
 
856
 
 
857
        DEBUG_MSG("replace_prompt_dialog, start\n");
 
858
        win = window_full(_("Confirm replace"), GTK_WIN_POS_MOUSE, 12, G_CALLBACK(window_close_by_widget_cb), NULL, TRUE);
 
859
        gtk_window_set_resizable (GTK_WINDOW (win), FALSE);     
 
860
 
 
861
        vbox = gtk_vbox_new (FALSE, 0);
 
862
        gtk_container_add (GTK_CONTAINER (win), vbox);
 
863
 
 
864
        hbox = gtk_hbox_new (FALSE, 12);
 
865
        gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
 
866
 
 
867
        image = gtk_image_new_from_stock ("gtk-dialog-question", GTK_ICON_SIZE_DIALOG);
 
868
        gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
 
869
 
 
870
        label = gtk_label_new (_("Replace selected text?"));
 
871
        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
 
872
        gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
 
873
        gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
 
874
 
 
875
        gtk_box_pack_start (GTK_BOX (vbox), gtk_hseparator_new (), FALSE, TRUE, 12);
 
876
 
 
877
        hbox = gtk_hbutton_box_new ();
 
878
        gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
 
879
        gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END);
 
880
        gtk_box_set_spacing (GTK_BOX (hbox), 6);
 
881
 
 
882
        butclose = bf_gtkstock_button(GTK_STOCK_CLOSE, G_CALLBACK(window_close_by_widget_cb), NULL);
 
883
        butskip = bf_allbuttons_backend(_("_Skip"), TRUE, 1000, G_CALLBACK(replace_prompt_dialog_skip_lcb), bfwin);
 
884
        butok = bf_allbuttons_backend(_("_Replace"), TRUE, 1001, G_CALLBACK(replace_prompt_dialog_ok_lcb), bfwin);
 
885
        butall = bf_generic_mnemonic_button(_("Replace _all"), G_CALLBACK(replace_prompt_dialog_all_lcb), bfwin);
 
886
        gtk_box_pack_start(GTK_BOX(hbox), butclose, FALSE, FALSE, 0);
 
887
        gtk_box_pack_start(GTK_BOX(hbox), butall, FALSE, FALSE, 0);
 
888
        gtk_box_pack_start(GTK_BOX(hbox), butok, FALSE, FALSE, 0);
 
889
        gtk_box_pack_start(GTK_BOX(hbox), butskip, FALSE, FALSE, 0);
 
890
        gtk_widget_grab_focus(butskip);
646
891
        gtk_widget_show_all(win);
 
892
        DEBUG_MSG("replace_prompt_dialog, end\n");
647
893
}
648
894
 
649
 
gint replace_prompt_doc(gchar *pattern, gint is_regex, gint is_case_sens, gint startpos, gint endpos, gchar *replace_string, Tdocument *doc) {
 
895
/**
 
896
 * replace_prompt_doc:
 
897
 * @search_pattern: #gchar* to search pattern
 
898
 * @matchtype: see #Tmatch_types
 
899
 * @is_case_sens: #gint
 
900
 * @startpos: Start offset in document buffer.
 
901
 * @endpos: End offset of search area. Set to -1 to cover entire buffer.
 
902
 * @replace_pattern: #gchar to replace pattern
 
903
 * @doc: a #Tdocument
 
904
 * 
 
905
 * Finds the next occurence of search_pattern in *doc, shows and selects it in the document,
 
906
 * and finally shows a replace_prompt_dialog to the user.
 
907
 *
 
908
 * last_snr2 is updated if an occurrence of search_pattern is found.
 
909
 * 
 
910
 * Return value: #gint, 1 if a new occurence of the search_pattern was found and a dialog is shown. 0 else.
 
911
 **/
 
912
gint replace_prompt_doc(Tbfwin *bfwin, gchar *search_pattern, Tmatch_types matchtype, gint is_case_sens, gint startpos, gint endpos, gchar *replace_pattern, Tdocument *doc, gboolean unescape) {
650
913
/* endpos -1 means do till end , returns if the document still had a match*/
651
 
        gchar *fulltext;
 
914
        gchar *fulltext, *realpat;
652
915
        Tsearch_result result;
653
916
 
654
 
        fulltext = gtk_editable_get_chars(GTK_EDITABLE(doc->textbox), startpos, endpos);
655
 
        result = search_backend(pattern, is_regex, is_case_sens, fulltext, GTK_TEXT(doc->textbox)->use_wchar, 0);
656
 
        last_snr2.doc = doc;
 
917
        DEBUG_MSG("replace_prompt_doc, doc=%p, startpos=%d, endpos=%d\n",doc,startpos,endpos);
 
918
        if (LASTSNR2(bfwin->snr2)->result.pmatch) {
 
919
                g_free(LASTSNR2(bfwin->snr2)->result.pmatch);
 
920
                LASTSNR2(bfwin->snr2)->result.pmatch = NULL;
 
921
        }
 
922
        fulltext = doc_get_chars(doc, startpos, endpos);
 
923
        utf8_offset_cache_reset();
 
924
        if (unescape) {
 
925
                realpat = unescape_string(search_pattern, FALSE);
 
926
        } else {
 
927
                realpat = search_pattern;
 
928
        }
 
929
        result = search_backend(bfwin,realpat, matchtype, is_case_sens, fulltext,0, 1);
 
930
        if (unescape) {
 
931
                g_free(realpat);
 
932
        }
 
933
        LASTSNR2(bfwin->snr2)->doc = doc;
657
934
        g_free(fulltext);
 
935
        DEBUG_MSG("replace_prompt_doc, doc=%p, result.end=%d\n", doc, result.end);
658
936
        if (result.end > 0) {
659
 
                last_snr2.result.start = result.start + startpos;
660
 
                last_snr2.result.end = result.end + startpos;
 
937
                gint i;
 
938
                LASTSNR2(bfwin->snr2)->result.start = result.start + startpos;
 
939
                LASTSNR2(bfwin->snr2)->result.end = result.end + startpos;
 
940
                LASTSNR2(bfwin->snr2)->result.nmatch = result.nmatch;
 
941
                LASTSNR2(bfwin->snr2)->result.pmatch = result.pmatch;
 
942
                for (i=0;i<result.nmatch;i++) {
 
943
                        DEBUG_MSG("replace_prompt_doc, adding offset %d to subsearch_pattern %d\n", startpos, i);
 
944
                        LASTSNR2(bfwin->snr2)->result.pmatch[i].rm_so += startpos;
 
945
                        LASTSNR2(bfwin->snr2)->result.pmatch[i].rm_eo += startpos;
 
946
                }
661
947
                doc_show_result(doc, result.start + startpos, result.end + startpos);
662
 
                replace_prompt_dialog();
 
948
                replace_prompt_dialog(bfwin);
663
949
                return 1;
664
950
        } else {
 
951
                g_free(result.pmatch);
665
952
                return 0;
666
953
        }
667
954
}
668
955
 
669
 
void replace_prompt_all(gchar *pattern, gint is_regex, gint is_case_sens, gchar *replace_string) {
 
956
/**
 
957
 * replace_prompt_all:
 
958
 * @search_pattern: #gchar* to search pattern
 
959
 * @matchtype: see #Tmatch_types
 
960
 * @is_case_sens: #gint
 
961
 * @replace_pattern: #gchar to replace pattern
 
962
 * 
 
963
 * Performs a replace_prompt_doc for all open documents.
 
964
 * 
 
965
 * Return value: void
 
966
 **/
 
967
void replace_prompt_all(Tbfwin *bfwin,gchar *search_pattern, Tmatch_types matchtype, gint is_case_sens, gchar *replace_pattern, gboolean unescape) {
670
968
        GList *tmplist;
671
969
        gint retvalue;
672
970
        Tdocument *tmpdoc;
673
971
 
674
 
        if (last_snr2.doc) {
675
 
                tmpdoc = last_snr2.doc;
 
972
        if (LASTSNR2(bfwin->snr2)->doc) {
 
973
                tmpdoc = LASTSNR2(bfwin->snr2)->doc;
676
974
        } else {
677
 
                tmplist = g_list_first(main_v->documentlist);
 
975
                tmplist = g_list_first(bfwin->documentlist);
678
976
                tmpdoc = (Tdocument *)tmplist->data;
679
977
        }
680
 
        retvalue = replace_prompt_doc(pattern, is_regex, is_case_sens, 0, -1, replace_string, tmpdoc);
 
978
        DEBUG_MSG("replace_prompt_all, starting with tmpdoc=%p at position %d\n",tmpdoc,LASTSNR2(bfwin->snr2)->result.end);
 
979
        retvalue = replace_prompt_doc(bfwin,search_pattern, matchtype, is_case_sens, (LASTSNR2(bfwin->snr2)->result.end < 0)?0:LASTSNR2(bfwin->snr2)->result.end, -1, replace_pattern, tmpdoc, unescape);
681
980
        while (retvalue == 0) {
682
 
                tmplist = g_list_find(main_v->documentlist, last_snr2.doc);
 
981
                tmplist = g_list_find(bfwin->documentlist, LASTSNR2(bfwin->snr2)->doc);
683
982
                tmplist = g_list_next(tmplist);
684
983
                if (tmplist) {
685
 
                        retvalue = replace_prompt_doc(pattern, is_regex, is_case_sens, 0, -1, replace_string, (Tdocument *)tmplist->data);
 
984
                        DEBUG_MSG("replace_prompt_all, next document is %p\n",tmplist->data);
 
985
                        retvalue = replace_prompt_doc(bfwin,search_pattern, matchtype, is_case_sens, 0, -1, replace_pattern, (Tdocument *)tmplist->data, unescape);
686
986
                } else {
687
987
                        retvalue = 1;
688
988
                }
689
989
        }
690
990
}
691
991
 
 
992
static void search_doc_bookmark_backend(Tbfwin *bfwin,Tdocument *document, gchar *search_pattern, Tmatch_types matchtype, gint is_case_sens, gint startpos, gboolean unescape) {
 
993
        gchar *fulltext, *realpat;
 
994
        gint buf_byte_offset=0;
 
995
        Tsearch_result result;
 
996
        fulltext = doc_get_chars(document, 0, -1);
 
997
        utf8_offset_cache_reset();
 
998
        if (unescape) {
 
999
                realpat = unescape_string(search_pattern, FALSE);
 
1000
        } else {
 
1001
                realpat = search_pattern;
 
1002
        }
 
1003
        result = search_backend(bfwin,realpat, matchtype, is_case_sens, fulltext, 0, FALSE);
 
1004
        while (result.end > 0) {
 
1005
                gchar *text = doc_get_chars(document, result.start, result.end);
 
1006
                DEBUG_MSG("search_bookmark, adding bookmark '%s' at %d\n", text, result.start);
 
1007
                bmark_add_extern(document, result.start, NULL, text, !main_v->props.bookmarks_default_store);
 
1008
                g_free(text);
 
1009
                if (LASTSNR2(bfwin->snr2)->overlapping_search) {
 
1010
                        buf_byte_offset = result.bstart + 1;
 
1011
                } else {
 
1012
                        buf_byte_offset = result.bend;
 
1013
                }
 
1014
                result = search_backend(bfwin,realpat, matchtype, is_case_sens, fulltext, buf_byte_offset, FALSE);
 
1015
        }
 
1016
        if (unescape) {
 
1017
                g_free(realpat);
 
1018
        }
 
1019
        g_free(fulltext);
 
1020
}
 
1021
 
 
1022
/**
 
1023
 * search_bookmark:
 
1024
 * @bfwin: #Tbfwin *
 
1025
 * @startat: #gint
 
1026
 *
 
1027
 * will search, and bookmark all matches
 
1028
 * 
 
1029
 */
 
1030
static void search_bookmark(Tbfwin *bfwin, gint startat) {
 
1031
        DEBUG_MSG("search_bookmark, started\n");
 
1032
        if (LASTSNR2(bfwin->snr2)->placetype_option==opened_files) {
 
1033
                GList *tmplist = g_list_first(bfwin->documentlist);
 
1034
                while (tmplist) {
 
1035
                        search_doc_bookmark_backend(bfwin,DOCUMENT(tmplist->data), LASTSNR2(bfwin->snr2)->search_pattern, LASTSNR2(bfwin->snr2)->matchtype_option, LASTSNR2(bfwin->snr2)->is_case_sens, 0, LASTSNR2(bfwin->snr2)->unescape);
 
1036
                        tmplist = g_list_next(tmplist);
 
1037
                }
 
1038
        } else {
 
1039
                search_doc_bookmark_backend(bfwin,DOCUMENT(bfwin->current_document), LASTSNR2(bfwin->snr2)->search_pattern, LASTSNR2(bfwin->snr2)->matchtype_option, LASTSNR2(bfwin->snr2)->is_case_sens, startat, LASTSNR2(bfwin->snr2)->unescape);
 
1040
        }
 
1041
        DEBUG_MSG("search_bookmark, done\n");
 
1042
}
 
1043
 
692
1044
/*****************************************************/
693
1045
 
694
 
void snr2_run(void) {
 
1046
/**
 
1047
 * snr2_run:
 
1048
 * @bfwin: #Tbfwin*
 
1049
 * @doc: a #Tdocument* If set to NULL, use bfwin->current_document
 
1050
 *
 
1051
 * Continues a search or replace action as specified by the last_snr2 struct.
 
1052
 * 
 
1053
 * Return value: void
 
1054
 **/
 
1055
void snr2_run(Tbfwin *bfwin, Tdocument *doc) {
695
1056
        gint startpos, endpos;
696
1057
        Tsearch_result result;
697
1058
        Tsearch_all_result result_all;
698
 
        replacetypes replacetype;
 
1059
        Treplace_types replacetype;
 
1060
 
 
1061
        if (doc==NULL) {
 
1062
                doc = bfwin->current_document;
 
1063
        }
 
1064
 
 
1065
        if (LASTSNR2(bfwin->snr2)->result.pmatch) {
 
1066
                g_free(LASTSNR2(bfwin->snr2)->result.pmatch);
 
1067
                LASTSNR2(bfwin->snr2)->result.pmatch = NULL;
 
1068
        }
699
1069
 
700
1070
        /* should be more stuff here */
701
 
        if (last_snr2.region_from_beginning) {
 
1071
        if (LASTSNR2(bfwin->snr2)->placetype_option==beginning) {
702
1072
                startpos = 0;
703
1073
                endpos = -1;
704
 
        } else if (last_snr2.region_from_cursor) {
705
 
                startpos = gtk_editable_get_position(GTK_EDITABLE(main_v->current_document->textbox));
 
1074
        } else if (LASTSNR2(bfwin->snr2)->placetype_option==cursor) {
 
1075
                startpos = doc_get_cursor_position(doc);
706
1076
                endpos = -1;
707
 
        } else {
708
 
                startpos = GTK_EDITABLE(main_v->current_document->textbox)->selection_start_pos;
709
 
                endpos = GTK_EDITABLE(main_v->current_document->textbox)->selection_end_pos;
 
1077
        } else if (LASTSNR2(bfwin->snr2)->placetype_option==selection) {
 
1078
                if (!doc_get_selection(doc,&startpos,&endpos)) {
 
1079
                        /* what to do if there was no selection ?*/
 
1080
                        DEBUG_MSG("snr2_run, no selection found, returning\n");
 
1081
                        return;
 
1082
                }
 
1083
                DEBUG_MSG("snr2_run, from selection: startpos=%d, endpos=%d\n", startpos, endpos);
710
1084
        }
711
 
        if (last_snr2.doc == main_v->current_document) {
712
 
                DEBUG_MSG("snr2_run, last_snr2.result.end=%d, startpos=%d\n", last_snr2.result.end, startpos);
713
 
                if (last_snr2.result.end > 0) {
714
 
                        if (last_snr2.overlapping_search) {
715
 
                                startpos = last_snr2.result.start + 1;
 
1085
        if (LASTSNR2(bfwin->snr2)->doc == doc) {
 
1086
                if (LASTSNR2(bfwin->snr2)->result.end > 0) {
 
1087
                        if (LASTSNR2(bfwin->snr2)->overlapping_search) {
 
1088
                                startpos = LASTSNR2(bfwin->snr2)->result.start + 1;
716
1089
                        } else {
717
 
                                startpos = last_snr2.result.end;
 
1090
                                startpos = LASTSNR2(bfwin->snr2)->result.end;
718
1091
                        }
719
1092
                }
720
 
        }       
721
 
        if (last_snr2.replace) {
722
 
                if (last_snr2.replacetype_string) {
 
1093
                DEBUG_MSG("snr2_run, LASTSNR2(bfwin->snr2)->result.end=%d, startpos=%d\n", LASTSNR2(bfwin->snr2)->result.end, startpos);
 
1094
        }
 
1095
        if (LASTSNR2(bfwin->snr2)->replace) {
 
1096
                if (LASTSNR2(bfwin->snr2)->replacetype_option==string) {
723
1097
                        replacetype = string;
724
 
                } else if (last_snr2.replacetype_upcase) {
725
 
                        replacetype = upcase;
 
1098
                } else if (LASTSNR2(bfwin->snr2)->replacetype_option==uppercase) {
 
1099
                        replacetype = uppercase;
726
1100
                } else {
727
 
                        replacetype = lowcase;
 
1101
                        replacetype = lowercase;
728
1102
                }
729
1103
        
730
 
                if (last_snr2.prompt_before_replacing) {
731
 
                        if (last_snr2.region_all_open_files) {
732
 
                                replace_prompt_all(last_snr2.pattern,last_snr2.is_regex, last_snr2.is_case_sens, last_snr2.replace_string);
 
1104
                if (LASTSNR2(bfwin->snr2)->prompt_before_replace) {
 
1105
                        if (LASTSNR2(bfwin->snr2)->placetype_option==opened_files) {
 
1106
                                replace_prompt_all(bfwin,LASTSNR2(bfwin->snr2)->search_pattern,LASTSNR2(bfwin->snr2)->matchtype_option, LASTSNR2(bfwin->snr2)->is_case_sens, LASTSNR2(bfwin->snr2)->replace_pattern, LASTSNR2(bfwin->snr2)->unescape);
733
1107
                        } else {
734
 
                                replace_prompt_doc(last_snr2.pattern, last_snr2.is_regex, last_snr2.is_case_sens, startpos, endpos, last_snr2.replace_string, main_v->current_document);
 
1108
                                replace_prompt_doc(bfwin,LASTSNR2(bfwin->snr2)->search_pattern, LASTSNR2(bfwin->snr2)->matchtype_option, LASTSNR2(bfwin->snr2)->is_case_sens, startpos, endpos, LASTSNR2(bfwin->snr2)->replace_pattern, doc, LASTSNR2(bfwin->snr2)->unescape);
735
1109
                        }
736
1110
                } else {
737
 
                        if (last_snr2.region_all_open_files) {
738
 
                                replace_all(last_snr2.pattern, last_snr2.is_regex, last_snr2.is_case_sens, last_snr2.replace_string, replacetype);
739
 
                        } else if (last_snr2.replace_once) {
740
 
                                replace_doc_once(last_snr2.pattern, last_snr2.is_regex, last_snr2.is_case_sens, startpos, endpos, last_snr2.replace_string, main_v->current_document, replacetype);
 
1111
                        if (LASTSNR2(bfwin->snr2)->placetype_option==opened_files) {
 
1112
                                replace_all(bfwin,LASTSNR2(bfwin->snr2)->search_pattern, LASTSNR2(bfwin->snr2)->matchtype_option, LASTSNR2(bfwin->snr2)->is_case_sens, LASTSNR2(bfwin->snr2)->replace_pattern, replacetype, LASTSNR2(bfwin->snr2)->unescape);
 
1113
                        } else if (LASTSNR2(bfwin->snr2)->replace_once) {
 
1114
                                replace_doc_once(bfwin,LASTSNR2(bfwin->snr2)->search_pattern, LASTSNR2(bfwin->snr2)->matchtype_option, LASTSNR2(bfwin->snr2)->is_case_sens, startpos, endpos, LASTSNR2(bfwin->snr2)->replace_pattern, doc, replacetype, LASTSNR2(bfwin->snr2)->unescape);
741
1115
                        } else {
742
 
                                replace_doc_multiple(last_snr2.pattern, last_snr2.is_regex, last_snr2.is_case_sens, startpos, endpos, last_snr2.replace_string, main_v->current_document, replacetype);
 
1116
                                replace_doc_multiple(bfwin,LASTSNR2(bfwin->snr2)->search_pattern, LASTSNR2(bfwin->snr2)->matchtype_option, LASTSNR2(bfwin->snr2)->is_case_sens, startpos, endpos, LASTSNR2(bfwin->snr2)->replace_pattern, doc, replacetype, LASTSNR2(bfwin->snr2)->unescape);
743
1117
                        }               
744
1118
                }
 
1119
        } else { /* find, not replace */
 
1120
                if (LASTSNR2(bfwin->snr2)->bookmark_results) {
 
1121
                        search_bookmark(bfwin, startpos);
 
1122
                } else {
 
1123
                        if (LASTSNR2(bfwin->snr2)->placetype_option==opened_files) {
 
1124
                                DEBUG_MSG("snr2dialog_ok_lcb, search = all\n");
 
1125
                                result_all = search_all(bfwin,LASTSNR2(bfwin->snr2)->search_pattern, LASTSNR2(bfwin->snr2)->matchtype_option, LASTSNR2(bfwin->snr2)->is_case_sens, LASTSNR2(bfwin->snr2)->unescape);
 
1126
                                DEBUG_MSG("snr2dialog_ok_lcb, result_all.doc=%p\n",result_all.doc);
 
1127
                                if (result_all.end > 0) {
 
1128
                                        doc_show_result(result_all.doc, result_all.start, result_all.end);
 
1129
                                } else {
 
1130
                                        info_dialog(bfwin->main_window,_("Search: no match found"), NULL);
 
1131
                                }
 
1132
                        } else {
 
1133
                                result = search_doc(bfwin,doc, LASTSNR2(bfwin->snr2)->search_pattern, LASTSNR2(bfwin->snr2)->matchtype_option, LASTSNR2(bfwin->snr2)->is_case_sens, startpos, LASTSNR2(bfwin->snr2)->unescape);
 
1134
                                if (result.end > 0) {
 
1135
                                        doc_show_result(doc, result.start, result.end);
 
1136
                                } else {
 
1137
                                        info_dialog(bfwin->main_window,_("Search: no match found"), NULL);
 
1138
                                }
 
1139
                        }
 
1140
                }
 
1141
        }
 
1142
        /* if highlighting is needed for this document do this now !! */
 
1143
        if (doc->need_highlighting && doc->highlightstate) {
 
1144
                doc_highlight_full(doc);
 
1145
        }
 
1146
}
 
1147
 
 
1148
/**
 
1149
 * snr2_run_extern_replace:
 
1150
 * @doc: a #Tdocument
 
1151
 * @search_pattern: #gchar* to search pattern
 
1152
 * @region: #gint, 0 = region_from_beginning, 1 = region_from_cursor, 2 = region_selection, 3 = region_all_open_files
 
1153
 * @matchtype: #gint, 0 = normal, 1 = posix, 2 = perl
 
1154
 * @is_case_sens: #gint
 
1155
 * @replace_pattern: #gchar* to replace pattern.
 
1156
 * @store_as_last_snr2: Set to FALSE to keep the old last_snr2 after the snr has been completed.
 
1157
 * 
 
1158
 * Performs the specified replace action on the document by setting
 
1159
 * a last_snr2 and calling snr2_run().
 
1160
 *
 
1161
 * Additional non-configureable arguments passed to snr2_run() via last_snr2:
 
1162
 * replace = 1
 
1163
 * prompt_before_replace = off
 
1164
 * replace_once = off
 
1165
 *
 
1166
 * Return value: void
 
1167
 **/
 
1168
void snr2_run_extern_replace(Tdocument *doc, gchar *search_pattern, gint region,
 
1169
                                                        gint matchtype, gint is_case_sens, gchar *replace_pattern,
 
1170
                                                        gboolean store_as_last_snr2) {
 
1171
        Tbfwin *bfwin = BFWIN(doc->bfwin);
 
1172
        gchar *search_pattern_bck, *replace_pattern_bck;
 
1173
        Tlast_snr2 last_snr2_bck;
 
1174
        
 
1175
        search_pattern_bck = LASTSNR2(bfwin->snr2)->search_pattern;
 
1176
        replace_pattern_bck = LASTSNR2(bfwin->snr2)->replace_pattern;
 
1177
        last_snr2_bck = *LASTSNR2(bfwin->snr2);
 
1178
        DEBUG_MSG("snr2..extern..: last_snr2_bck.search_pattern=%p, replace_pattern=%p\n"
 
1179
                ,last_snr2_bck.search_pattern, last_snr2_bck.replace_pattern);
 
1180
 
 
1181
        if (!search_pattern || !replace_pattern || !strlen(search_pattern)) {
 
1182
                DEBUG_MSG("snr2_run_extern, returning, non-valid arguments\n");
 
1183
                return;
 
1184
        }
 
1185
        DEBUG_MSG("snr2..extern..: doc=%p, search_pattern='%s', region=%d, matchtype=%d, is_case_sens=%d, replace_pattern=%s, store_as_last=%d\n"
 
1186
                        ,doc,search_pattern,region,matchtype,is_case_sens,replace_pattern,store_as_last_snr2);
 
1187
        LASTSNR2(bfwin->snr2)->search_pattern = g_strdup(search_pattern);
 
1188
        LASTSNR2(bfwin->snr2)->placetype_option = region;
 
1189
        LASTSNR2(bfwin->snr2)->is_case_sens = is_case_sens;
 
1190
        LASTSNR2(bfwin->snr2)->overlapping_search = 0;
 
1191
        LASTSNR2(bfwin->snr2)->replace = 1;
 
1192
        LASTSNR2(bfwin->snr2)->replace_pattern = g_strdup(replace_pattern);
 
1193
        LASTSNR2(bfwin->snr2)->prompt_before_replace = 0;
 
1194
        LASTSNR2(bfwin->snr2)->replace_once = 0;
 
1195
        LASTSNR2(bfwin->snr2)->unescape = 0;
 
1196
        LASTSNR2(bfwin->snr2)->matchtype_option = matchtype;
 
1197
        LASTSNR2(bfwin->snr2)->replacetype_option = string;
 
1198
        LASTSNR2(bfwin->snr2)->bookmark_results = 0;
 
1199
        snr2_run(BFWIN(doc->bfwin),doc);
 
1200
        if (store_as_last_snr2) {
 
1201
                DEBUG_MSG("free-ing old patterns at %p and %p\n",search_pattern_bck,replace_pattern_bck);
 
1202
                g_free(search_pattern_bck);
 
1203
                g_free(replace_pattern_bck);
745
1204
        } else {
746
 
                if (last_snr2.region_all_open_files) {
747
 
                        DEBUG_MSG("snr2dialog_ok_lcb, search = all\n");
748
 
                        result_all = search_all(last_snr2.pattern, last_snr2.is_regex, last_snr2.is_case_sens);
749
 
                        DEBUG_MSG("snr2dialog_ok_lcb, result_all.doc=%p\n",result_all.doc);
750
 
                        doc_show_result(result_all.doc, result_all.start, result_all.end);
751
 
                } else {
752
 
                        result = search_doc(main_v->current_document, last_snr2.pattern, last_snr2.is_regex, last_snr2.is_case_sens, startpos);
753
 
                        doc_show_result(main_v->current_document, result.start, result.end);    
754
 
                }
 
1205
                g_free(LASTSNR2(bfwin->snr2)->search_pattern);
 
1206
                g_free(LASTSNR2(bfwin->snr2)->replace_pattern);
 
1207
                *LASTSNR2(bfwin->snr2) = last_snr2_bck;
755
1208
        }
756
1209
}
757
1210
 
758
 
/*****************************************************/
759
 
 
760
 
static void snr2dialog_destroy_lcb(GtkWidget *widget, GdkEvent *event, gpointer data) {
 
1211
/**
 
1212
 * doc_search_run_extern:
 
1213
 * @doc: a #Tdocument
 
1214
 * @search_pattern: #gchar search pattern
 
1215
 * @matchtype: #gint, 0 = normal, 1 = posix, 2 = perl
 
1216
 * @is_case_sens: #gint, case sensitive pattern?
 
1217
 *
 
1218
 * Frontend for search_doc, calling it with supplied arguments and startpos = 0.
 
1219
 * 
 
1220
 * Return value: #Tsearch_result_doc
 
1221
 **/
 
1222
Tsearch_result doc_search_run_extern(Tdocument *doc, gchar *search_pattern, gint matchtype, gint is_case_sens) {
 
1223
        return search_doc(BFWIN(doc->bfwin),doc, search_pattern, matchtype, is_case_sens, 0, FALSE);
 
1224
 
1225
 
 
1226
/******************************************************/
 
1227
/*        Search and replace dialogs callbacks        */
 
1228
/******************************************************/
 
1229
 
 
1230
static void snr2dialog_destroy_lcb(GtkWidget *widget, gpointer data) {
 
1231
        DEBUG_MSG("snr2dialog_destroy_lcb, started, about to call window_destroy\n");
761
1232
        window_destroy(((Tsnr2_win *)data)->window);
 
1233
        DEBUG_MSG("snr2dialog_destroy_lcb, about to free data %p\n", data);
762
1234
        g_free(data);
 
1235
        DEBUG_MSG("snr2dialog_destroy_lcb, done\n");
763
1236
}
764
1237
 
765
1238
static void snr2dialog_cancel_lcb(GtkWidget *widget, gpointer data) {
766
 
        snr2dialog_destroy_lcb(NULL, NULL, data);
767
 
}
768
 
 
769
 
static void snr2dialog_replacetype_toggled(GtkWidget *widget, Tsnr2_win *data) {
770
 
        gtk_entry_set_editable(GTK_ENTRY(data->replace_string), gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->replacetype_string)));
 
1239
        snr2dialog_destroy_lcb(NULL, data);
771
1240
}
772
1241
 
773
1242
/*****************************************************/
774
1243
 
 
1244
/*
 
1245
 * Sets the last_snr2 as specified by the user and calls snr2_run(NULL) (aka, run on current document)
 
1246
 */
775
1247
static void snr2dialog_ok_lcb(GtkWidget *widget, Tsnr2_win *data) {
776
 
        if (last_snr2.pattern) {
777
 
                g_free(last_snr2.pattern);
778
 
                last_snr2.pattern = NULL;
779
 
        }
780
 
        if (last_snr2.replace_string) {
781
 
                g_free(last_snr2.replace_string);
782
 
                last_snr2.replace_string = NULL;
783
 
        }
784
 
        last_snr2.pattern = gtk_editable_get_chars(GTK_EDITABLE(data->pattern), 0, -1);
785
 
        last_snr2.region_from_beginning = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->region_from_beginning));
786
 
        last_snr2.region_from_cursor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->region_from_cursor));
787
 
        last_snr2.region_selection = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->region_selection));
788
 
        last_snr2.region_all_open_files = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->region_all_open_files));
789
 
        last_snr2.is_regex = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->is_regex));
790
 
        last_snr2.is_case_sens = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->is_case_sens));
791
 
        last_snr2.overlapping_search = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->overlapping_search));
 
1248
        /*GtkTextIter itstart, itend;
 
1249
        GtkTextBuffer *buf;*/
 
1250
        Tbfwin *bfwin = data->bfwin;
 
1251
        if (LASTSNR2(bfwin->snr2)->search_pattern) {
 
1252
                g_free(LASTSNR2(bfwin->snr2)->search_pattern);
 
1253
                LASTSNR2(bfwin->snr2)->search_pattern = NULL;
 
1254
        }
 
1255
        if (LASTSNR2(bfwin->snr2)->replace_pattern) {
 
1256
                g_free(LASTSNR2(bfwin->snr2)->replace_pattern);
 
1257
                LASTSNR2(bfwin->snr2)->replace_pattern = NULL;
 
1258
        }
 
1259
        /*buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data->search_entry));
 
1260
        gtk_text_buffer_get_bounds(buf,&itstart,&itend);
 
1261
        LASTSNR2(bfwin->snr2)->search_pattern = gtk_text_buffer_get_text(buf,&itstart,&itend, FALSE);*/
 
1262
        LASTSNR2(bfwin->snr2)->search_pattern = gtk_editable_get_chars(GTK_EDITABLE(GTK_COMBO(data->search_combo)->entry),0,-1);
 
1263
        
 
1264
        data->bfwin->session->searchlist = add_to_history_stringlist(data->bfwin->session->searchlist,LASTSNR2(bfwin->snr2)->search_pattern,TRUE,TRUE);
 
1265
        
 
1266
        LASTSNR2(bfwin->snr2)->unescape = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->unescape));
 
1267
        LASTSNR2(bfwin->snr2)->is_case_sens = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->is_case_sens));
 
1268
        LASTSNR2(bfwin->snr2)->overlapping_search = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->overlapping_search));
792
1269
        if (data->replace) {
793
 
                last_snr2.replace = 1;
794
 
                last_snr2.replace_string = gtk_editable_get_chars(GTK_EDITABLE(data->replace_string), 0, -1);
795
 
                last_snr2.prompt_before_replacing = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->prompt_before_replacing));
796
 
                last_snr2.replace_once = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->replace_once));
797
 
                last_snr2.replacetype_string = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->replacetype_string)));
798
 
                last_snr2.replacetype_upcase = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->replacetype_upcase)));
799
 
                last_snr2.replacetype_lowcase = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->replacetype_lowcase)));
 
1270
                /*GtkTextIter itstart, itend;
 
1271
                GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data->replace_entry));
 
1272
                gtk_text_buffer_get_bounds(buf,&itstart,&itend);
 
1273
                LASTSNR2(bfwin->snr2)->replace_pattern = gtk_text_buffer_get_text(buf,&itstart,&itend, FALSE);*/
 
1274
                LASTSNR2(bfwin->snr2)->replace = 1;
 
1275
                LASTSNR2(bfwin->snr2)->replace_pattern = gtk_editable_get_chars(GTK_EDITABLE(GTK_COMBO(data->replace_combo)->entry),0,-1);
 
1276
                
 
1277
                data->bfwin->session->replacelist = add_to_history_stringlist(data->bfwin->session->replacelist,LASTSNR2(bfwin->snr2)->replace_pattern,TRUE,TRUE);
 
1278
                
 
1279
                LASTSNR2(bfwin->snr2)->prompt_before_replace = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->prompt_before_replace));
 
1280
                LASTSNR2(bfwin->snr2)->replace_once = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->replace_once));
800
1281
        } else {
801
 
                last_snr2.replace = 0;
 
1282
                LASTSNR2(bfwin->snr2)->replace = 0;
 
1283
                LASTSNR2(bfwin->snr2)->bookmark_results = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->bookmark_results));
802
1284
        }
803
1285
        window_destroy(data->window);
804
1286
        g_free(data);
805
1287
 
806
 
        snr2_run();
807
 
}
808
 
 
809
 
/* void snr2_run_extern_replace
810
 
arguments are translated to last_snr2 like this:
811
 
pattern = patten
812
 
region,  0 = region_from_beginning, 
813
 
                        1 = region_from_cursor, 
814
 
                        2 = region_selection,
815
 
                        3 = region_all_open_files
816
 
is_regex = is_regex
817
 
is_case_sens = is_case_sens
818
 
overlapping_search is off
819
 
replace = 1
820
 
replace_string = replace_string
821
 
prompt_before_replacing = off
822
 
replace_once = off
823
 
replacetype_string = 1
824
 
replacetype_upcase = 0
825
 
replacetype_lowcase = 0
826
 
*/
827
 
void snr2_run_extern_replace(gchar *pattern, gint region,
828
 
                                                        gint is_regex, gint is_case_sens, gchar *replace_string) {
829
 
        if (!pattern || !replace_string || !strlen(pattern)) {
830
 
                DEBUG_MSG("snr2_run_extern, returning, non-valid arguments\n");
831
 
                return;
832
 
        }
833
 
        if (last_snr2.pattern) {
834
 
                g_free(last_snr2.pattern);
835
 
                last_snr2.pattern = NULL;
836
 
        }
837
 
        if (last_snr2.replace_string) {
838
 
                g_free(last_snr2.replace_string);
839
 
                last_snr2.replace_string = NULL;
840
 
        }
841
 
        last_snr2.pattern = g_strdup(pattern);
842
 
        last_snr2.region_from_beginning = region == 0 ? 1: 0;
843
 
        last_snr2.region_from_cursor = region == 1 ? 1: 0;
844
 
        last_snr2.region_selection = region == 2 ? 1: 0;
845
 
        last_snr2.region_all_open_files = region == 3 ? 1: 0;
846
 
        last_snr2.is_regex = is_regex;
847
 
        last_snr2.is_case_sens = is_case_sens;
848
 
        last_snr2.overlapping_search = 0;
849
 
        last_snr2.replace = 1;
850
 
        last_snr2.replace_string = g_strdup(replace_string);
851
 
        last_snr2.prompt_before_replacing = 0;
852
 
        last_snr2.replace_once = 0;
853
 
        last_snr2.replacetype_string = 1;
854
 
        last_snr2.replacetype_upcase = 0;
855
 
        last_snr2.replacetype_lowcase = 0;
856
 
 
857
 
        snr2_run();
858
 
}
859
 
 
860
 
static void snr2dialog(gint is_replace, gint is_new_search) {
861
 
 
 
1288
        snr2_run(bfwin,NULL);
 
1289
}
 
1290
 
 
1291
static void placetype_changed_lcb(GtkWidget *widget, Tsnr2_win *snr2win) {
 
1292
        LASTSNR2(snr2win->bfwin->snr2)->placetype_option =  gtk_option_menu_get_history((GtkOptionMenu *) snr2win->placetype_option);
 
1293
        DEBUG_MSG("placetype_changed_lcb, changing option to %d\n", LASTSNR2(snr2win->bfwin->snr2)->placetype_option);
 
1294
}       
 
1295
 
 
1296
static void matchtype_changed_lcb(GtkWidget *widget, Tsnr2_win *snr2win) {
 
1297
        LASTSNR2(snr2win->bfwin->snr2)->matchtype_option =  gtk_option_menu_get_history((GtkOptionMenu *) snr2win->matchtype_option);
 
1298
        if (snr2win->replace) {
 
1299
                if (LASTSNR2(snr2win->bfwin->snr2)->matchtype_option==0) {
 
1300
                        gtk_widget_hide(snr2win->subpat_help);
 
1301
                }
 
1302
                else {
 
1303
                        gtk_widget_show(snr2win->subpat_help);
 
1304
                }
 
1305
        }
 
1306
        DEBUG_MSG("matchtype_changed_lcb, changing option to %d\n", LASTSNR2(snr2win->bfwin->snr2)->matchtype_option);
 
1307
}       
 
1308
 
 
1309
static void replacetype_changed_lcb(GtkWidget *widget, Tsnr2_win *snr2win) {
 
1310
        LASTSNR2(snr2win->bfwin->snr2)->replacetype_option =  gtk_option_menu_get_history((GtkOptionMenu *) snr2win->replacetype_option);
 
1311
        /*gtk_widget_set_sensitive(snr2win->replace_entry, LASTSNR2(snr2win->bfwin->snr2)->replacetype_option==0);*/
 
1312
        gtk_widget_set_sensitive(snr2win->replace_combo, LASTSNR2(snr2win->bfwin->snr2)->replacetype_option==0);
 
1313
        DEBUG_MSG("replacetype_changed_lcb, changing option to %d\n", LASTSNR2(snr2win->bfwin->snr2)->replacetype_option);
 
1314
}
 
1315
/*
 
1316
static gboolean search_entry_key_press_event_lcb(GtkWidget *widget,GdkEventKey *event,Tsnr2_win *snr2win) {
 
1317
        if ((event->state & GDK_CONTROL_MASK) && (event->keyval == GDK_Return)) {
 
1318
                snr2dialog_ok_lcb(NULL, snr2win);
 
1319
                return TRUE;
 
1320
        }
 
1321
        return FALSE;
 
1322
}*/
 
1323
 
 
1324
static void snr2dialog(Tbfwin *bfwin, gint is_replace, gint is_new_search) {
862
1325
        Tsnr2_win *snr2win;
863
 
        GtkWidget *vbox, *hbox, *vbox2, *vbox3, *frame, *but;
 
1326
        GtkWidget *vbox, *hbox, *button, *table;
864
1327
        gchar *tmptext;
865
1328
 
866
1329
        snr2win = g_malloc(sizeof(Tsnr2_win));
 
1330
        snr2win->bfwin = bfwin;
867
1331
        if (is_replace) {
868
1332
                tmptext = _("Replace");
869
1333
                snr2win->replace = 1;
870
1334
        } else {
871
 
                tmptext = _("Search");
 
1335
                tmptext = _("Find");
872
1336
                snr2win->replace = 0;
873
1337
        }
874
1338
        if (is_new_search) {
875
 
                reset_last_snr2();
 
1339
                reset_last_snr2(bfwin);
876
1340
        } else {
877
 
                last_snr2.result.start = -1;
878
 
                last_snr2.result.end = -1;
879
 
                last_snr2.doc = NULL;
 
1341
                LASTSNR2(bfwin->snr2)->result.start = -1;
 
1342
                LASTSNR2(bfwin->snr2)->result.end = -1;
 
1343
                LASTSNR2(bfwin->snr2)->doc = NULL;
880
1344
        }
881
 
        snr2win->window = window_full(tmptext, GTK_WIN_POS_MOUSE, GTK_WINDOW_DIALOG
882
 
                                                , 5, snr2dialog_destroy_lcb, snr2win);
883
 
        gtk_window_set_wmclass(GTK_WINDOW(snr2win->window), "Bluefish", "snr");
884
 
        vbox = gtk_vbox_new(FALSE, 1);
 
1345
        snr2win->window = window_full(tmptext, GTK_WIN_POS_MOUSE, 12, G_CALLBACK(snr2dialog_destroy_lcb), snr2win, TRUE);
 
1346
        gtk_window_set_role(GTK_WINDOW(snr2win->window), "snr");
 
1347
        vbox = gtk_vbox_new(FALSE, 0);
885
1348
        gtk_container_add(GTK_CONTAINER(snr2win->window), vbox);
886
 
        
887
 
        hbox = gtk_hbox_new(FALSE,0);
888
 
        gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
889
 
        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Find: ")), FALSE, FALSE, 0);
890
 
        snr2win->pattern = boxed_entry_with_text(last_snr2.pattern, 0, hbox);
891
 
        gtk_widget_set_usize(snr2win->pattern, 300, -1);
892
 
 
893
 
        frame = gtk_frame_new(_("Where"));
894
 
        gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
895
 
        vbox2 = gtk_vbox_new(TRUE, 0);
896
 
        gtk_container_add(GTK_CONTAINER(frame), vbox2);
897
 
        snr2win->region_from_beginning = boxed_radiobut_with_value(_("Start at beginning of document"), last_snr2.region_from_beginning, NULL, vbox2);
898
 
        snr2win->region_from_cursor = boxed_radiobut_with_value(_("Start at cursor position"), last_snr2.region_from_cursor, GTK_RADIO_BUTTON(snr2win->region_from_beginning),  vbox2);
899
 
        snr2win->region_selection = boxed_radiobut_with_value(_("In selection"), last_snr2.region_selection, GTK_RADIO_BUTTON(snr2win->region_from_cursor), vbox2);
900
 
        snr2win->region_all_open_files = boxed_radiobut_with_value(_("In all open files"), last_snr2.region_all_open_files, GTK_RADIO_BUTTON(snr2win->region_selection), vbox2);
901
 
        
902
 
        snr2win->is_case_sens = boxed_checkbut_with_value(_("Case sensitive"), last_snr2.is_case_sens, vbox);
903
 
        snr2win->is_regex = boxed_checkbut_with_value(_("Use regular expression matching"), last_snr2.is_regex, vbox);
904
 
        snr2win->overlapping_search = boxed_checkbut_with_value(_("Overlapping searches"), last_snr2.overlapping_search, vbox);
905
 
        if (is_replace) {
906
 
                frame = gtk_frame_new(_("Replace"));
907
 
                gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
908
 
                vbox2 = gtk_vbox_new(FALSE, 3);
909
 
                gtk_container_add(GTK_CONTAINER(frame), vbox2);
 
1349
 
 
1350
        if (is_replace) {
 
1351
                table = gtk_table_new (2, 2, FALSE);
 
1352
        }
 
1353
        else {
 
1354
                table = gtk_table_new (1, 2, FALSE);
 
1355
        }
 
1356
        gtk_widget_show (table);
 
1357
        gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
 
1358
        gtk_table_set_row_spacings (GTK_TABLE (table), 12);
 
1359
        gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
1360
 
 
1361
        snr2win->search_label = gtk_label_new_with_mnemonic(_("_Search for: "));
 
1362
        gtk_table_attach (GTK_TABLE (table), snr2win->search_label, 0, 1, 0, 1,
 
1363
                                        (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 2, 0);
 
1364
        gtk_label_set_justify (GTK_LABEL (snr2win->search_label), GTK_JUSTIFY_LEFT);
 
1365
        gtk_misc_set_alignment (GTK_MISC (snr2win->search_label), 0, 0.5);
 
1366
        /*snr2win->search_scrollbox = textview_buffer_in_scrolwin(&snr2win->search_entry, 300, 50, LASTSNR2(bfwin->snr2)->search_pattern, GTK_WRAP_NONE);*/
 
1367
        
 
1368
        snr2win->search_combo = combo_with_popdown("", bfwin->session->searchlist, TRUE);
 
1369
        gtk_table_attach (GTK_TABLE (table), snr2win->search_combo, 1, 2, 0, 1,
 
1370
                                        (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0);
 
1371
        /*g_signal_connect(G_OBJECT(snr2win->search_entry), "key_press_event", G_CALLBACK(search_entry_key_press_event_lcb), snr2win);*/
 
1372
 
 
1373
        if (is_replace) {
 
1374
                snr2win->replace_label = gtk_label_new_with_mnemonic(_("_Replace with: "));
 
1375
                gtk_table_attach (GTK_TABLE (table), snr2win->replace_label, 0, 1, 1, 2,
 
1376
                                                (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 2, 0);
 
1377
                gtk_label_set_justify (GTK_LABEL (snr2win->replace_label), GTK_JUSTIFY_LEFT);
 
1378
                gtk_misc_set_alignment (GTK_MISC (snr2win->replace_label), 0, 0.5);
 
1379
                /*snr2win->replace_scrollbox = textview_buffer_in_scrolwin(&snr2win->replace_entry, 300, 50, LASTSNR2(bfwin->snr2)->replace_pattern, GTK_WRAP_NONE);*/
 
1380
                snr2win->replace_combo = combo_with_popdown("", bfwin->session->replacelist, TRUE);
 
1381
                gtk_table_attach (GTK_TABLE (table), snr2win->replace_combo, 1, 2, 1, 2,
 
1382
                                                (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0);
 
1383
                /*g_signal_connect(G_OBJECT(snr2win->replace_entry), "key_press_event", G_CALLBACK(search_entry_key_press_event_lcb), snr2win);*/
 
1384
                snr2win->subpat_help = gtk_label_new(_("\\0 refers to the first subsearch_pattern, \\1 to the second etc."));
 
1385
                gtk_box_pack_start(GTK_BOX(vbox), snr2win->subpat_help, FALSE, TRUE, 6);
 
1386
                gtk_label_set_justify (GTK_LABEL (snr2win->subpat_help), GTK_JUSTIFY_LEFT);
 
1387
                gtk_misc_set_alignment (GTK_MISC (snr2win->subpat_help), 1, 0.5);
 
1388
        }
 
1389
 
 
1390
        if (is_replace) {
 
1391
                table = gtk_table_new (3, 2, FALSE);
 
1392
        } else {
 
1393
                table = gtk_table_new (2, 2, FALSE);
 
1394
        }
 
1395
        gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 12);
 
1396
        gtk_table_set_row_spacings (GTK_TABLE (table), 12);
 
1397
        gtk_table_set_col_spacings (GTK_TABLE (table), 6);
 
1398
        {
 
1399
                gchar *placeactions[] = {N_("Beginning of document till end"), N_("Current position till end"), N_("Beginning of selection till end of selection"), N_("All opened files begin till end"), NULL};
 
1400
                gchar *matchactions[] = {N_("Disabled"), N_("POSIX type"),      N_("PERL type"), NULL};
 
1401
                GtkWidget *matchlabel, *placelabel = gtk_label_new(_("Starts at:"));
 
1402
                DEBUG_MSG("snr2dialog, LASTSNR2(bfwin->snr2)->placetype_option=%d\n", LASTSNR2(bfwin->snr2)->placetype_option);
 
1403
                snr2win->placetype_option = optionmenu_with_value(placeactions, LASTSNR2(bfwin->snr2)->placetype_option);
 
1404
 
 
1405
                gtk_table_attach (GTK_TABLE (table), placelabel, 0, 1, 0, 1,
 
1406
                                                (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 2, 0);
 
1407
                gtk_label_set_justify (GTK_LABEL (placelabel), GTK_JUSTIFY_LEFT);
 
1408
                gtk_misc_set_alignment (GTK_MISC (placelabel), 0, 0.5);
 
1409
                gtk_table_attach (GTK_TABLE (table), snr2win->placetype_option, 1, 2, 0, 1, 
 
1410
                                                (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0);
 
1411
                g_signal_connect(G_OBJECT((GtkWidget *) snr2win->placetype_option), "changed", G_CALLBACK(placetype_changed_lcb), snr2win);
910
1412
                
911
 
                hbox = gtk_hbox_new(FALSE,0);
912
 
                gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0);
913
 
                gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(_("Replace with: ")), FALSE, FALSE, 0);
914
 
                snr2win->replace_string = boxed_entry_with_text(last_snr2.replace_string, 0, hbox);
915
 
                if (last_snr2.replacetype_upcase || last_snr2.replacetype_lowcase) {
916
 
                        gtk_entry_set_editable(GTK_ENTRY(snr2win->replace_string), 0);
 
1413
                matchlabel = gtk_label_new(_("Regular expression:"));
 
1414
                DEBUG_MSG("snr2dialog, LASTSNR2(bfwin->snr2)->matchtype_option=%d\n", LASTSNR2(bfwin->snr2)->matchtype_option);
 
1415
                snr2win->matchtype_option = optionmenu_with_value(matchactions, LASTSNR2(bfwin->snr2)->matchtype_option);
 
1416
 
 
1417
                gtk_table_attach (GTK_TABLE (table), matchlabel, 0, 1, 1, 2,
 
1418
                                                (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 2, 0);
 
1419
                gtk_label_set_justify (GTK_LABEL (matchlabel), GTK_JUSTIFY_LEFT);
 
1420
                gtk_misc_set_alignment (GTK_MISC (matchlabel), 0, 0.5);
 
1421
                gtk_table_attach (GTK_TABLE (table), snr2win->matchtype_option, 1, 2, 1, 2, 
 
1422
                                                (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0);
 
1423
                g_signal_connect(G_OBJECT((GtkWidget *) snr2win->matchtype_option), "changed", G_CALLBACK(matchtype_changed_lcb), snr2win);
 
1424
 
 
1425
 
 
1426
                if (is_replace) {
 
1427
                        gchar *replaceactions[] = {N_("Normal"), N_("Uppercase"),       N_("Lowercase"), NULL};
 
1428
                        GtkWidget *replacelabel = gtk_label_new(_("Replace type:"));
 
1429
                        DEBUG_MSG("snr2dialog, LASTSNR2(bfwin->snr2)->replacetype_option=%d\n", LASTSNR2(bfwin->snr2)->replacetype_option);
 
1430
                        snr2win->replacetype_option = optionmenu_with_value(replaceactions, LASTSNR2(bfwin->snr2)->replacetype_option);
 
1431
        
 
1432
                        gtk_table_attach (GTK_TABLE (table), replacelabel, 0, 1, 2, 3, 
 
1433
                                                        (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 2, 0);
 
1434
                        gtk_label_set_justify (GTK_LABEL (replacelabel), GTK_JUSTIFY_LEFT);
 
1435
                        gtk_misc_set_alignment (GTK_MISC (replacelabel), 0, 0.5);
 
1436
                        gtk_table_attach (GTK_TABLE (table), snr2win->replacetype_option, 1, 2, 2, 3, 
 
1437
                                                        (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0);
 
1438
                        g_signal_connect(G_OBJECT((GtkWidget *) snr2win->replacetype_option), "changed", G_CALLBACK(replacetype_changed_lcb), snr2win);
917
1439
                }
918
 
                hbox = gtk_hbox_new(TRUE,3);
919
 
                gtk_box_pack_start(GTK_BOX(vbox2), hbox, TRUE, TRUE, 3);
920
 
 
921
 
                vbox3 = gtk_vbox_new(TRUE,3);
922
 
                gtk_box_pack_start(GTK_BOX(hbox), vbox3, TRUE, TRUE, 3);        
923
 
                
924
 
                snr2win->replacetype_string = boxed_radiobut_with_value(_("Replace text"), last_snr2.replacetype_string, NULL, vbox3);
925
 
                snr2win->replacetype_upcase = boxed_radiobut_with_value(_("Replace uppercase"), last_snr2.replacetype_upcase, GTK_RADIO_BUTTON(snr2win->replacetype_string), vbox3);
926
 
                snr2win->replacetype_lowcase = boxed_radiobut_with_value(_("Replace lowercase"), last_snr2.replacetype_lowcase, GTK_RADIO_BUTTON(snr2win->replacetype_string), vbox3);
927
 
 
928
 
                vbox3 = gtk_vbox_new(TRUE,3);
929
 
                gtk_box_pack_start(GTK_BOX(hbox), vbox3, TRUE, TRUE, 3);        
930
 
                snr2win->prompt_before_replacing = boxed_checkbut_with_value(_("Prompt before replacing"), last_snr2.prompt_before_replacing, vbox3);
931
 
                snr2win->replace_once = boxed_checkbut_with_value(_("Replace once"), last_snr2.replace_once, vbox3);
932
 
                gtk_signal_connect(GTK_OBJECT(snr2win->replacetype_string), "toggled", 
933
 
                                snr2dialog_replacetype_toggled, snr2win);
934
 
        }
 
1440
        }
 
1441
        snr2win->unescape = boxed_checkbut_with_value(_("_Patterns contain backslash escape sequences (\\n, \\t)"), LASTSNR2(bfwin->snr2)->unescape, vbox);
 
1442
        snr2win->is_case_sens = boxed_checkbut_with_value(_("_Match case"), LASTSNR2(bfwin->snr2)->is_case_sens, vbox);
 
1443
        snr2win->overlapping_search = boxed_checkbut_with_value(_("O_verlap searches"), LASTSNR2(bfwin->snr2)->overlapping_search, vbox);
 
1444
        if (is_replace) {
 
1445
                snr2win->prompt_before_replace = boxed_checkbut_with_value(_("Prompt _before replace"), LASTSNR2(bfwin->snr2)->prompt_before_replace, vbox);
 
1446
                snr2win->replace_once = boxed_checkbut_with_value(_("Replace o_nce"), LASTSNR2(bfwin->snr2)->replace_once, vbox);
 
1447
        } else {
 
1448
                snr2win->bookmark_results = boxed_checkbut_with_value(_("Bookmark results"), LASTSNR2(bfwin->snr2)->bookmark_results, vbox);
 
1449
        }
 
1450
 
 
1451
        hbox = gtk_hseparator_new ();
 
1452
        gtk_widget_show (hbox);
 
1453
        gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 12);
 
1454
 
935
1455
        hbox = gtk_hbutton_box_new();
936
1456
        gtk_hbutton_box_set_layout_default(GTK_BUTTONBOX_END);
937
 
        gtk_button_box_set_spacing(GTK_BUTTON_BOX(hbox), 1);
938
 
        gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
939
 
 
940
 
        but = bf_stock_ok_button(snr2dialog_ok_lcb, snr2win);
941
 
        gtk_box_pack_start(GTK_BOX(hbox), but, TRUE, TRUE, 0);
942
 
        gtk_window_set_default(GTK_WINDOW(snr2win->window), but);
943
 
        gtk_box_pack_start(GTK_BOX(hbox), bf_stock_cancel_button(snr2dialog_cancel_lcb, snr2win), TRUE, TRUE, 0);
944
 
        
945
 
        gtk_widget_grab_focus(snr2win->pattern);
946
 
        gtk_widget_show_all(snr2win->window);
947
 
        
948
 
}
949
 
 
950
 
/*****************************************************/
951
 
 
952
 
void search_cb(GtkWidget *widget, gpointer data) {
953
 
        snr2dialog(0, 0);
954
 
}
955
 
 
956
 
void new_search_cb(GtkWidget *widget, gpointer data) {
957
 
        snr2dialog(0, 1);
958
 
}
959
 
 
960
 
void search_again_cb(GtkWidget *widget, gpointer data) {
961
 
        snr2_run();     
962
 
}
963
 
 
964
 
void replace_again_cb(GtkWidget *widget, gpointer data) {
965
 
        snr2_run();
966
 
}
967
 
 
968
 
void replace_cb(GtkWidget *widget, gpointer data) {
969
 
        snr2dialog(1, 0);
970
 
}
971
 
 
972
 
void new_replace_cb(GtkWidget *widget, gpointer data) {
973
 
        snr2dialog(1, 1);
974
 
}
975
 
 
976
 
/*****************************************************/
 
1457
        gtk_button_box_set_spacing(GTK_BUTTON_BOX(hbox), 6);
 
1458
        gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
 
1459
 
 
1460
        gtk_box_pack_start(GTK_BOX(hbox), bf_stock_cancel_button(G_CALLBACK(snr2dialog_cancel_lcb), snr2win), FALSE, TRUE, 0);
 
1461
        button = bf_stock_ok_button(G_CALLBACK(snr2dialog_ok_lcb), snr2win);
 
1462
        gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, TRUE, 0);
 
1463
        gtk_window_set_default(GTK_WINDOW(snr2win->window), button);
 
1464
        
 
1465
        gtk_label_set_mnemonic_widget(GTK_LABEL(snr2win->search_label), GTK_COMBO(snr2win->search_combo)->entry);
 
1466
        if(is_replace) {
 
1467
                gtk_label_set_mnemonic_widget(GTK_LABEL(snr2win->replace_label), GTK_COMBO(snr2win->replace_combo)->entry);
 
1468
        }
 
1469
        gtk_widget_grab_focus(snr2win->search_combo);
 
1470
        gtk_widget_show_all(vbox);
 
1471
 
 
1472
        gtk_widget_show(snr2win->window);
 
1473
/*      {
 
1474
                GtkTextIter itstart, itend;
 
1475
                gtk_text_buffer_get_bounds(gtk_text_view_get_buffer(GTK_TEXT_VIEW(snr2win->search_entry)),&itstart,&itend);
 
1476
                gtk_text_buffer_move_mark_by_name(gtk_text_view_get_buffer(GTK_TEXT_VIEW(snr2win->search_entry)),"insert",&itstart);
 
1477
                gtk_text_buffer_move_mark_by_name(gtk_text_view_get_buffer(GTK_TEXT_VIEW(snr2win->search_entry)),"selection_bound",&itend);
 
1478
        }*/
 
1479
        
 
1480
        if (is_replace) {
 
1481
                matchtype_changed_lcb(NULL, snr2win);
 
1482
                replacetype_changed_lcb(NULL, snr2win);
 
1483
        }
 
1484
}
 
1485
 
 
1486
/*****************************************************/
 
1487
 
 
1488
void search_from_selection(Tbfwin *bfwin) {
 
1489
        gchar *string;
 
1490
        GtkClipboard* cb;
 
1491
 
 
1492
        cb = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
 
1493
        string = gtk_clipboard_wait_for_text(cb);
 
1494
        if (string) {
 
1495
                if (LASTSNR2(bfwin->snr2)->search_pattern) {
 
1496
                        g_free(LASTSNR2(bfwin->snr2)->search_pattern);
 
1497
                }
 
1498
                if (LASTSNR2(bfwin->snr2)->replace_pattern) {
 
1499
                        g_free(LASTSNR2(bfwin->snr2)->replace_pattern);
 
1500
                        LASTSNR2(bfwin->snr2)->replace_pattern = NULL;
 
1501
                }
 
1502
                LASTSNR2(bfwin->snr2)->search_pattern = string;
 
1503
                LASTSNR2(bfwin->snr2)->placetype_option = 0;
 
1504
                LASTSNR2(bfwin->snr2)->is_case_sens = 1;
 
1505
                LASTSNR2(bfwin->snr2)->overlapping_search = 0;
 
1506
                LASTSNR2(bfwin->snr2)->replace = 0;
 
1507
                LASTSNR2(bfwin->snr2)->matchtype_option = 0;
 
1508
                snr2_run(bfwin,bfwin->current_document);
 
1509
        }
 
1510
}
 
1511
 
 
1512
/**
 
1513
 * search_cb:
 
1514
 * @widget: unused #GtkWidget*
 
1515
 * @data: unused #gpointer
 
1516
 * 
 
1517
 * Show the search-dialog.
 
1518
 * 
 
1519
 * Return value: void
 
1520
 **/
 
1521
void search_cb(GtkWidget *widget, Tbfwin *bfwin) {
 
1522
        snr2dialog(bfwin, 0, 0);
 
1523
}
 
1524
 
 
1525
/**
 
1526
 * search_again_cb:
 
1527
 * @widget: unused #GtkWidget*
 
1528
 * @data: unused #gpointer
 
1529
 * 
 
1530
 * Repeat last search, if any.
 
1531
 * 
 
1532
 * Return value: void
 
1533
 **/ 
 
1534
void search_again_cb(GtkWidget *widget, Tbfwin *bfwin) {
 
1535
        snr2_run(bfwin,NULL);   
 
1536
}
 
1537
 
 
1538
/**
 
1539
 * replace_again_cb:
 
1540
 * @widget: unused #GtkWidget*
 
1541
 * @data: unused #gpointer
 
1542
 * 
 
1543
 * Repeat last replace, if any.
 
1544
 * 
 
1545
 * Return value: void
 
1546
 **/ 
 
1547
void replace_again_cb(GtkWidget *widget, Tbfwin *bfwin) {
 
1548
        snr2_run(bfwin,NULL);
 
1549
}
 
1550
 
 
1551
/**
 
1552
 * replace_cb:
 
1553
 * @widget: unused #GtkWidget*
 
1554
 * @data: unused #gpointer
 
1555
 * 
 
1556
 * Show replace dialog.
 
1557
 * 
 
1558
 * Return value: void
 
1559
 **/ 
 
1560
void replace_cb(GtkWidget *widget, Tbfwin *bfwin) {
 
1561
        snr2dialog(bfwin, 1, 0);
 
1562
}
 
1563
 
 
1564
/*****************************************************/
 
1565
 
 
1566
#ifdef NOTPORTEDYET
977
1567
 
978
1568
static gint do_filename_curfile_replace(gchar *fulltext, Tsearch_result result, gint offset, gchar *olddirname, gchar *newfilename, gint changelen, Tdocument *doc) {
979
1569
/* returns the change in the lenght of the buffer compared to the actual document text */
991
1581
        /* code to check if this is a file */
992
1582
        if (file_exists_and_readable(olddirfile)) {
993
1583
                DEBUG_MSG("do_filename_change_replace, olddirfile=%s does exist!!\n", olddirfile);
994
 
                /* code to create replace_string */
 
1584
                /* code to create replace_pattern */
995
1585
                olddirfile = most_efficient_filename(olddirfile);
996
1586
                DEBUG_MSG("do_filename_change_replace, updated olddirfile=%s \n", olddirfile);
997
1587
                replacestring = create_relative_link_to(newfilename, olddirfile);
998
1588
                DEBUG_MSG("do_filename_change_replace, replacestring=%s, newfilename=%s\n", replacestring, newfilename);
999
1589
                /* code to actual replace it */
1000
 
                doc_replace_text(replacestring, result.start + offset + 1 + changelen, result.end + offset + changelen -1, doc);        
 
1590
                doc_replace_text(doc, replacestring, result.start + offset + 1 + changelen, result.end + offset + changelen -1);        
1001
1591
                change_lenght = strlen(replacestring) - strlen(possible_filename) + changelen;
1002
1592
                DEBUG_MSG("do_filename_change_replace, replacestring=%s, possible_filename=%s\n", replacestring, possible_filename);
1003
1593
                DEBUG_MSG("do_filename_change_replace, change_lenght=%d\n",change_lenght );             
1004
1594
                g_free(replacestring); 
1005
1595
        } else {
1006
 
/*              DEBUG_MSG("do_filename_change_replace, olddirfile=%s does NOT exist\n", olddirfile);  */
 
1596
                DEBUG_MSG("do_filename_change_replace, olddirfile=%s does NOT exist\n", olddirfile);  
1007
1597
        }
1008
1598
        g_free(possible_filename);
1009
1599
        g_free(olddirfile);
1023
1613
        if (strcmp(possible_filename, oldfilename) == 0) {
1024
1614
                eff_my_filename = most_efficient_filename(g_strdup(doc->filename));
1025
1615
                replacestring = create_relative_link_to(eff_my_filename, newfilename);
1026
 
                doc_replace_text(replacestring, result.start + offset + 1 + changelen, result.end + offset + changelen -1, doc);
 
1616
                doc_replace_text(doc, replacestring, result.start + offset + 1 + changelen, result.end + offset + changelen -1);
1027
1617
                change_length = strlen(replacestring) - strlen(possible_filename) + changelen;          
1028
1618
                g_free(eff_my_filename);
1029
1619
                g_free(replacestring);
1032
1622
        return change_length;
1033
1623
}
1034
1624
 
 
1625
/**
 
1626
 * update_filenames_in_file:
 
1627
 * @doc: a #Tdocument
 
1628
 * @oldfilename: Filename to change from.
 
1629
 * @newfilename: Filename to change to.
 
1630
 * @doc_has_newfilename: If *doc (blabla?)
 
1631
 * 
 
1632
 * 
 
1633
 *
 
1634
 * Return value: void
 
1635
 **/
1035
1636
void update_filenames_in_file(Tdocument *doc, gchar *oldfilename, gchar *newfilename, gint doc_has_newfilename) {
1036
1637
        gchar *fulltext;
1037
1638
        Tsearch_result result;
1038
1639
        gint cur_offset, changelen=0;
1039
 
        gchar *pattern;
1040
 
        gint is_regex, is_case_sens;
 
1640
        gchar *search_pattern;
 
1641
        Tmatch_types matchtype;
 
1642
        gint is_case_sens;
1041
1643
        gchar *olddirname=NULL;
1042
1644
 
1043
1645
        if ((oldfilename == NULL)|| (newfilename == NULL)) {
1044
1646
                return;
1045
1647
        }
1046
 
        pattern = "\"[^\"]+\"";
1047
 
        is_regex = 1;
 
1648
        search_pattern = "\"[^\"]+\"";
 
1649
        matchtype = match_posix;
1048
1650
        is_case_sens = 0;
1049
1651
        cur_offset = 0;
1050
1652
 
1051
1653
        if (doc_has_newfilename) {
1052
 
                        olddirname = g_dirname(oldfilename);
 
1654
                        olddirname = g_path_get_dirname(oldfilename);
1053
1655
        }
1054
1656
 
1055
 
        fulltext = gtk_editable_get_chars(GTK_EDITABLE(doc->textbox), 0, -1);
1056
 
        result = search_backend(pattern, is_regex, is_case_sens, fulltext, GTK_TEXT(doc->textbox)->use_wchar, 0);
 
1657
        fulltext = doc_get_chars(doc, 0, -1);
 
1658
        utf8_offset_cache_reset();
 
1659
        result = search_backend(search_pattern, matchtype, is_case_sens, fulltext, 0);
1057
1660
        while (result.end > 0) {
1058
1661
                if (doc_has_newfilename) {
1059
1662
                        changelen = do_filename_curfile_replace(fulltext, result, cur_offset, olddirname, newfilename, changelen, doc);
1061
1664
                        changelen = do_filename_otherfile_replace(fulltext, result, cur_offset, oldfilename, newfilename, changelen, doc);
1062
1665
                }
1063
1666
                cur_offset += result.bstart +1;
1064
 
                result = search_backend(pattern, is_regex, is_case_sens, &fulltext[cur_offset], GTK_TEXT(doc->textbox)->use_wchar, 0);
 
1667
                result = search_backend(search_pattern, matchtype, is_case_sens, &fulltext[cur_offset], 0);
1065
1668
        }
1066
1669
        g_free(fulltext);
1067
1670
        if (doc_has_newfilename) {
1068
1671
                g_free(olddirname);
1069
1672
        }
1070
1673
}
 
1674
#endif /* NOTPORTEDYET */
 
1675
 
 
1676
/**
 
1677
 * update_encoding_meta_in_file:
 
1678
 * @doc: a #Tdocument*
 
1679
 * @encoding: #gchar*, The documents character encoding
 
1680
 *
 
1681
 * Update the HTML meta encoding tags for the supplied document.
 
1682
 *
 
1683
 * Return value: void
 
1684
 **/
 
1685
void update_encoding_meta_in_file(Tdocument *doc, gchar *encoding) {
 
1686
        if (encoding) {
 
1687
                Tbfwin *bfwin = BFWIN(doc->bfwin);
 
1688
                Tlast_snr2 last_snr2_bck = *LASTSNR2(bfwin->snr2);
 
1689
                gchar *last_search_pattern_bck = g_strdup(LASTSNR2(bfwin->snr2)->search_pattern);
 
1690
                gchar *search_pattern, *fulltext;
 
1691
                Tsearch_result result;
 
1692
                /* first find if there is a meta encoding tag already */
 
1693
                search_pattern = "<meta[ \t\n]http-equiv[ \t\n]*=[ \t\n]*\"content-type\"[ \t\n]+content[ \t\n]*=[ \t\n]*\"([^;]*);[ \t\n]*charset=[a-z0-9-]*\"[ \t\n]*(/?)>";
 
1694
                fulltext = doc_get_chars(doc, 0, -1);
 
1695
                utf8_offset_cache_reset();
 
1696
                result = search_backend(bfwin,search_pattern, match_posix, 0, fulltext, 0, 1);
 
1697
                if (result.end > 0) {
 
1698
                        gchar *replacestring, *type, *xhtmlend;
 
1699
                        DEBUG_MSG("update_encoding_meta_in_file, we have a match, nmatch=%d\n",result.nmatch);
 
1700
                        if (result.nmatch > 2) {
 
1701
                                type = g_strndup(fulltext+result.pmatch[1].rm_so, result.pmatch[1].rm_eo - result.pmatch[1].rm_so);
 
1702
                                xhtmlend = g_strndup(fulltext+result.pmatch[2].rm_so, result.pmatch[2].rm_eo - result.pmatch[2].rm_so);
 
1703
                                DEBUG_MSG("update_encoding_meta_in_file, type=%s (bstart=%d, bend=%d, so[1]=%d, eo[1]=%d)\n",type,result.bstart,result.bend,result.pmatch[1].rm_so,result.pmatch[1].rm_eo);
 
1704
                        } else {
 
1705
                                type = g_strdup("text/html");
 
1706
                                xhtmlend = g_strdup( main_v->props.xhtml ? "/" : "");
 
1707
                        }
 
1708
                        replacestring = g_strconcat("<meta http-equiv=\"Content-Type\" content=\"",type,"; charset=",encoding,"\" ",xhtmlend,">", NULL);
 
1709
                        DEBUG_MSG("update_encoding_meta_in_file, 1: we have a match\n");
 
1710
                        doc_replace_text(doc, replacestring, result.start, result.end);
 
1711
                        g_free(replacestring);
 
1712
                        g_free(type);
 
1713
                        g_free(xhtmlend);
 
1714
                } else {
 
1715
                        DEBUG_MSG("update_encoding_meta_in_file, 1: NO match\n");
 
1716
                        /* now search for <head>, we can append it to this tag */
 
1717
                        search_pattern = "<head>";
 
1718
                        result = search_backend(bfwin,search_pattern, match_posix, 0, fulltext, 0, 0);
 
1719
                        if (result.end > 0) {
 
1720
                                gchar *replacestring = g_strconcat("<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=",encoding,"\">", NULL);
 
1721
                                DEBUG_MSG("update_encoding_meta_in_file, 2: we have a match\n");
 
1722
                                doc_replace_text(doc, replacestring, result.start, result.end);
 
1723
                                g_free(replacestring);
 
1724
                        } else {
 
1725
                                DEBUG_MSG("update_encoding_meta_in_file, 2: NO match\n");
 
1726
                        }
 
1727
                }
 
1728
                g_free(fulltext);
 
1729
                g_free(LASTSNR2(bfwin->snr2)->search_pattern);
 
1730
                *LASTSNR2(bfwin->snr2) = last_snr2_bck;
 
1731
                LASTSNR2(bfwin->snr2)->search_pattern = last_search_pattern_bck;
 
1732
        }
 
1733
}