~peter-pearse/ubuntu/oneiric/x11-apps/prop001

« back to all changes in this revision

Viewing changes to xedit/tags.c

  • Committer: Bazaar Package Importer
  • Author(s): Brice Goglin
  • Date: 2009-07-27 18:55:03 UTC
  • Revision ID: james.westby@ubuntu.com-20090727185503-9p9hfcmtvlc24mko
Tags: 7.4+2
* Add xedit 1.1.2, closes: #499085, #505064.
* Bump Standards-Version to 3.8.2, no changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2007 Paulo César Pereira de Andrade
 
3
 *
 
4
 * Permission is hereby granted, free of charge, to any person obtaining a
 
5
 * copy of this software and associated documentation files (the "Software"),
 
6
 * to deal in the Software without restriction, including without limitation
 
7
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
8
 * and/or sell copies of the Software, and to permit persons to whom the
 
9
 * Software is furnished to do so, subject to the following conditions:
 
10
 *
 
11
 * The above copyright notice and this permission notice (including the next
 
12
 * paragraph) shall be included in all copies or substantial portions of the
 
13
 * Software.
 
14
 *
 
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
17
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
18
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
19
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
20
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
21
 * DEALINGS IN THE SOFTWARE.
 
22
 *
 
23
 * Author: Paulo César Pereira de Andrade
 
24
 */
 
25
 
 
26
/*
 
27
 *   Certain tag files may require quite some time and memory to load.
 
28
 * Linux kernel 2.6x is an example, the tags file itself is almost 80Mb
 
29
 * and xedit will use over 100Mb to store the data, and take quite some
 
30
 * time to load it (and can grow drastically with every loaded files
 
31
 * due to the memory used by the file contents and internal structures,
 
32
 * like the syntax highlight ones).
 
33
 *   Possible workarounds could be to load the tags file in a separate
 
34
 * process or thread. The memory problem would be hard to circunvent,
 
35
 * as the tags file metadata would need to be stored in some very fast
 
36
 * database, or at least some special format that would not require
 
37
 * a linear search in a huge tags file.
 
38
 */
 
39
 
 
40
#include "xedit.h"
 
41
#include "util.h"
 
42
#include "re.h"
 
43
#include <unistd.h>
 
44
 
 
45
/*
 
46
 * Types
 
47
 */
 
48
typedef struct _TagsEntry       TagsEntry;
 
49
typedef struct _RegexEntry      RegexEntry;
 
50
 
 
51
struct _TagsEntry {
 
52
    hash_key    *symbol;
 
53
    TagsEntry   *next;
 
54
 
 
55
    int         nentries;
 
56
    hash_entry  **filenames;
 
57
    char        **patterns;
 
58
};
 
59
 
 
60
struct _RegexEntry {
 
61
    hash_key    *pattern;
 
62
    RegexEntry  *next;
 
63
 
 
64
    re_cod      regex;
 
65
};
 
66
 
 
67
struct _XeditTagsInfo {
 
68
    hash_key            *pathname;
 
69
    XeditTagsInfo       *next;
 
70
 
 
71
    hash_table          *entries;
 
72
    hash_table          *filenames;
 
73
    hash_table          *patterns;
 
74
 
 
75
    /* Used when searching for alternate tags and failing descending to
 
76
     * root directory */
 
77
    Boolean             visited;
 
78
 
 
79
    /* Flag to know if tags file is in xedit cwd and allow using relative
 
80
     * pathnames when loading a file with some tag definition, so that
 
81
     * other code will not fail to write file (or even worse, write to
 
82
     * wrong file) if file is edited and tags is not in the current dir */
 
83
    Boolean             incwd;
 
84
 
 
85
    /* Cache information for circulating over multiple definitions */
 
86
    XeditTagsInfo       *tags;          /* If trying another TagsInfo */
 
87
    TagsEntry           *entry;         /* Entry in tags->tags */
 
88
    int                 offset;
 
89
    Widget              textwindow;
 
90
    XawTextPosition     position;
 
91
};
 
92
 
 
93
/*
 
94
 * Prototypes
 
95
 */
 
96
static XeditTagsInfo *LoadTagsFile(char *tagsfile);
 
97
static XeditTagsInfo *DoLoadTagsFile(char *tagsfile, int length);
 
98
static void FindTagFirst(XeditTagsInfo *tags, char *symbol, int length);
 
99
static void FindTagNext(XeditTagsInfo *tags,
 
100
                        Widget window, XawTextPosition position);
 
101
static void FindTag(XeditTagsInfo *tags);
 
102
 
 
103
/*
 
104
 * Initialization
 
105
 */
 
106
extern Widget texts[3];
 
107
static hash_table *ht_tags;
 
108
 
 
109
/*
 
110
 * Implementation
 
111
 */
 
112
void
 
113
TagsAction(Widget w, XEvent *event, String *params, Cardinal *num_params)
 
114
{
 
115
    xedit_flist_item    *item;
 
116
    char                buffer[1024];
 
117
    XawTextPosition     position, left, right;
 
118
    XawTextBlock        block;
 
119
    int                 length;
 
120
    Widget              source;
 
121
 
 
122
    source = XawTextGetSource(w);
 
123
    item = FindTextSource(source, NULL);
 
124
    if (item->tags == NULL)
 
125
        SearchTagsFile(item);
 
126
 
 
127
    if (item->tags) {
 
128
        position = XawTextGetInsertionPoint(w);
 
129
        XawTextGetSelectionPos(w, &left, &right);
 
130
        if (right > left) {
 
131
            XawTextSourceRead(source, left, &block, right - left);
 
132
            length = block.length + 1;
 
133
            if (length >= sizeof(buffer))
 
134
                length = sizeof(buffer);
 
135
            XmuSnprintf(buffer, length, "%s", block.ptr);
 
136
            item->tags->textwindow = w;
 
137
            item->tags->position = position;
 
138
            FindTagFirst(item->tags, buffer, length - 1);
 
139
        }
 
140
        else
 
141
            FindTagNext(item->tags, w, position);
 
142
    }
 
143
    else
 
144
        Feep();
 
145
}
 
146
 
 
147
void
 
148
SearchTagsFile(xedit_flist_item *item)
 
149
{
 
150
    if (app_resources.loadTags) {
 
151
        char            buffer[BUFSIZ];
 
152
        char            *ptr, *tagsfile;
 
153
        int             length;
 
154
        Boolean         exists;
 
155
        FileAccess      file_access;
 
156
 
 
157
        tagsfile = NULL;
 
158
 
 
159
        /* If path fully specified in resource */
 
160
        if (app_resources.tagsName[0] == '/')
 
161
            tagsfile = ResolveName(app_resources.tagsName);
 
162
        /* Descend up to root directory searching for a tags file */
 
163
        else {
 
164
            /* *scratch* buffer */
 
165
            if (item->filename[0] != '/') {
 
166
                ptr = ResolveName(app_resources.tagsName);
 
167
                strncpy(buffer, ptr ? ptr : "", sizeof(buffer));
 
168
            }
 
169
            else
 
170
                strncpy(buffer, item->filename, sizeof(buffer));
 
171
 
 
172
            /* Make sure buffer is nul terminated */
 
173
            buffer[sizeof(buffer) - 1] = '\0';
 
174
            ptr = buffer + strlen(buffer);
 
175
 
 
176
            for (;;) {
 
177
                while (ptr > buffer && ptr[-1] != '/')
 
178
                    --ptr;
 
179
                if (ptr <= buffer)
 
180
                    break;
 
181
                length = ptr - buffer;
 
182
                if (length >= sizeof(buffer))
 
183
                    length = sizeof(buffer);
 
184
                strncpy(ptr, app_resources.tagsName,
 
185
                        sizeof(buffer) - length);
 
186
                buffer[sizeof(buffer) - 1] = '\0';
 
187
 
 
188
                /* Check if tags filename exists */
 
189
                tagsfile = ResolveName(buffer);
 
190
                if (tagsfile != NULL) {
 
191
                    file_access = CheckFilePermissions(tagsfile, &exists);
 
192
                    /* Check if can read tagsfile */
 
193
                    if (exists &&
 
194
                        (file_access == READ_OK || file_access == WRITE_OK))
 
195
                        break;
 
196
                    else
 
197
                        tagsfile = NULL;
 
198
                }
 
199
                *--ptr = '\0';
 
200
            }
 
201
        }
 
202
 
 
203
        if (tagsfile)
 
204
            item->tags = LoadTagsFile(tagsfile);
 
205
        else {
 
206
            XeditPrintf("No tags file found."
 
207
                        " Run \"ctags -R\" to build a tags file.\n");
 
208
            item->tags = NULL;
 
209
        }
 
210
    }
 
211
}
 
212
 
 
213
static void
 
214
FindTagFirst(XeditTagsInfo *tags, char *symbol, int length)
 
215
{
 
216
    char        *ptr;
 
217
    TagsEntry   *entry;
 
218
    char        buffer[BUFSIZ];
 
219
 
 
220
    /* Check for malformed parameters */
 
221
    ptr = symbol;
 
222
    while (*ptr) {
 
223
        if (*ptr == ' ' || *ptr == '\t' || *ptr == '\n' || *ptr == '\r' ||
 
224
            *ptr == '(' || *ptr == ')') {
 
225
            Feep();
 
226
            return;
 
227
        }
 
228
        ptr++;
 
229
    }
 
230
 
 
231
    /* First try in buffer tags */
 
232
    tags->tags = tags;
 
233
    entry = (TagsEntry *)hash_check(tags->entries, symbol, length);
 
234
    if (entry == NULL) {
 
235
        /* Try to find in alternate tags */
 
236
        strncpy(buffer, tags->pathname->value, tags->pathname->length);
 
237
        buffer[tags->pathname->length] = '\0';
 
238
        ptr = buffer + tags->pathname->length - 1;
 
239
 
 
240
        for (tags->tags = (XeditTagsInfo *)hash_iter_first(ht_tags);
 
241
             tags->tags;
 
242
             tags->tags = (XeditTagsInfo *)hash_iter_next(ht_tags))
 
243
            tags->tags->visited = False;
 
244
 
 
245
        tags->visited = True;
 
246
 
 
247
        while (ptr > buffer && entry == NULL) {
 
248
            --ptr;
 
249
            while (ptr > buffer && ptr[-1] != '/')
 
250
                --ptr;
 
251
            if (ptr <= buffer)
 
252
                break;
 
253
            *ptr = '\0';
 
254
 
 
255
            /* Try an upper directory tags */
 
256
            tags->tags = (XeditTagsInfo *)
 
257
                hash_check(ht_tags, buffer, ptr - buffer);
 
258
            if (tags->tags) {
 
259
                tags->tags->visited = True;
 
260
                entry = (TagsEntry *)
 
261
                    hash_check(tags->tags->entries, symbol, length);
 
262
            }
 
263
        }
 
264
 
 
265
        /* If still failed, check other available tags
 
266
         * for possible different projects */
 
267
        if (entry == NULL) {
 
268
            for (tags->tags = (XeditTagsInfo *)hash_iter_first(ht_tags);
 
269
                 tags->tags;
 
270
                 tags->tags = (XeditTagsInfo *)hash_iter_next(ht_tags)) {
 
271
                if (tags->tags->visited == False) {
 
272
                    entry = (TagsEntry *)
 
273
                        hash_check(tags->tags->entries, symbol, length);
 
274
                    /* Stop on first match */
 
275
                    if (entry != NULL)
 
276
                        break;
 
277
                }
 
278
            }
 
279
        }
 
280
 
 
281
        if (entry == NULL) {
 
282
            XeditPrintf("Symbol %s not in tags\n", symbol);
 
283
            Feep();
 
284
            return;
 
285
        }
 
286
    }
 
287
 
 
288
    tags->entry = entry;
 
289
    tags->offset = 0;
 
290
 
 
291
    FindTag(tags);
 
292
}
 
293
 
 
294
static void
 
295
FindTagNext(XeditTagsInfo *tags, Widget window, XawTextPosition position)
 
296
{
 
297
    if (window != tags->textwindow || position != tags->position)
 
298
        Feep();
 
299
    else {
 
300
        if (tags->entry->nentries > 1) {
 
301
            if (++tags->offset >= tags->entry->nentries)
 
302
                tags->offset = 0;
 
303
            FindTag(tags);
 
304
        }
 
305
        else
 
306
            Feep();
 
307
    }
 
308
}
 
309
 
 
310
static XeditTagsInfo *
 
311
LoadTagsFile(char *tagsfile)
 
312
{
 
313
    XeditTagsInfo       *tags;
 
314
    int                 length;
 
315
 
 
316
    if (ht_tags == NULL)
 
317
        ht_tags = hash_new(11, NULL);
 
318
 
 
319
    /* tags key is only the directory name with ending '/' */
 
320
    length = strlen(tagsfile) - strlen(app_resources.tagsName);
 
321
    tags = (XeditTagsInfo *)hash_check(ht_tags, tagsfile, length);
 
322
 
 
323
    return (tags ? tags : DoLoadTagsFile(tagsfile, length));
 
324
}
 
325
 
 
326
static XeditTagsInfo *
 
327
DoLoadTagsFile(char *tagsfile, int length)
 
328
{
 
329
    char                *ptr;
 
330
    FILE                *file;
 
331
    XeditTagsInfo       *tags;
 
332
    TagsEntry           *entry;
 
333
    hash_entry          *file_entry;
 
334
    char                buffer[BUFSIZ];
 
335
    char                *symbol, *filename, *pattern;
 
336
 
 
337
    file = fopen(tagsfile, "r");
 
338
    if (file) {
 
339
        char *cwd;
 
340
 
 
341
        tags = XtNew(XeditTagsInfo);
 
342
 
 
343
        cwd = getcwd(buffer, sizeof(buffer));
 
344
        tags->incwd = cwd &&
 
345
            (strlen(cwd) == length - 1 &&
 
346
             memcmp(cwd, tagsfile, length - 1) == 0);
 
347
 
 
348
        /* Build pathname as a nul terminated directory specification string */
 
349
        tags->pathname = XtNew(hash_key);
 
350
        tags->pathname->value = XtMalloc(length + 1);
 
351
        tags->pathname->length = length;
 
352
        memcpy(tags->pathname->value, tagsfile, length);
 
353
        tags->pathname->value[length] = '\0';
 
354
        tags->next = NULL;
 
355
 
 
356
        tags->entries = hash_new(809, NULL);
 
357
        tags->filenames = hash_new(31, NULL);
 
358
        tags->patterns = hash_new(47, NULL);
 
359
 
 
360
        /* Cache information */
 
361
        tags->tags = tags;      /* :-) */
 
362
        tags->entry = NULL;
 
363
        tags->offset = 0;
 
364
        tags->textwindow = NULL;
 
365
        tags->position = 0;
 
366
 
 
367
        while (fgets(buffer, sizeof(buffer) - 1, file)) {
 
368
            /* XXX Ignore malformed lines and tags file format information */
 
369
            if (isspace(buffer[0]) || buffer[0] == '!')
 
370
                continue;
 
371
 
 
372
            /* Symbol name */
 
373
            symbol = ptr = buffer;
 
374
            while (*ptr && !isspace(*ptr))
 
375
                ptr++;
 
376
            *ptr++ = '\0';
 
377
            while (isspace(*ptr))
 
378
                ptr++;
 
379
 
 
380
            /* Filename with basename of tagsfile for symbol definition */
 
381
            filename = ptr;
 
382
            while (*ptr && !isspace(*ptr))
 
383
                ptr++;
 
384
            *ptr++ = '\0';
 
385
            while (isspace(*ptr))
 
386
                ptr++;
 
387
 
 
388
            pattern = ptr;
 
389
            /* Check for regex */
 
390
            if (*pattern == '/' || *pattern == '?') {
 
391
                ptr++;
 
392
                while (*ptr && *ptr != *pattern) {
 
393
                    if (*ptr == '\\') {
 
394
                        if (ptr[1] == *pattern || ptr[1] == '\\') {
 
395
                            /* XXX tags will escape pattern end, and backslash
 
396
                             * not sure about other special characters */
 
397
                            memmove(ptr, ptr + 1, strlen(ptr));
 
398
                        }
 
399
                        else {
 
400
                            ++ptr;
 
401
                            if (!*ptr)
 
402
                                break;
 
403
                        }
 
404
                    }
 
405
                    ptr++;
 
406
                }
 
407
 
 
408
                if (*ptr != *pattern)
 
409
                    continue;
 
410
                ++pattern;
 
411
                /*   Will do a RE_NOSPEC search, that means ^ and $
 
412
                 * would be literally search (do this to avoid escaping
 
413
                 * other regex characters and building a fast/simple literal
 
414
                 * string search pattern.
 
415
                 *   Expect patterns to be full line */
 
416
                if (*pattern == '^' && ptr[-1] == '$') {
 
417
                    ++pattern;
 
418
                    --ptr;
 
419
                }
 
420
            }
 
421
            /* Check for line number */
 
422
            else if (isdigit(*ptr)) {
 
423
                while (isdigit(*ptr))
 
424
                    ptr++;
 
425
            }
 
426
            /* Format not understood */
 
427
            else
 
428
                continue;
 
429
 
 
430
            *ptr = '\0';
 
431
 
 
432
            length = strlen(symbol);
 
433
            entry = (TagsEntry *)hash_check(tags->entries,
 
434
                                            symbol, length);
 
435
            if (entry == NULL) {
 
436
                entry = XtNew(TagsEntry);
 
437
                entry->symbol = XtNew(hash_key);
 
438
                entry->symbol->value = XtNewString(symbol);
 
439
                entry->symbol->length = length;
 
440
                entry->next = NULL;
 
441
                entry->nentries = 0;
 
442
                entry->filenames = NULL;
 
443
                entry->patterns = NULL;
 
444
                hash_put(tags->entries, (hash_entry *)entry);
 
445
            }
 
446
 
 
447
            length = strlen(filename);
 
448
            file_entry = hash_check(tags->filenames, filename, length);
 
449
            if (file_entry == NULL) {
 
450
                file_entry = XtNew(hash_entry);
 
451
                file_entry->key = XtNew(hash_key);
 
452
                file_entry->key->value = XtNewString(filename);
 
453
                file_entry->key->length = length;
 
454
                file_entry->next = NULL;
 
455
                hash_put(tags->filenames, file_entry);
 
456
            }
 
457
 
 
458
            if ((entry->nentries % 4) == 0) {
 
459
                entry->filenames = (hash_entry **)
 
460
                        XtRealloc((char *)entry->filenames,
 
461
                                  sizeof(hash_entry *) *
 
462
                                  (entry->nentries + 4));
 
463
                entry->patterns = (char **)
 
464
                        XtRealloc((char *)entry->patterns,
 
465
                                  sizeof(char *) *
 
466
                                  (entry->nentries + 4));
 
467
            }
 
468
            entry->filenames[entry->nentries] = file_entry;
 
469
            entry->patterns[entry->nentries] = XtNewString(pattern);
 
470
            ++entry->nentries;
 
471
        }
 
472
        fclose(file);
 
473
 
 
474
        /* Add tags information to global hash table */
 
475
        hash_put(ht_tags, (hash_entry *)tags);
 
476
        XeditPrintf("Tags file %s loaded\n", tagsfile);
 
477
    }
 
478
    else {
 
479
        XeditPrintf("Failed to load tags file %s\n", tagsfile);
 
480
        tags = NULL;
 
481
    }
 
482
 
 
483
    return (tags);
 
484
}
 
485
 
 
486
static void
 
487
FindTag(XeditTagsInfo *tags)
 
488
{
 
489
    static String       params[] = { "vertical", NULL };
 
490
 
 
491
    char                buffer[BUFSIZ];
 
492
    char                *pattern;
 
493
    int                 length;
 
494
    char                *line;
 
495
    char                *text;
 
496
    RegexEntry          *regex;
 
497
    re_mat              match;
 
498
    XawTextPosition     position, left, right, last;
 
499
    Widget              source;
 
500
    XawTextBlock        block;
 
501
    int                 size;
 
502
    int                 lineno;
 
503
    Boolean             found;
 
504
    xedit_flist_item    *item;
 
505
    Widget              otherwindow;
 
506
 
 
507
    XmuSnprintf(buffer, sizeof(buffer), "%s%s", tags->tags->pathname->value,
 
508
                tags->entry->filenames[tags->offset]->key->value);
 
509
 
 
510
    pattern = tags->entry->patterns[tags->offset];
 
511
    if (isdigit(*pattern)) {
 
512
        lineno = atoi(pattern);
 
513
        regex = NULL;
 
514
    }
 
515
    else {
 
516
        lineno = 0;
 
517
        length = strlen(pattern);
 
518
        regex = (RegexEntry *)hash_check(tags->patterns, pattern, length);
 
519
        if (regex == NULL) {
 
520
            regex = XtNew(RegexEntry);
 
521
            regex->pattern = XtNew(hash_key);
 
522
            regex->pattern->value = XtNewString(pattern);
 
523
            regex->pattern->length = length;
 
524
            regex->next = NULL;
 
525
            if (recomp(&regex->regex, pattern, RE_NOSUB | RE_NOSPEC)) {
 
526
                XeditPrintf("Failed to compile regex %s\n", pattern);
 
527
                Feep();
 
528
                return;
 
529
            }
 
530
            hash_put(tags->patterns, (hash_entry *)regex);
 
531
        }
 
532
    }
 
533
 
 
534
    /* Short circuit to know if split horizontally */
 
535
    if (!XtIsManaged(texts[1]))
 
536
        XtCallActionProc(textwindow, "split-window", NULL, params, 1);
 
537
 
 
538
    /* Switch to "other" buffer */
 
539
    XtCallActionProc(textwindow, "other-window", NULL, NULL, 0);
 
540
 
 
541
    /* This should print an error message if tags file cannot be read */
 
542
    if (!LoadFileInTextwindow(tags->incwd ?
 
543
                              tags->entry->filenames[tags->offset]->key->value :
 
544
                              buffer, buffer))
 
545
        return;
 
546
 
 
547
    otherwindow = textwindow;
 
548
 
 
549
    item = FindTextSource(XawTextGetSource(textwindow), NULL);
 
550
    source = item->source;
 
551
    left = XawTextSourceScan(source, 0, XawstAll, XawsdLeft, 1, True);
 
552
 
 
553
    found = False;
 
554
 
 
555
    if (lineno) {
 
556
        right = RSCAN(left, lineno, False);
 
557
        left = LSCAN(right, 1, False);
 
558
        found = True;
 
559
    }
 
560
    else {
 
561
        right = RSCAN(left, 1, True);
 
562
        last = XawTextSourceScan(source, 0, XawstAll, XawsdRight, 1, True);
 
563
        text = buffer;
 
564
 
 
565
        size = sizeof(buffer);
 
566
        for (;;) {
 
567
            length = right - left;
 
568
            match.rm_so = 0;
 
569
            match.rm_eo = length;
 
570
            XawTextSourceRead(source, left, &block, right - left);
 
571
            if (block.length >= length)
 
572
                line = block.ptr;
 
573
            else {
 
574
                if (length > size) {
 
575
                    if (text == buffer)
 
576
                        text = XtMalloc(length);
 
577
                    else
 
578
                        text = XtRealloc(text, length);
 
579
                    size = length;
 
580
                }
 
581
                line = text;
 
582
                memcpy(line, block.ptr, block.length);
 
583
                length = block.length;
 
584
                for (position = left + length;
 
585
                     position < right;
 
586
                     position += block.length) {
 
587
                    XawTextSourceRead(source, position, &block, right - position);
 
588
                    memcpy(line + length, block.ptr, block.length);
 
589
                    length += block.length;
 
590
                }
 
591
            }
 
592
 
 
593
            /* If not last line or if it ends in a newline */
 
594
            if (right < last ||
 
595
                (right > left && line[match.rm_eo - 1] == '\n')) {
 
596
                --match.rm_eo;
 
597
                length = match.rm_eo;
 
598
            }
 
599
 
 
600
            /* Accept as a match when matching the entire line, as the regex
 
601
             * search pattern is optmized to not need to start with ^ and not
 
602
             * need to end with $*/
 
603
            if (reexec(&regex->regex, line, 1, &match, RE_STARTEND) == 0 &&
 
604
                match.rm_eo > match.rm_so &&
 
605
                match.rm_so == 0 && match.rm_eo == length) {
 
606
                right = left + match.rm_so + (match.rm_eo - match.rm_so);
 
607
                found = True;
 
608
                break;
 
609
            }
 
610
            else if (right >= last) {
 
611
                XeditPrintf("Failed to match regex %s\n", pattern);
 
612
                Feep();
 
613
                break;
 
614
            }
 
615
            else {
 
616
                left = LSCAN(right + 1, 1, False);
 
617
                right = RSCAN(left, 1, True);
 
618
            }
 
619
        }
 
620
 
 
621
        if (text != buffer)
 
622
            XtFree(text);
 
623
    }
 
624
 
 
625
    /* Switch back to editing buffer */
 
626
    XtCallActionProc(otherwindow, "other-window", NULL, NULL, 0);
 
627
 
 
628
    if (found) {
 
629
        if (source != XawTextGetSource(tags->textwindow) ||
 
630
            right < tags->position || left > tags->position) {
 
631
            XawTextSetInsertionPoint(otherwindow, left);
 
632
            XawTextSetSelection(otherwindow, left, right);
 
633
        }
 
634
    }
 
635
}