qemacs-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemacs-commit] qemacs Makefile qe.h qe.c search.c


From: Charlie Gordon
Subject: [Qemacs-commit] qemacs Makefile qe.h qe.c search.c
Date: Mon, 17 Aug 2015 16:56:49 +0000

CVSROOT:        /sources/qemacs
Module name:    qemacs
Changes by:     Charlie Gordon <chqrlie>        15/08/17 16:56:49

Modified files:
        .              : Makefile qe.h qe.c 
Added files:
        .              : search.c 

Log message:
        search: split search code from qe.c into new module search.c

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/qemacs/Makefile?cvsroot=qemacs&r1=1.78&r2=1.79
http://cvs.savannah.gnu.org/viewcvs/qemacs/qe.h?cvsroot=qemacs&r1=1.198&r2=1.199
http://cvs.savannah.gnu.org/viewcvs/qemacs/qe.c?cvsroot=qemacs&r1=1.201&r2=1.202
http://cvs.savannah.gnu.org/viewcvs/qemacs/search.c?cvsroot=qemacs&rev=1.1

Patches:
Index: Makefile
===================================================================
RCS file: /sources/qemacs/qemacs/Makefile,v
retrieving revision 1.78
retrieving revision 1.79
diff -u -b -r1.78 -r1.79
--- Makefile    7 Aug 2015 08:28:59 -0000       1.78
+++ Makefile    17 Aug 2015 16:56:48 -0000      1.79
@@ -63,8 +63,8 @@
 TARGETLIBS:=
 TARGETS+= qe$(EXE) tqe$(EXE) kmaps ligatures
 
-OBJS:= qe.o parser.o charset.o buffer.o input.o display.o util.o hex.o \
-       list.o cutils.o
+OBJS:= qe.o util.o cutils.o charset.o buffer.o search.o parser.o input.o 
display.o hex.o \
+       list.o
 TOBJS:= $(OBJS)
 
 OBJS+= extras.o variables.o

Index: qe.h
===================================================================
RCS file: /sources/qemacs/qemacs/qe.h,v
retrieving revision 1.198
retrieving revision 1.199
diff -u -b -r1.198 -r1.199
--- qe.h        16 Aug 2015 23:15:02 -0000      1.198
+++ qe.h        17 Aug 2015 16:56:48 -0000      1.199
@@ -1880,6 +1880,7 @@
 void do_scroll_left_right(EditState *s, int dir);
 void do_scroll_up_down(EditState *s, int dir);
 void perform_scroll_up_down(EditState *s, int h);
+void do_center_cursor_maybe(EditState *s);
 void do_center_cursor(EditState *s);
 void do_quote(EditState *s, int argval);
 void do_overwrite_mode(EditState *s, int argval);
@@ -1962,7 +1963,6 @@
 void window_resize(EditState *s, int target_w, int target_h);
 void wheel_scroll_up_down(EditState *s, int dir);
 void qe_mouse_event(QEEvent *ev);
-int parse_command_line(int argc, char **argv);
 void set_user_option(const char *user);
 void set_tty_charset(const char *name);
 

Index: qe.c
===================================================================
RCS file: /sources/qemacs/qemacs/qe.c,v
retrieving revision 1.201
retrieving revision 1.202
diff -u -b -r1.201 -r1.202
--- qe.c        16 Aug 2015 23:15:01 -0000      1.201
+++ qe.c        17 Aug 2015 16:56:49 -0000      1.202
@@ -1187,7 +1187,7 @@
 }
 
 /* center window if offset is not currently visible */
-static void do_center_cursor_maybe(EditState *s)
+void do_center_cursor_maybe(EditState *s)
 {
     if (s->offset < s->offset_top
     ||  (s->offset_bottom >= 0 && s->offset >= s->offset_bottom)) {
@@ -6455,777 +6455,6 @@
     qe_free(&reply);
 }
 
-/* Search stuff */
-
-#define SEARCH_FLAG_SMARTCASE  0x0001  /* case fold unless upper case present 
*/
-#define SEARCH_FLAG_IGNORECASE 0x0002
-#define SEARCH_FLAG_WORD       0x0004
-#define SEARCH_FLAG_WRAPPED    0x0008
-#define SEARCH_FLAG_HEX        0x0010
-#define SEARCH_FLAG_UNIHEX     0x0020
-
-/* XXX: OPTIMIZE ! */
-static int eb_search(EditBuffer *b, int start_offset, int dir, int flags,
-                     const unsigned int *buf, int len,
-                     CSSAbortFunc *abort_func, void *abort_opaque,
-                     int *found_offset, int *found_end)
-{
-    int total_size = b->total_size;
-    int c, c2, offset = start_offset, offset1, offset2, offset3, pos;
-
-    if (len == 0)
-        return 0;
-
-    *found_offset = -1;
-    *found_end = -1;
-
-    /* analyze buffer if smart case */
-    if (flags & SEARCH_FLAG_SMARTCASE) {
-        int upper_count = 0;
-        int lower_count = 0;
-        for (pos = 0; pos < len; pos++) {
-            lower_count += qe_islower(buf[pos]);
-            upper_count += qe_isupper(buf[pos]);
-        }
-        if (lower_count > 0 && upper_count == 0)
-            flags |= SEARCH_FLAG_IGNORECASE;
-    }
-
-    if (flags & SEARCH_FLAG_HEX) {
-        /* handle buffer as single bytes */
-        /* XXX: should handle ucs2 and ucs4 as words */
-        for (;; (void)(dir >= 0 && offset++)) {
-            if (dir < 0) {
-                if (offset == 0)
-                    return 0;
-                offset--;
-            }
-            if (offset >= total_size)
-                return 0;
-
-            if ((offset & 0xfffff) == 0) {
-                /* check for search abort every megabyte */
-                if (abort_func && abort_func(abort_opaque))
-                    return -1;
-            }
-
-            pos = 0;
-            for (offset2 = offset; offset2 < total_size;) {
-                /* CG: Should bufferize a bit ? */
-                c = eb_read_one_byte(b, offset2++);
-                c2 = buf[pos++];
-                if (c != c2)
-                    break;
-                if (pos >= len) {
-                    /* check end of word */
-                    *found_offset = offset;
-                    *found_end = offset2;
-                    return 1;
-                }
-            }
-        }
-    }
-
-    for (offset1 = offset;;) {
-        if (dir < 0) {
-            if (offset == 0)
-                return 0;
-            eb_prevc(b, offset, &offset);
-        } else {
-            offset = offset1;
-            if (offset >= total_size)
-                return 0;
-        }
-        if ((offset & 0xfffff) == 0) {
-            /* check for search abort every megabyte */
-            if (abort_func && abort_func(abort_opaque))
-                return -1;
-        }
-
-        if (flags & SEARCH_FLAG_WORD) {
-            /* check for start of word */
-            c = eb_prevc(b, offset, &offset3);
-            if (qe_isword(c))
-                continue;
-        }
-
-        /* CG: XXX: Should use buffer specific accelerator */
-        /* Get first char separately to compute offset1 */
-        c = eb_nextc(b, offset, &offset1);
-
-        pos = 0;
-        for (offset2 = offset1;;) {
-            c2 = buf[pos++];
-            if (flags & SEARCH_FLAG_IGNORECASE) {
-                if (qe_toupper(c) != qe_toupper(c2))
-                    break;
-            } else {
-                if (c != c2)
-                    break;
-            }
-            if (pos >= len) {
-                if (flags & SEARCH_FLAG_WORD) {
-                    /* check for end of word */
-                    c = eb_nextc(b, offset2, &offset3);
-                    if (qe_isword(c))
-                        break;
-                }
-                if (dir > 0 || offset2 <= start_offset) {
-                    *found_offset = offset;
-                    *found_end = offset2;
-                    return 1;
-                }
-            }
-            if (offset2 >= total_size)
-                break;
-            c = eb_nextc(b, offset2, &offset2);
-        }
-    }
-}
-
-/* should separate search string length and number of match positions */
-#define SEARCH_LENGTH  256
-#define FOUND_TAG      0x80000000
-#define FOUND_REV      0x40000000
-
-/* store last searched string */
-static unsigned int last_search_u32[SEARCH_LENGTH];
-static int last_search_u32_len = 0;
-
-static int search_abort_func(__unused__ void *opaque)
-{
-    return is_user_input_pending();
-}
-
-typedef struct ISearchState {
-    EditState *s;
-    int saved_mark;
-    int start_offset;
-    int start_dir;
-    int quoting;
-    int dir;
-    int pos;
-    int search_flags;
-    int found_offset, found_end;
-    unsigned int search_u32[SEARCH_LENGTH];
-} ISearchState;
-
-static void buf_encode_search_u32(buf_t *out, const unsigned int *str, int len)
-{
-    int i;
-
-    for (i = 0; i < len; i++) {
-        unsigned int v = str[i];
-        if (!(v & FOUND_TAG)) {
-            if (v < 32 || v == 127) {
-                buf_printf(out, "^%c", (v + '@') & 127);
-            } else {
-                buf_putc_utf8(out, v);
-            }
-            if (buf_avail(out) <= 0)
-                break;
-        }
-    }
-}
-
-static void buf_encode_search_str(buf_t *out, const char *str)
-{
-    while (*str) {
-        int c = utf8_decode(&str);
-        if (c < 32 || c == 127) {
-            buf_printf(out, "^%c", (c + '@') & 127);
-        } else {
-            buf_putc_utf8(out, c);
-        }
-        if (buf_avail(out) <= 0)
-            break;
-    }
-}
-
-static void isearch_display(ISearchState *is)
-{
-    EditState *s = is->s;
-    char ubuf[256];
-    buf_t outbuf, *out;
-    unsigned int buf[SEARCH_LENGTH];
-    int c, i, len, hex_nibble, max_nibble, h, hc;
-    unsigned int v;
-    int search_offset, flags, dir = is->start_dir;
-
-    /* prepare the search bytes */
-    len = 0;
-    search_offset = is->start_offset;
-    max_nibble = hex_nibble = hc = 0;
-    flags = is->search_flags;
-    if (flags & SEARCH_FLAG_UNIHEX)
-        max_nibble = 6;
-    if (flags & SEARCH_FLAG_HEX)
-        max_nibble = 2;
-
-    for (i = 0; i < is->pos; i++) {
-        v = is->search_u32[i];
-        if (v & FOUND_TAG) {
-            dir = (v & FOUND_REV) ? -1 : 1;
-            search_offset = v & ~(FOUND_TAG | FOUND_REV);
-            continue;
-        }
-        c = v;
-        if (len < countof(buf)) {
-            if (max_nibble) {
-                h = to_hex(c);
-                if (h >= 0) {
-                    hc = (hc << 4) | h;
-                    if (++hex_nibble == max_nibble) {
-                        buf[len++] = hc;
-                        hex_nibble = hc = 0;
-                    }
-                } else {
-                    if (c == ' ' && hex_nibble) {
-                        buf[len++] = hc;
-                        hex_nibble = hc = 0;
-                    }
-                }
-            } else {
-                buf[len++] = c;
-            }
-        }
-    }
-    if (hex_nibble >= 2) {
-        buf[len++] = hc;
-        hex_nibble = hc = 0;
-    }
-
-    is->dir = dir;
-
-    if (len == 0) {
-        s->b->mark = is->saved_mark;
-        s->offset = is->start_offset;
-        s->region_style = 0;
-        is->found_offset = -1;
-    } else {
-        if (eb_search(s->b, search_offset, is->dir, flags,
-                      buf, len, search_abort_func, NULL,
-                      &is->found_offset, &is->found_end) > 0) {
-            s->region_style = QE_STYLE_SEARCH_MATCH;
-            if (is->dir > 0) {
-                s->b->mark = is->found_offset;
-                s->offset = is->found_end;
-            } else {
-                s->b->mark = is->found_end;
-                s->offset = is->found_offset;
-            }
-        }
-    }
-
-    /* display search string */
-    out = buf_init(&outbuf, ubuf, sizeof(ubuf));
-    if (is->found_offset < 0 && len > 0)
-        buf_puts(out, "Failing ");
-    else
-    if (is->search_flags & SEARCH_FLAG_WRAPPED) {
-        buf_puts(out, "Wrapped ");
-        is->search_flags &= ~SEARCH_FLAG_WRAPPED;
-    }
-    if (is->search_flags & SEARCH_FLAG_UNIHEX)
-        buf_puts(out, "Unihex ");
-    if (is->search_flags & SEARCH_FLAG_HEX)
-        buf_puts(out, "Hex ");
-    if (is->search_flags & SEARCH_FLAG_WORD)
-        buf_puts(out, "Word ");
-    if (is->search_flags & SEARCH_FLAG_IGNORECASE)
-        buf_puts(out, "Folding ");
-    else
-    if (!(is->search_flags & SEARCH_FLAG_SMARTCASE))
-        buf_puts(out, "Exact ");
-
-    buf_puts(out, "I-search");
-    if (is->dir < 0)
-        buf_puts(out, " backward");
-    buf_puts(out, ": ");
-    buf_encode_search_u32(out, is->search_u32, is->pos);
-    if (is->quoting)
-        buf_puts(out, "^Q-");
-
-    /* display text */
-    do_center_cursor_maybe(s);
-    edit_display(s->qe_state);
-    put_status(NULL, "%s", out->buf);
-    dpy_flush(s->screen);
-}
-
-static int isearch_grab(ISearchState *is, EditBuffer *b, int from, int to)
-{
-    int offset, c, last = is->pos;
-    if (b) {
-        if (to < 0 || to > b->total_size)
-            to = b->total_size;
-        for (offset = from; is->pos < SEARCH_LENGTH && offset < to;) {
-            c = eb_nextc(b, offset, &offset);
-            is->search_u32[is->pos++] = c;
-        }
-    }
-    return is->pos - last;
-}
-
-static void isearch_key(void *opaque, int ch)
-{
-    ISearchState *is = opaque;
-    EditState *s = is->s;
-    QEmacsState *qs = &qe_state;
-    int i, j, offset0, offset1, curdir = is->dir;
-    int emacs_behaviour = !qs->emulation_flags;
-
-    if (is->quoting) {
-        is->quoting = 0;
-        if (!KEY_IS_SPECIAL(ch))
-            goto addch;
-    }
-    /* XXX: all these should be isearch-mode bindings */
-    switch (ch) {
-    case KEY_DEL:
-    case KEY_BS:
-        if (is->pos > 0)
-            is->pos--;
-        break;
-    case KEY_CTRL('g'):
-        s->b->mark = is->saved_mark;
-        s->offset = is->start_offset;
-        s->region_style = 0;
-        put_status(s, "Quit");
-    the_end:
-        /* save current searched string */
-        if (is->pos > 0) {
-            j = 0;
-            for (i = 0; i < is->pos; i++) {
-                if (!(is->search_u32[i] & FOUND_TAG))
-                    last_search_u32[j++] = is->search_u32[i];
-            }
-            last_search_u32_len = j;
-        }
-        qe_ungrab_keys();
-        qe_free(&is);
-        edit_display(s->qe_state);
-        dpy_flush(s->screen);
-        return;
-    case KEY_CTRL('s'):         /* next match */
-        is->dir = 1;
-        goto addpos;
-    case KEY_CTRL('r'):         /* previous match */
-        is->dir = -1;
-    addpos:
-        /* use last seached string if no input */
-        if (is->pos == 0 && is->dir == curdir) {
-            memcpy(is->search_u32, last_search_u32,
-                   last_search_u32_len * sizeof(*is->search_u32));
-            is->pos = last_search_u32_len;
-        } else
-        if (is->pos < SEARCH_LENGTH) {
-            /* add the match position, if any */
-            unsigned long v = is->dir > 0 ? FOUND_TAG : FOUND_TAG | FOUND_REV;
-            if (is->found_offset < 0) {
-                is->search_flags |= SEARCH_FLAG_WRAPPED;
-                if (is->dir < 0)
-                    v |= s->b->total_size;
-            } else {
-                v |= s->offset;
-            }
-            is->search_u32[is->pos++] = v;
-        }
-        break;
-    case KEY_CTRL('q'):
-        is->quoting = 1;
-        break;
-    case KEY_META('w'):
-        emacs_behaviour ^= 1;
-        /* fall thru */
-    case KEY_CTRL('w'):
-        if (emacs_behaviour) {
-            /* grab word at cursor */
-            offset0 = s->offset;
-            do_word_right(s, 1);
-            offset1 = s->offset;
-            s->offset = offset0;
-            isearch_grab(is, s->b, offset0, offset1);
-        } else {
-            /* toggle word match */
-            is->search_flags ^= SEARCH_FLAG_WORD;
-        }
-        break;
-    case KEY_META('y'):
-        emacs_behaviour ^= 1;
-        /* fall thru */
-    case KEY_CTRL('y'):
-        if (emacs_behaviour) {
-            /* grab line at cursor */
-            offset0 = s->offset;
-            if (eb_nextc(s->b, offset0, &offset1) == '\n')
-                offset0 = offset1;
-            do_eol(s);
-            offset1 = s->offset;
-            s->offset = offset0;
-            isearch_grab(is, s->b, offset0, offset1);
-        } else {
-            /* yank into search string */
-            isearch_grab(is, qs->yank_buffers[qs->yank_current], 0, -1);
-        }
-        break;
-    case KEY_META('b'):
-    case KEY_CTRL('b'):
-        /* cycle unihex, hex, normal search */
-        if (is->search_flags & SEARCH_FLAG_UNIHEX)
-            is->search_flags ^= SEARCH_FLAG_HEX | SEARCH_FLAG_UNIHEX;
-        else
-        if (is->search_flags & SEARCH_FLAG_HEX)
-            is->search_flags ^= SEARCH_FLAG_HEX;
-        else
-            is->search_flags ^= SEARCH_FLAG_UNIHEX;
-        break;
-    case KEY_META('c'):
-    case KEY_CTRL('c'):
-        /* toggle case sensitivity */
-        if (is->search_flags & (SEARCH_FLAG_IGNORECASE | 
SEARCH_FLAG_SMARTCASE)) {
-            is->search_flags &= ~SEARCH_FLAG_IGNORECASE;
-        } else {
-            is->search_flags |= SEARCH_FLAG_IGNORECASE;
-        }
-        is->search_flags &= ~SEARCH_FLAG_SMARTCASE;
-        break;
-    case KEY_CTRL('l'):
-        do_center_cursor(s);
-        break;
-    default:
-        if ((KEY_IS_SPECIAL(ch) || KEY_IS_CONTROL(ch)) && ch != '\t') {
-            /* exit search mode */
-#if 0
-            // FIXME: behaviour from qemacs-0.3pre13
-            if (is->found_offset >= 0) {
-                s->b->mark = is->found_offset;
-            } else {
-                s->b->mark = is->start_offset;
-            }
-            put_status(s, "Marked");
-#endif
-            s->b->mark = is->start_offset;
-            s->region_style = 0;
-            put_status(s, "Mark saved where search started");
-            /* repost key */
-            if (ch != KEY_RET)
-                unget_key(ch);
-            goto the_end;
-        } else {
-        addch:
-            if (is->pos < SEARCH_LENGTH) {
-                is->search_u32[is->pos++] = ch;
-            }
-        }
-        break;
-    }
-    isearch_display(is);
-}
-
-/* XXX: handle busy */
-void do_isearch(EditState *s, int dir)
-{
-    ISearchState *is;
-    int flags = SEARCH_FLAG_SMARTCASE;
-
-    is = qe_mallocz(ISearchState);
-    if (!is)
-        return;
-    is->s = s;
-    is->saved_mark = s->b->mark;
-    is->start_offset = s->offset;
-    is->start_dir = is->dir = dir;
-    is->pos = 0;
-    if (s->hex_mode) {
-        if (s->unihex_mode)
-            flags |= SEARCH_FLAG_UNIHEX;
-        else
-            flags |= SEARCH_FLAG_HEX;
-    }
-    is->search_flags = flags;
-
-    qe_grab_keys(isearch_key, is);
-    isearch_display(is);
-}
-
-static int search_to_u32(unsigned int *buf, int size,
-                         const char *str, int flags)
-{
-    if (flags & (SEARCH_FLAG_HEX | SEARCH_FLAG_UNIHEX)) {
-        /* CG: XXX: Should mix utf8 and hex syntax in hex modes */
-        const char *s;
-        int c, hex_nibble, max_nibble, h, hc, len;
-
-        max_nibble = (flags & SEARCH_FLAG_UNIHEX) ? 6 : 2;
-        s = str;
-        hex_nibble = hc = 0;
-        for (len = 0; len < size;) {
-            c = *s++;
-            if (c == '\0') {
-                if (hex_nibble >= 2) {
-                    buf[len++] = hc;
-                    hex_nibble = hc = 0;
-                }
-                break;
-            }
-            h = to_hex(c);
-            if (h >= 0) {
-                hc = (hc << 4) | h;
-                if (++hex_nibble == max_nibble) {
-                    buf[len++] = hc;
-                    hex_nibble = hc = 0;
-                }
-            } else {
-                if (c == ' ' && hex_nibble) {
-                    buf[len++] = hc;
-                    hex_nibble = hc = 0;
-                }
-            }
-        }
-        return len;
-    } else {
-        return utf8_to_unicode(buf, size, str);
-    }
-}
-
-typedef struct QueryReplaceState {
-    EditState *s;
-    int start_offset;
-    int search_flags;
-    int replace_all;
-    int nb_reps;
-    int search_u32_len, replace_u32_len;
-    int found_offset, found_end;
-    int last_offset;
-    char search_str[SEARCH_LENGTH];     /* may be in hex */
-    char replace_str[SEARCH_LENGTH];    /* may be in hex */
-    unsigned int search_u32[SEARCH_LENGTH];   /* code points */
-    unsigned int replace_u32[SEARCH_LENGTH];  /* code points */
-} QueryReplaceState;
-
-static void query_replace_abort(QueryReplaceState *is)
-{
-    EditState *s = is->s;
-
-    qe_ungrab_keys();
-    s->b->mark = is->start_offset;
-    s->region_style = 0;
-    put_status(NULL, "Replaced %d occurrences", is->nb_reps);
-    qe_free(&is);
-    edit_display(s->qe_state);
-    dpy_flush(&global_screen);
-}
-
-static void query_replace_replace(QueryReplaceState *is)
-{
-    EditState *s = is->s;
-
-    /* XXX: handle smart case replacement */
-    is->nb_reps++;
-    eb_delete(s->b, is->found_offset, is->found_end - is->found_offset);
-    is->found_offset += eb_insert_u32_buf(s->b, is->found_offset,
-        is->replace_u32, is->replace_u32_len);
-}
-
-static void query_replace_display(QueryReplaceState *is)
-{
-    EditState *s = is->s;
-    char ubuf[256];
-    buf_t outbuf, *out;
-
-    is->last_offset = is->found_offset;
-    is->search_u32_len = search_to_u32(is->search_u32,
-                                       countof(is->search_u32),
-                                       is->search_str, is->search_flags);
-    is->replace_u32_len = search_to_u32(is->replace_u32,
-                                        countof(is->replace_u32),
-                                        is->replace_str, is->search_flags);
-
-    for (;;) {
-        if (eb_search(s->b, is->found_offset, 1, is->search_flags,
-                      is->search_u32, is->search_u32_len,
-                      NULL, NULL, &is->found_offset, &is->found_end) <= 0) {
-            query_replace_abort(is);
-            return;
-        }
-        if (is->replace_all) {
-            query_replace_replace(is);
-            continue;
-        }
-        break;
-    }
-    /* display prompt string */
-    out = buf_init(&outbuf, ubuf, sizeof(ubuf));
-    if (is->search_flags & SEARCH_FLAG_UNIHEX)
-        buf_puts(out, "Unihex ");
-    if (is->search_flags & SEARCH_FLAG_HEX)
-        buf_puts(out, "Hex ");
-    if (is->search_flags & SEARCH_FLAG_WORD)
-        buf_puts(out, "Word ");
-    if (is->search_flags & SEARCH_FLAG_IGNORECASE)
-        buf_puts(out, "Folding ");
-    else
-    if (!(is->search_flags & SEARCH_FLAG_SMARTCASE))
-        buf_puts(out, "Exact ");
-
-    buf_puts(out, "Query replace ");
-    buf_encode_search_str(out, is->search_str);
-    buf_puts(out, " with ");
-    buf_encode_search_str(out, is->replace_str);
-    buf_puts(out, ": ");
-
-    s->offset = is->found_end;
-    s->b->mark = is->found_offset;
-    s->region_style = QE_STYLE_SEARCH_MATCH;
-    do_center_cursor_maybe(s);
-    edit_display(s->qe_state);
-    put_status(NULL, "%s", out->buf);
-    dpy_flush(s->screen);
-}
-
-static void query_replace_key(void *opaque, int ch)
-{
-    QueryReplaceState *is = opaque;
-    EditState *s = is->s;
-    QEmacsState *qs = &qe_state;
-
-    switch (ch) {
-    case 'Y':
-    case 'y':
-    case KEY_SPC:
-        query_replace_replace(is);
-        s->offset = is->found_offset;
-        break;
-    case '!':
-        is->replace_all = 1;
-        break;
-    case 'N':
-    case 'n':
-    case KEY_DELETE:
-        is->found_offset = is->found_end;
-        break;
-    case KEY_META('w'):
-    case KEY_CTRL('w'):
-        /* toggle word match */
-        is->search_flags ^= SEARCH_FLAG_WORD;
-        is->found_offset = is->last_offset;
-        break;
-    case KEY_META('b'):
-    case KEY_CTRL('b'):
-        /* cycle unihex, hex, normal search */
-        if (is->search_flags & SEARCH_FLAG_UNIHEX)
-            is->search_flags ^= SEARCH_FLAG_HEX | SEARCH_FLAG_UNIHEX;
-        else
-        if (is->search_flags & SEARCH_FLAG_HEX)
-            is->search_flags ^= SEARCH_FLAG_HEX;
-        else
-            is->search_flags ^= SEARCH_FLAG_UNIHEX;
-        is->found_offset = is->last_offset;
-        break;
-    case KEY_META('c'):
-    case KEY_CTRL('c'):
-        /* toggle case sensitivity */
-        if (is->search_flags & (SEARCH_FLAG_IGNORECASE | 
SEARCH_FLAG_SMARTCASE)) {
-            is->search_flags &= ~SEARCH_FLAG_IGNORECASE;
-        } else {
-            is->search_flags |= SEARCH_FLAG_IGNORECASE;
-        }
-        is->search_flags &= ~SEARCH_FLAG_SMARTCASE;
-        is->found_offset = is->last_offset;
-        break;
-    case KEY_CTRL('g'):
-        /* abort */
-        if (qs->emulation_flags) {
-            /* restore point to original location */
-            s->offset = is->start_offset;
-        }
-        query_replace_abort(is);
-        return;
-    case KEY_CTRL('l'):
-        do_center_cursor(s);
-        break;
-    case '.':
-        query_replace_replace(is);
-        s->offset = is->found_offset;
-        /* FALL THRU */
-    default:
-        query_replace_abort(is);
-        return;
-    }
-    query_replace_display(is);
-}
-
-static void query_replace(EditState *s, const char *search_str,
-                          const char *replace_str, int all, int flags)
-{
-    QueryReplaceState *is;
-
-    if (s->b->flags & BF_READONLY)
-        return;
-
-    is = qe_mallocz(QueryReplaceState);
-    if (!is)
-        return;
-    is->s = s;
-    pstrcpy(is->search_str, sizeof(is->search_str), search_str);
-    pstrcpy(is->replace_str, sizeof(is->replace_str), replace_str);
-
-    if (s->hex_mode) {
-        if (s->unihex_mode)
-            flags = SEARCH_FLAG_UNIHEX;
-        else
-            flags = SEARCH_FLAG_HEX;
-    }
-    is->search_flags = flags;
-    is->replace_all = all;
-    is->start_offset = is->last_offset = s->offset;
-    is->found_offset = is->found_end = s->offset;
-
-    qe_grab_keys(query_replace_key, is);
-    query_replace_display(is);
-}
-
-void do_query_replace(EditState *s, const char *search_str,
-                      const char *replace_str)
-{
-    int flags = SEARCH_FLAG_SMARTCASE;
-    query_replace(s, search_str, replace_str, 0, flags);
-}
-
-void do_replace_string(EditState *s, const char *search_str,
-                       const char *replace_str, int argval)
-{
-    int flags = SEARCH_FLAG_SMARTCASE;
-    if (argval != NO_ARG)
-        flags |= SEARCH_FLAG_WORD;
-    query_replace(s, search_str, replace_str, 1, flags);
-}
-
-void do_search_string(EditState *s, const char *search_str, int dir)
-{
-    unsigned int search_u32[SEARCH_LENGTH];
-    int search_u32_len;
-    int found_offset, found_end;
-    int flags = SEARCH_FLAG_SMARTCASE;
-
-    if (s->hex_mode) {
-        if (s->unihex_mode)
-            flags |= SEARCH_FLAG_UNIHEX;
-        else
-            flags |= SEARCH_FLAG_HEX;
-    }
-    search_u32_len = search_to_u32(search_u32, countof(search_u32),
-                                   search_str, flags);
-    if (eb_search(s->b, s->offset, dir, flags, search_u32, search_u32_len,
-                  NULL, NULL, &found_offset, &found_end) > 0) {
-        s->offset = (dir < 0) ? found_offset : found_end;
-        do_center_cursor_maybe(s);
-    } else {
-        put_status(s, "Search failed: \"%s\"", search_str);
-    }
-}
-
 /*----------------*/
 
 void do_doctor(EditState *s)
@@ -8087,7 +7316,7 @@
 
 const char str_version[] = "QEmacs version " QE_VERSION;
 const char str_credits[] = "Copyright (c) 2000-2003 Fabrice Bellard\n"
-                           "Copyright (c) 2000-2014 Charlie Gordon\n";
+                           "Copyright (c) 2000-2015 Charlie Gordon\n";
 
 static void show_version(void)
 {
@@ -8131,7 +7360,7 @@
     exit(1);
 }
 
-int parse_command_line(int argc, char **argv)
+static int parse_command_line(int argc, char **argv)
 {
     int _optind;
 

Index: search.c
===================================================================
RCS file: search.c
diff -N search.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ search.c    17 Aug 2015 16:56:49 -0000      1.1
@@ -0,0 +1,794 @@
+/*
+ * QEmacs, tiny but powerful multimode editor
+ *
+ * Copyright (c) 2000-2002 Fabrice Bellard.
+ * Copyright (c) 2000-2015 Charlie Gordon.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "qe.h"
+#include "variables.h"
+
+/* Search stuff */
+
+#define SEARCH_FLAG_SMARTCASE  0x0001  /* case fold unless upper case present 
*/
+#define SEARCH_FLAG_IGNORECASE 0x0002
+#define SEARCH_FLAG_WORD       0x0004
+#define SEARCH_FLAG_WRAPPED    0x0008
+#define SEARCH_FLAG_HEX        0x0010
+#define SEARCH_FLAG_UNIHEX     0x0020
+
+/* XXX: OPTIMIZE ! */
+static int eb_search(EditBuffer *b, int start_offset, int dir, int flags,
+                     const unsigned int *buf, int len,
+                     CSSAbortFunc *abort_func, void *abort_opaque,
+                     int *found_offset, int *found_end)
+{
+    int total_size = b->total_size;
+    int c, c2, offset = start_offset, offset1, offset2, offset3, pos;
+
+    if (len == 0)
+        return 0;
+
+    *found_offset = -1;
+    *found_end = -1;
+
+    /* analyze buffer if smart case */
+    if (flags & SEARCH_FLAG_SMARTCASE) {
+        int upper_count = 0;
+        int lower_count = 0;
+        for (pos = 0; pos < len; pos++) {
+            lower_count += qe_islower(buf[pos]);
+            upper_count += qe_isupper(buf[pos]);
+        }
+        if (lower_count > 0 && upper_count == 0)
+            flags |= SEARCH_FLAG_IGNORECASE;
+    }
+
+    if (flags & SEARCH_FLAG_HEX) {
+        /* handle buffer as single bytes */
+        /* XXX: should handle ucs2 and ucs4 as words */
+        for (;; (void)(dir >= 0 && offset++)) {
+            if (dir < 0) {
+                if (offset == 0)
+                    return 0;
+                offset--;
+            }
+            if (offset >= total_size)
+                return 0;
+
+            if ((offset & 0xfffff) == 0) {
+                /* check for search abort every megabyte */
+                if (abort_func && abort_func(abort_opaque))
+                    return -1;
+            }
+
+            pos = 0;
+            for (offset2 = offset; offset2 < total_size;) {
+                /* CG: Should bufferize a bit ? */
+                c = eb_read_one_byte(b, offset2++);
+                c2 = buf[pos++];
+                if (c != c2)
+                    break;
+                if (pos >= len) {
+                    /* check end of word */
+                    *found_offset = offset;
+                    *found_end = offset2;
+                    return 1;
+                }
+            }
+        }
+    }
+
+    for (offset1 = offset;;) {
+        if (dir < 0) {
+            if (offset == 0)
+                return 0;
+            eb_prevc(b, offset, &offset);
+        } else {
+            offset = offset1;
+            if (offset >= total_size)
+                return 0;
+        }
+        if ((offset & 0xfffff) == 0) {
+            /* check for search abort every megabyte */
+            if (abort_func && abort_func(abort_opaque))
+                return -1;
+        }
+
+        if (flags & SEARCH_FLAG_WORD) {
+            /* check for start of word */
+            c = eb_prevc(b, offset, &offset3);
+            if (qe_isword(c))
+                continue;
+        }
+
+        /* CG: XXX: Should use buffer specific accelerator */
+        /* Get first char separately to compute offset1 */
+        c = eb_nextc(b, offset, &offset1);
+
+        pos = 0;
+        for (offset2 = offset1;;) {
+            c2 = buf[pos++];
+            if (flags & SEARCH_FLAG_IGNORECASE) {
+                if (qe_toupper(c) != qe_toupper(c2))
+                    break;
+            } else {
+                if (c != c2)
+                    break;
+            }
+            if (pos >= len) {
+                if (flags & SEARCH_FLAG_WORD) {
+                    /* check for end of word */
+                    c = eb_nextc(b, offset2, &offset3);
+                    if (qe_isword(c))
+                        break;
+                }
+                if (dir > 0 || offset2 <= start_offset) {
+                    *found_offset = offset;
+                    *found_end = offset2;
+                    return 1;
+                }
+            }
+            if (offset2 >= total_size)
+                break;
+            c = eb_nextc(b, offset2, &offset2);
+        }
+    }
+}
+
+/* should separate search string length and number of match positions */
+#define SEARCH_LENGTH  256
+#define FOUND_TAG      0x80000000
+#define FOUND_REV      0x40000000
+
+/* store last searched string */
+static unsigned int last_search_u32[SEARCH_LENGTH];
+static int last_search_u32_len = 0;
+
+static int search_abort_func(__unused__ void *opaque)
+{
+    return is_user_input_pending();
+}
+
+typedef struct ISearchState {
+    EditState *s;
+    int saved_mark;
+    int start_offset;
+    int start_dir;
+    int quoting;
+    int dir;
+    int pos;
+    int search_flags;
+    int found_offset, found_end;
+    unsigned int search_u32[SEARCH_LENGTH];
+} ISearchState;
+
+static void buf_encode_search_u32(buf_t *out, const unsigned int *str, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++) {
+        unsigned int v = str[i];
+        if (!(v & FOUND_TAG)) {
+            if (v < 32 || v == 127) {
+                buf_printf(out, "^%c", (v + '@') & 127);
+            } else {
+                buf_putc_utf8(out, v);
+            }
+            if (buf_avail(out) <= 0)
+                break;
+        }
+    }
+}
+
+static void buf_encode_search_str(buf_t *out, const char *str)
+{
+    while (*str) {
+        int c = utf8_decode(&str);
+        if (c < 32 || c == 127) {
+            buf_printf(out, "^%c", (c + '@') & 127);
+        } else {
+            buf_putc_utf8(out, c);
+        }
+        if (buf_avail(out) <= 0)
+            break;
+    }
+}
+
+static void isearch_display(ISearchState *is)
+{
+    EditState *s = is->s;
+    char ubuf[256];
+    buf_t outbuf, *out;
+    unsigned int buf[SEARCH_LENGTH];
+    int c, i, len, hex_nibble, max_nibble, h, hc;
+    unsigned int v;
+    int search_offset, flags, dir = is->start_dir;
+
+    /* prepare the search bytes */
+    len = 0;
+    search_offset = is->start_offset;
+    max_nibble = hex_nibble = hc = 0;
+    flags = is->search_flags;
+    if (flags & SEARCH_FLAG_UNIHEX)
+        max_nibble = 6;
+    if (flags & SEARCH_FLAG_HEX)
+        max_nibble = 2;
+
+    for (i = 0; i < is->pos; i++) {
+        v = is->search_u32[i];
+        if (v & FOUND_TAG) {
+            dir = (v & FOUND_REV) ? -1 : 1;
+            search_offset = v & ~(FOUND_TAG | FOUND_REV);
+            continue;
+        }
+        c = v;
+        if (len < countof(buf)) {
+            if (max_nibble) {
+                h = to_hex(c);
+                if (h >= 0) {
+                    hc = (hc << 4) | h;
+                    if (++hex_nibble == max_nibble) {
+                        buf[len++] = hc;
+                        hex_nibble = hc = 0;
+                    }
+                } else {
+                    if (c == ' ' && hex_nibble) {
+                        buf[len++] = hc;
+                        hex_nibble = hc = 0;
+                    }
+                }
+            } else {
+                buf[len++] = c;
+            }
+        }
+    }
+    if (hex_nibble >= 2) {
+        buf[len++] = hc;
+        hex_nibble = hc = 0;
+    }
+
+    is->dir = dir;
+
+    if (len == 0) {
+        s->b->mark = is->saved_mark;
+        s->offset = is->start_offset;
+        s->region_style = 0;
+        is->found_offset = -1;
+    } else {
+        if (eb_search(s->b, search_offset, is->dir, flags,
+                      buf, len, search_abort_func, NULL,
+                      &is->found_offset, &is->found_end) > 0) {
+            s->region_style = QE_STYLE_SEARCH_MATCH;
+            if (is->dir > 0) {
+                s->b->mark = is->found_offset;
+                s->offset = is->found_end;
+            } else {
+                s->b->mark = is->found_end;
+                s->offset = is->found_offset;
+            }
+        }
+    }
+
+    /* display search string */
+    out = buf_init(&outbuf, ubuf, sizeof(ubuf));
+    if (is->found_offset < 0 && len > 0)
+        buf_puts(out, "Failing ");
+    else
+    if (is->search_flags & SEARCH_FLAG_WRAPPED) {
+        buf_puts(out, "Wrapped ");
+        is->search_flags &= ~SEARCH_FLAG_WRAPPED;
+    }
+    if (is->search_flags & SEARCH_FLAG_UNIHEX)
+        buf_puts(out, "Unihex ");
+    if (is->search_flags & SEARCH_FLAG_HEX)
+        buf_puts(out, "Hex ");
+    if (is->search_flags & SEARCH_FLAG_WORD)
+        buf_puts(out, "Word ");
+    if (is->search_flags & SEARCH_FLAG_IGNORECASE)
+        buf_puts(out, "Folding ");
+    else
+    if (!(is->search_flags & SEARCH_FLAG_SMARTCASE))
+        buf_puts(out, "Exact ");
+
+    buf_puts(out, "I-search");
+    if (is->dir < 0)
+        buf_puts(out, " backward");
+    buf_puts(out, ": ");
+    buf_encode_search_u32(out, is->search_u32, is->pos);
+    if (is->quoting)
+        buf_puts(out, "^Q-");
+
+    /* display text */
+    do_center_cursor_maybe(s);
+    edit_display(s->qe_state);
+    put_status(NULL, "%s", out->buf);
+    dpy_flush(s->screen);
+}
+
+static int isearch_grab(ISearchState *is, EditBuffer *b, int from, int to)
+{
+    int offset, c, last = is->pos;
+    if (b) {
+        if (to < 0 || to > b->total_size)
+            to = b->total_size;
+        for (offset = from; is->pos < SEARCH_LENGTH && offset < to;) {
+            c = eb_nextc(b, offset, &offset);
+            is->search_u32[is->pos++] = c;
+        }
+    }
+    return is->pos - last;
+}
+
+static void isearch_key(void *opaque, int ch)
+{
+    ISearchState *is = opaque;
+    EditState *s = is->s;
+    QEmacsState *qs = &qe_state;
+    int i, j, offset0, offset1, curdir = is->dir;
+    int emacs_behaviour = !qs->emulation_flags;
+
+    if (is->quoting) {
+        is->quoting = 0;
+        if (!KEY_IS_SPECIAL(ch))
+            goto addch;
+    }
+    /* XXX: all these should be isearch-mode bindings */
+    switch (ch) {
+    case KEY_DEL:
+    case KEY_BS:
+        if (is->pos > 0)
+            is->pos--;
+        break;
+    case KEY_CTRL('g'):
+        s->b->mark = is->saved_mark;
+        s->offset = is->start_offset;
+        s->region_style = 0;
+        put_status(s, "Quit");
+    the_end:
+        /* save current searched string */
+        if (is->pos > 0) {
+            j = 0;
+            for (i = 0; i < is->pos; i++) {
+                if (!(is->search_u32[i] & FOUND_TAG))
+                    last_search_u32[j++] = is->search_u32[i];
+            }
+            last_search_u32_len = j;
+        }
+        qe_ungrab_keys();
+        qe_free(&is);
+        edit_display(s->qe_state);
+        dpy_flush(s->screen);
+        return;
+    case KEY_CTRL('s'):         /* next match */
+        is->dir = 1;
+        goto addpos;
+    case KEY_CTRL('r'):         /* previous match */
+        is->dir = -1;
+    addpos:
+        /* use last seached string if no input */
+        if (is->pos == 0 && is->dir == curdir) {
+            memcpy(is->search_u32, last_search_u32,
+                   last_search_u32_len * sizeof(*is->search_u32));
+            is->pos = last_search_u32_len;
+        } else
+        if (is->pos < SEARCH_LENGTH) {
+            /* add the match position, if any */
+            unsigned long v = is->dir > 0 ? FOUND_TAG : FOUND_TAG | FOUND_REV;
+            if (is->found_offset < 0) {
+                is->search_flags |= SEARCH_FLAG_WRAPPED;
+                if (is->dir < 0)
+                    v |= s->b->total_size;
+            } else {
+                v |= s->offset;
+            }
+            is->search_u32[is->pos++] = v;
+        }
+        break;
+    case KEY_CTRL('q'):
+        is->quoting = 1;
+        break;
+    case KEY_META('w'):
+        emacs_behaviour ^= 1;
+        /* fall thru */
+    case KEY_CTRL('w'):
+        if (emacs_behaviour) {
+            /* grab word at cursor */
+            offset0 = s->offset;
+            do_word_right(s, 1);
+            offset1 = s->offset;
+            s->offset = offset0;
+            isearch_grab(is, s->b, offset0, offset1);
+        } else {
+            /* toggle word match */
+            is->search_flags ^= SEARCH_FLAG_WORD;
+        }
+        break;
+    case KEY_META('y'):
+        emacs_behaviour ^= 1;
+        /* fall thru */
+    case KEY_CTRL('y'):
+        if (emacs_behaviour) {
+            /* grab line at cursor */
+            offset0 = s->offset;
+            if (eb_nextc(s->b, offset0, &offset1) == '\n')
+                offset0 = offset1;
+            do_eol(s);
+            offset1 = s->offset;
+            s->offset = offset0;
+            isearch_grab(is, s->b, offset0, offset1);
+        } else {
+            /* yank into search string */
+            isearch_grab(is, qs->yank_buffers[qs->yank_current], 0, -1);
+        }
+        break;
+    case KEY_META('b'):
+    case KEY_CTRL('b'):
+        /* cycle unihex, hex, normal search */
+        if (is->search_flags & SEARCH_FLAG_UNIHEX)
+            is->search_flags ^= SEARCH_FLAG_HEX | SEARCH_FLAG_UNIHEX;
+        else
+        if (is->search_flags & SEARCH_FLAG_HEX)
+            is->search_flags ^= SEARCH_FLAG_HEX;
+        else
+            is->search_flags ^= SEARCH_FLAG_UNIHEX;
+        break;
+    case KEY_META('c'):
+    case KEY_CTRL('c'):
+        /* toggle case sensitivity */
+        if (is->search_flags & (SEARCH_FLAG_IGNORECASE | 
SEARCH_FLAG_SMARTCASE)) {
+            is->search_flags &= ~SEARCH_FLAG_IGNORECASE;
+        } else {
+            is->search_flags |= SEARCH_FLAG_IGNORECASE;
+        }
+        is->search_flags &= ~SEARCH_FLAG_SMARTCASE;
+        break;
+    case KEY_CTRL('l'):
+        do_center_cursor(s);
+        break;
+    default:
+        if ((KEY_IS_SPECIAL(ch) || KEY_IS_CONTROL(ch)) && ch != '\t') {
+            /* exit search mode */
+#if 0
+            // FIXME: behaviour from qemacs-0.3pre13
+            if (is->found_offset >= 0) {
+                s->b->mark = is->found_offset;
+            } else {
+                s->b->mark = is->start_offset;
+            }
+            put_status(s, "Marked");
+#endif
+            s->b->mark = is->start_offset;
+            s->region_style = 0;
+            put_status(s, "Mark saved where search started");
+            /* repost key */
+            if (ch != KEY_RET)
+                unget_key(ch);
+            goto the_end;
+        } else {
+        addch:
+            if (is->pos < SEARCH_LENGTH) {
+                is->search_u32[is->pos++] = ch;
+            }
+        }
+        break;
+    }
+    isearch_display(is);
+}
+
+/* XXX: handle busy */
+void do_isearch(EditState *s, int dir)
+{
+    ISearchState *is;
+    int flags = SEARCH_FLAG_SMARTCASE;
+
+    is = qe_mallocz(ISearchState);
+    if (!is)
+        return;
+    is->s = s;
+    is->saved_mark = s->b->mark;
+    is->start_offset = s->offset;
+    is->start_dir = is->dir = dir;
+    is->pos = 0;
+    if (s->hex_mode) {
+        if (s->unihex_mode)
+            flags |= SEARCH_FLAG_UNIHEX;
+        else
+            flags |= SEARCH_FLAG_HEX;
+    }
+    is->search_flags = flags;
+
+    qe_grab_keys(isearch_key, is);
+    isearch_display(is);
+}
+
+static int search_to_u32(unsigned int *buf, int size,
+                         const char *str, int flags)
+{
+    if (flags & (SEARCH_FLAG_HEX | SEARCH_FLAG_UNIHEX)) {
+        /* CG: XXX: Should mix utf8 and hex syntax in hex modes */
+        const char *s;
+        int c, hex_nibble, max_nibble, h, hc, len;
+
+        max_nibble = (flags & SEARCH_FLAG_UNIHEX) ? 6 : 2;
+        s = str;
+        hex_nibble = hc = 0;
+        for (len = 0; len < size;) {
+            c = *s++;
+            if (c == '\0') {
+                if (hex_nibble >= 2) {
+                    buf[len++] = hc;
+                    hex_nibble = hc = 0;
+                }
+                break;
+            }
+            h = to_hex(c);
+            if (h >= 0) {
+                hc = (hc << 4) | h;
+                if (++hex_nibble == max_nibble) {
+                    buf[len++] = hc;
+                    hex_nibble = hc = 0;
+                }
+            } else {
+                if (c == ' ' && hex_nibble) {
+                    buf[len++] = hc;
+                    hex_nibble = hc = 0;
+                }
+            }
+        }
+        return len;
+    } else {
+        return utf8_to_unicode(buf, size, str);
+    }
+}
+
+typedef struct QueryReplaceState {
+    EditState *s;
+    int start_offset;
+    int search_flags;
+    int replace_all;
+    int nb_reps;
+    int search_u32_len, replace_u32_len;
+    int found_offset, found_end;
+    int last_offset;
+    char search_str[SEARCH_LENGTH];     /* may be in hex */
+    char replace_str[SEARCH_LENGTH];    /* may be in hex */
+    unsigned int search_u32[SEARCH_LENGTH];   /* code points */
+    unsigned int replace_u32[SEARCH_LENGTH];  /* code points */
+} QueryReplaceState;
+
+static void query_replace_abort(QueryReplaceState *is)
+{
+    EditState *s = is->s;
+
+    qe_ungrab_keys();
+    s->b->mark = is->start_offset;
+    s->region_style = 0;
+    put_status(NULL, "Replaced %d occurrences", is->nb_reps);
+    qe_free(&is);
+    edit_display(s->qe_state);
+    dpy_flush(s->screen);
+}
+
+static void query_replace_replace(QueryReplaceState *is)
+{
+    EditState *s = is->s;
+
+    /* XXX: handle smart case replacement */
+    is->nb_reps++;
+    eb_delete(s->b, is->found_offset, is->found_end - is->found_offset);
+    is->found_offset += eb_insert_u32_buf(s->b, is->found_offset,
+        is->replace_u32, is->replace_u32_len);
+}
+
+static void query_replace_display(QueryReplaceState *is)
+{
+    EditState *s = is->s;
+    char ubuf[256];
+    buf_t outbuf, *out;
+
+    is->last_offset = is->found_offset;
+    is->search_u32_len = search_to_u32(is->search_u32,
+                                       countof(is->search_u32),
+                                       is->search_str, is->search_flags);
+    is->replace_u32_len = search_to_u32(is->replace_u32,
+                                        countof(is->replace_u32),
+                                        is->replace_str, is->search_flags);
+
+    for (;;) {
+        if (eb_search(s->b, is->found_offset, 1, is->search_flags,
+                      is->search_u32, is->search_u32_len,
+                      NULL, NULL, &is->found_offset, &is->found_end) <= 0) {
+            query_replace_abort(is);
+            return;
+        }
+        if (is->replace_all) {
+            query_replace_replace(is);
+            continue;
+        }
+        break;
+    }
+    /* display prompt string */
+    out = buf_init(&outbuf, ubuf, sizeof(ubuf));
+    if (is->search_flags & SEARCH_FLAG_UNIHEX)
+        buf_puts(out, "Unihex ");
+    if (is->search_flags & SEARCH_FLAG_HEX)
+        buf_puts(out, "Hex ");
+    if (is->search_flags & SEARCH_FLAG_WORD)
+        buf_puts(out, "Word ");
+    if (is->search_flags & SEARCH_FLAG_IGNORECASE)
+        buf_puts(out, "Folding ");
+    else
+    if (!(is->search_flags & SEARCH_FLAG_SMARTCASE))
+        buf_puts(out, "Exact ");
+
+    buf_puts(out, "Query replace ");
+    buf_encode_search_str(out, is->search_str);
+    buf_puts(out, " with ");
+    buf_encode_search_str(out, is->replace_str);
+    buf_puts(out, ": ");
+
+    s->offset = is->found_end;
+    s->b->mark = is->found_offset;
+    s->region_style = QE_STYLE_SEARCH_MATCH;
+    do_center_cursor_maybe(s);
+    edit_display(s->qe_state);
+    put_status(NULL, "%s", out->buf);
+    dpy_flush(s->screen);
+}
+
+static void query_replace_key(void *opaque, int ch)
+{
+    QueryReplaceState *is = opaque;
+    EditState *s = is->s;
+    QEmacsState *qs = &qe_state;
+
+    switch (ch) {
+    case 'Y':
+    case 'y':
+    case KEY_SPC:
+        query_replace_replace(is);
+        s->offset = is->found_offset;
+        break;
+    case '!':
+        is->replace_all = 1;
+        break;
+    case 'N':
+    case 'n':
+    case KEY_DELETE:
+        is->found_offset = is->found_end;
+        break;
+    case KEY_META('w'):
+    case KEY_CTRL('w'):
+        /* toggle word match */
+        is->search_flags ^= SEARCH_FLAG_WORD;
+        is->found_offset = is->last_offset;
+        break;
+    case KEY_META('b'):
+    case KEY_CTRL('b'):
+        /* cycle unihex, hex, normal search */
+        if (is->search_flags & SEARCH_FLAG_UNIHEX)
+            is->search_flags ^= SEARCH_FLAG_HEX | SEARCH_FLAG_UNIHEX;
+        else
+        if (is->search_flags & SEARCH_FLAG_HEX)
+            is->search_flags ^= SEARCH_FLAG_HEX;
+        else
+            is->search_flags ^= SEARCH_FLAG_UNIHEX;
+        is->found_offset = is->last_offset;
+        break;
+    case KEY_META('c'):
+    case KEY_CTRL('c'):
+        /* toggle case sensitivity */
+        if (is->search_flags & (SEARCH_FLAG_IGNORECASE | 
SEARCH_FLAG_SMARTCASE)) {
+            is->search_flags &= ~SEARCH_FLAG_IGNORECASE;
+        } else {
+            is->search_flags |= SEARCH_FLAG_IGNORECASE;
+        }
+        is->search_flags &= ~SEARCH_FLAG_SMARTCASE;
+        is->found_offset = is->last_offset;
+        break;
+    case KEY_CTRL('g'):
+        /* abort */
+        if (qs->emulation_flags) {
+            /* restore point to original location */
+            s->offset = is->start_offset;
+        }
+        query_replace_abort(is);
+        return;
+    case KEY_CTRL('l'):
+        do_center_cursor(s);
+        break;
+    case '.':
+        query_replace_replace(is);
+        s->offset = is->found_offset;
+        /* FALL THRU */
+    default:
+        query_replace_abort(is);
+        return;
+    }
+    query_replace_display(is);
+}
+
+static void query_replace(EditState *s, const char *search_str,
+                          const char *replace_str, int all, int flags)
+{
+    QueryReplaceState *is;
+
+    if (s->b->flags & BF_READONLY)
+        return;
+
+    is = qe_mallocz(QueryReplaceState);
+    if (!is)
+        return;
+    is->s = s;
+    pstrcpy(is->search_str, sizeof(is->search_str), search_str);
+    pstrcpy(is->replace_str, sizeof(is->replace_str), replace_str);
+
+    if (s->hex_mode) {
+        if (s->unihex_mode)
+            flags = SEARCH_FLAG_UNIHEX;
+        else
+            flags = SEARCH_FLAG_HEX;
+    }
+    is->search_flags = flags;
+    is->replace_all = all;
+    is->start_offset = is->last_offset = s->offset;
+    is->found_offset = is->found_end = s->offset;
+
+    qe_grab_keys(query_replace_key, is);
+    query_replace_display(is);
+}
+
+void do_query_replace(EditState *s, const char *search_str,
+                      const char *replace_str)
+{
+    int flags = SEARCH_FLAG_SMARTCASE;
+    query_replace(s, search_str, replace_str, 0, flags);
+}
+
+void do_replace_string(EditState *s, const char *search_str,
+                       const char *replace_str, int argval)
+{
+    int flags = SEARCH_FLAG_SMARTCASE;
+    if (argval != NO_ARG)
+        flags |= SEARCH_FLAG_WORD;
+    query_replace(s, search_str, replace_str, 1, flags);
+}
+
+void do_search_string(EditState *s, const char *search_str, int dir)
+{
+    unsigned int search_u32[SEARCH_LENGTH];
+    int search_u32_len;
+    int found_offset, found_end;
+    int flags = SEARCH_FLAG_SMARTCASE;
+
+    if (s->hex_mode) {
+        if (s->unihex_mode)
+            flags |= SEARCH_FLAG_UNIHEX;
+        else
+            flags |= SEARCH_FLAG_HEX;
+    }
+    search_u32_len = search_to_u32(search_u32, countof(search_u32),
+                                   search_str, flags);
+    if (eb_search(s->b, s->offset, dir, flags, search_u32, search_u32_len,
+                  NULL, NULL, &found_offset, &found_end) > 0) {
+        s->offset = (dir < 0) ? found_offset : found_end;
+        do_center_cursor_maybe(s);
+    } else {
+        put_status(s, "Search failed: \"%s\"", search_str);
+    }
+}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]