Add regex support for search and replace

* import libunicode and libregexp from QuickJS
* add utility functions:
  min/max_uint32, min/max_int64 clz/ctz/32/64
  bswap12/32/64
* add packed get and put inline functions
* add DynBuf package (dbuf_xxx)
* add unicode_to/from_utf8()
* add regex support in eb_search
* add partial regex support in query_replace: no subexpressions support
* bumped VERSION to 6.1.0
This commit is contained in:
Charlie Gordon 2023-03-05 13:34:19 +01:00
commit fcf4c46321
12 changed files with 9529 additions and 3 deletions

View file

@ -155,6 +155,7 @@ endif
ifdef CONFIG_UNICODE_JOIN
OBJS+= unicode_join.o arabic.o indic.o
OBJS+= libunicode.o libregexp.o
endif
# more charsets if needed
@ -339,6 +340,8 @@ $(OBJS_DIR)/charsetjis.o: charsetjis.c charsetjis.def
$(OBJS_DIR)/fbfrender.o: fbfrender.c fbfrender.h libfbf.h
$(OBJS_DIR)/qe.o: qe.c qeconfig.h
$(OBJS_DIR)/modes/stb.o: modes/stb.c modes/stb_image.h
$(OBJS_DIR)/libunicode.o: libunicode.c libunicode.h libunicode-table.h
$(OBJS_DIR)/libregexp.o: libregexp.c libregexp.h libregexp-opcode.h
$(OBJS_DIR)/%.o: %.c $(DEPENDS) Makefile
$(echo) CC $(ECHO_CFLAGS) -c $<
@ -471,6 +474,10 @@ unitable.txt: $(BINDIR)/unitable$(EXE) Makefile
unicode_width: $(BINDIR)/unitable$(EXE) Makefile
$(BINDIR)/unitable -V $(UNICODE_VER) -W -a > unicode_width.h
#
#libunicode_table: $(BINDIR)/unicode_gen$(EXE) Makefile
# $(BINDIR)/unicode_gen libunicode-table.h
#
# fonts (only needed for html2png)
#

View file

@ -313,7 +313,7 @@ insert_window_left() deletes some left-most windows
* `hex-mode` search strings should mix hex ut8 strings and ASCII control char names
* isearch in hex should display search string in hex
* transfer case in `query-replace`
* regex search/replace
* regex replace with subexpressions
* query replace across multiple files
* query replace options: u -> undo last change
* add non selectable query-replace-mode for key bindings, cmd description and documentation

View file

@ -1 +1 @@
6.0.0
6.1.0

242
cutils.c
View file

@ -23,6 +23,7 @@
* THE SOFTWARE.
*/
#include <stdarg.h>
#include <string.h>
#include "config.h" /* for CONFIG_WIN32 */
@ -236,3 +237,244 @@ char *get_dirname(char *dest, int size, const char *file) {
}
return dest;
}
/* Dynamic buffer package */
static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size)
{
return realloc(ptr, size);
}
void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func)
{
memset(s, 0, sizeof(*s));
if (!realloc_func)
realloc_func = dbuf_default_realloc;
s->opaque = opaque;
s->realloc_func = realloc_func;
}
void dbuf_init(DynBuf *s)
{
dbuf_init2(s, NULL, NULL);
}
/* return < 0 if error */
int dbuf_realloc(DynBuf *s, size_t new_size)
{
size_t size = s->allocated_size;
if (new_size > size) {
uint8_t *new_buf;
if (s->error)
return -1;
size += size / 2;
if (new_size < size)
new_size = size;
new_buf = s->realloc_func(s->opaque, s->buf, new_size);
if (!new_buf) {
s->error = TRUE;
return -1;
}
s->buf = new_buf;
s->allocated_size = new_size;
}
return 0;
}
int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len)
{
size_t end;
end = offset + len;
if (dbuf_realloc(s, end))
return -1;
memcpy(s->buf + offset, data, len);
if (end > s->size)
s->size = end;
return 0;
}
int dbuf_put(DynBuf *s, const uint8_t *data, size_t len)
{
if (unlikely((s->size + len) > s->allocated_size)) {
if (dbuf_realloc(s, s->size + len))
return -1;
}
memcpy(s->buf + s->size, data, len);
s->size += len;
return 0;
}
int dbuf_put_self(DynBuf *s, size_t offset, size_t len)
{
if (unlikely((s->size + len) > s->allocated_size)) {
if (dbuf_realloc(s, s->size + len))
return -1;
}
memcpy(s->buf + s->size, s->buf + offset, len);
s->size += len;
return 0;
}
int dbuf_putc(DynBuf *s, uint8_t c)
{
return dbuf_put(s, &c, 1);
}
int dbuf_putstr(DynBuf *s, const char *str)
{
return dbuf_put(s, (const uint8_t *)str, strlen(str));
}
int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
const char *fmt, ...)
{
va_list ap;
char buf[128];
int len;
va_start(ap, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (len < 0)
return len;
if (len < (int)sizeof(buf)) {
/* fast case */
return dbuf_put(s, (uint8_t *)buf, len);
} else {
if (dbuf_realloc(s, s->size + len + 1))
return -1;
va_start(ap, fmt);
vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size,
fmt, ap);
va_end(ap);
s->size += len;
}
return 0;
}
void dbuf_free(DynBuf *s)
{
/* we test s->buf as a fail safe to avoid crashing if dbuf_free()
is called twice */
if (s->buf) {
s->realloc_func(s->opaque, s->buf, 0);
}
memset(s, 0, sizeof(*s));
}
/* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes
are output. */
int unicode_to_utf8(uint8_t *buf, unsigned int c)
{
uint8_t *q = buf;
if (c < 0x80) {
*q++ = c;
} else {
if (c < 0x800) {
*q++ = (c >> 6) | 0xc0;
} else {
if (c < 0x10000) {
*q++ = (c >> 12) | 0xe0;
} else {
if (c < 0x00200000) {
*q++ = (c >> 18) | 0xf0;
} else {
if (c < 0x04000000) {
*q++ = (c >> 24) | 0xf8;
} else if (c < 0x80000000) {
*q++ = (c >> 30) | 0xfc;
*q++ = ((c >> 24) & 0x3f) | 0x80;
} else {
return 0;
}
*q++ = ((c >> 18) & 0x3f) | 0x80;
}
*q++ = ((c >> 12) & 0x3f) | 0x80;
}
*q++ = ((c >> 6) & 0x3f) | 0x80;
}
*q++ = (c & 0x3f) | 0x80;
}
return q - buf;
}
#if 0
static const int utf8_min_code[5] = {
0x80, 0x800, 0x10000, 0x200000, 0x4000000,
//0x80, 0x20, 0x400, 0x8000, 0x100000,
//0x80, 0x20, 0x10, 0x200, 0x4000,
//0x80, 0x20, 0x10, 0x8, 0x100,
//0x80, 0x20, 0x10, 0x8, 0x4,
};
#endif
/* return -1 if error. *pp is not updated in this case. max_len must
be >= 1. The maximum length for a UTF-8 byte sequence is 6 bytes. */
// XXX: should return synthetic byte code for invalid UTF-8 encoding
// emacs uses 0x3fff80-0x3fffff for invalud bytes 0x80 to 0xff.
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)
{
int c, n, b;
c = *p++;
if (c < 0x80) {
*pp = p;
return c;
}
switch (c) {
case 0xc0: case 0xc1:
return -1;
case 0xc2: case 0xc3:
case 0xc4: case 0xc5: case 0xc6: case 0xc7:
case 0xc8: case 0xc9: case 0xca: case 0xcb:
case 0xcc: case 0xcd: case 0xce: case 0xcf:
case 0xd0: case 0xd1: case 0xd2: case 0xd3:
case 0xd4: case 0xd5: case 0xd6: case 0xd7:
case 0xd8: case 0xd9: case 0xda: case 0xdb:
case 0xdc: case 0xdd: case 0xde: case 0xdf:
if (max_len < 2)
return -1;
b = *p++ ^ 0x80;
if (b >= 0x40)
return -1;
c = ((c & 0x1f) << 6) | b;
*pp = p;
return c;
case 0xe0: case 0xe1: case 0xe2: case 0xe3:
case 0xe4: case 0xe5: case 0xe6: case 0xe7:
case 0xe8: case 0xe9: case 0xea: case 0xeb:
case 0xec: case 0xed: case 0xee: case 0xef:
n = 1;
break;
case 0xf0: case 0xf1: case 0xf2: case 0xf3:
case 0xf4: case 0xf5: case 0xf6: case 0xf7:
n = 2;
break;
case 0xf8: case 0xf9: case 0xfa: case 0xfb:
n = 3;
break;
case 0xfc: case 0xfd:
n = 4;
break;
default:
return -1;
}
if (max_len < n + 2)
return -1;
b = *p++ ^ 0x80;
if (b >= 0x40)
return -1;
c &= 0x1f >> n;
c = (c << 6) | b;
if (c < (0x40 >> n))
return -1;
while (n --> 0) {
b = *p++ ^ 0x80;
if (b >= 0x40)
return -1;
c = (c << 6) | b;
}
*pp = p;
return c;
}

202
cutils.h
View file

@ -270,6 +270,208 @@ static inline int min_uint(unsigned int a, unsigned int b) {
return b;
}
static inline uint32_t max_uint32(uint32_t a, uint32_t b) {
if (a > b)
return a;
else
return b;
}
static inline uint32_t min_uint32(uint32_t a, uint32_t b) {
if (a < b)
return a;
else
return b;
}
static inline int64_t max_int64(int64_t a, int64_t b) {
if (a > b)
return a;
else
return b;
}
static inline int64_t min_int64(int64_t a, int64_t b) {
if (a < b)
return a;
else
return b;
}
/* WARNING: undefined if a = 0 */
static inline int clz32(unsigned int a)
{
return __builtin_clz(a);
}
/* WARNING: undefined if a = 0 */
static inline int clz64(uint64_t a)
{
return __builtin_clzll(a);
}
/* WARNING: undefined if a = 0 */
static inline int ctz32(unsigned int a)
{
return __builtin_ctz(a);
}
/* WARNING: undefined if a = 0 */
static inline int ctz64(uint64_t a)
{
return __builtin_ctzll(a);
}
struct __attribute__((packed)) packed_u64 {
uint64_t v;
};
struct __attribute__((packed)) packed_u32 {
uint32_t v;
};
struct __attribute__((packed)) packed_u16 {
uint16_t v;
};
static inline uint64_t get_u64(const uint8_t *tab)
{
return ((const struct packed_u64 *)tab)->v;
}
static inline int64_t get_i64(const uint8_t *tab)
{
return (int64_t)((const struct packed_u64 *)tab)->v;
}
static inline void put_u64(uint8_t *tab, uint64_t val)
{
((struct packed_u64 *)tab)->v = val;
}
static inline uint32_t get_u32(const uint8_t *tab)
{
return ((const struct packed_u32 *)tab)->v;
}
static inline int32_t get_i32(const uint8_t *tab)
{
return (int32_t)((const struct packed_u32 *)tab)->v;
}
static inline void put_u32(uint8_t *tab, uint32_t val)
{
((struct packed_u32 *)tab)->v = val;
}
static inline uint32_t get_u16(const uint8_t *tab)
{
return ((const struct packed_u16 *)tab)->v;
}
static inline int32_t get_i16(const uint8_t *tab)
{
return (int16_t)((const struct packed_u16 *)tab)->v;
}
static inline void put_u16(uint8_t *tab, uint16_t val)
{
((struct packed_u16 *)tab)->v = val;
}
static inline uint32_t get_u8(const uint8_t *tab)
{
return *tab;
}
static inline int32_t get_i8(const uint8_t *tab)
{
return (int8_t)*tab;
}
static inline void put_u8(uint8_t *tab, uint8_t val)
{
*tab = val;
}
static inline uint16_t bswap16(uint16_t x)
{
return (x >> 8) | (x << 8);
}
static inline uint32_t bswap32(uint32_t v)
{
return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |
((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);
}
static inline uint64_t bswap64(uint64_t v)
{
return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |
((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) |
((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) |
((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) |
((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) |
((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) |
((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |
((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));
}
/* XXX: should take an extra argument to pass slack information to the caller */
typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);
typedef struct DynBuf {
uint8_t *buf;
size_t size;
size_t allocated_size;
BOOL error; /* true if a memory allocation error occurred */
DynBufReallocFunc *realloc_func;
void *opaque; /* for realloc_func */
} DynBuf;
void dbuf_init(DynBuf *s);
void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);
int dbuf_realloc(DynBuf *s, size_t new_size);
int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len);
int dbuf_put(DynBuf *s, const uint8_t *data, size_t len);
int dbuf_put_self(DynBuf *s, size_t offset, size_t len);
int dbuf_putc(DynBuf *s, uint8_t c);
int dbuf_putstr(DynBuf *s, const char *str);
static inline int dbuf_put_u16(DynBuf *s, uint16_t val) {
return dbuf_put(s, (uint8_t *)&val, 2);
}
static inline int dbuf_put_u32(DynBuf *s, uint32_t val) {
return dbuf_put(s, (uint8_t *)&val, 4);
}
static inline int dbuf_put_u64(DynBuf *s, uint64_t val) {
return dbuf_put(s, (uint8_t *)&val, 8);
}
int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
const char *fmt, ...);
void dbuf_free(DynBuf *s);
static inline BOOL dbuf_error(DynBuf *s) {
return s->error;
}
static inline void dbuf_set_error(DynBuf *s) {
s->error = TRUE;
}
#define UTF8_CHAR_LEN_MAX 6
int unicode_to_utf8(uint8_t *buf, unsigned int c);
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp);
static inline int from_hex(int c) {
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
else if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
else
return -1;
}
/* Double linked lists. Same API as the linux kernel */
struct list_head {

58
libregexp-opcode.h Normal file
View file

@ -0,0 +1,58 @@
/*
* Regular Expression Engine
*
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifdef DEF
DEF(invalid, 1) /* never used */
DEF(char, 3)
DEF(char32, 5)
DEF(dot, 1)
DEF(any, 1) /* same as dot but match any character including line terminator */
DEF(line_start, 1)
DEF(line_end, 1)
DEF(goto, 5)
DEF(split_goto_first, 5)
DEF(split_next_first, 5)
DEF(match, 1)
DEF(save_start, 2) /* save start position */
DEF(save_end, 2) /* save end position, must come after saved_start */
DEF(save_reset, 3) /* reset save positions */
DEF(loop, 5) /* decrement the top the stack and goto if != 0 */
DEF(push_i32, 5) /* push integer on the stack */
DEF(drop, 1)
DEF(word_boundary, 1)
DEF(not_word_boundary, 1)
DEF(back_reference, 2)
DEF(backward_back_reference, 2) /* must come after back_reference */
DEF(range, 3) /* variable length */
DEF(range32, 3) /* variable length */
DEF(lookahead, 5)
DEF(negative_lookahead, 5)
DEF(push_char_pos, 1) /* push the character position on the stack */
DEF(bne_char_pos, 5) /* pop one stack element and jump if equal to the character
position */
DEF(prev, 1) /* go to the previous char */
DEF(simple_greedy_quant, 17)
#endif /* DEF */

2680
libregexp.c Normal file

File diff suppressed because it is too large Load diff

94
libregexp.h Normal file
View file

@ -0,0 +1,94 @@
/*
* Regular Expression Engine
*
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef LIBREGEXP_H
#define LIBREGEXP_H
#include <stddef.h>
#include "libunicode.h"
#define LRE_BOOL int /* for documentation purposes */
#define LRE_FLAG_GLOBAL (1 << 0)
#define LRE_FLAG_IGNORECASE (1 << 1)
#define LRE_FLAG_MULTILINE (1 << 2)
#define LRE_FLAG_DOTALL (1 << 3)
#define LRE_FLAG_UTF16 (1 << 4)
#define LRE_FLAG_STICKY (1 << 5)
#define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */
uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
const char *buf, size_t buf_len, int re_flags,
void *opaque);
int lre_get_capture_count(const uint8_t *bc_buf);
int lre_get_flags(const uint8_t *bc_buf);
const char *lre_get_groupnames(const uint8_t *bc_buf);
int lre_exec(uint8_t **capture,
const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen,
int cbuf_type, void *opaque, uint32_t bof_char, uint32_t eof_char,
unsigned int (*nextc)(const uint8_t *bc_buf, int offset, int *offsetp),
unsigned int (*prevc)(const uint8_t *bc_buf, int offset, int *offsetp));
int lre_parse_escape(const uint8_t **pp, int allow_utf16);
LRE_BOOL lre_is_space(int c);
/* must be provided by the user */
LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size);
void *lre_realloc(void *opaque, void *ptr, size_t size);
/* JS identifier test */
extern uint32_t const lre_id_start_table_ascii[4];
extern uint32_t const lre_id_continue_table_ascii[4];
static inline int lre_js_is_ident_first(int c)
{
if ((uint32_t)c < 128) {
return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1;
} else {
#ifdef CONFIG_ALL_UNICODE
return lre_is_id_start(c);
#else
return !lre_is_space(c);
#endif
}
}
static inline int lre_js_is_ident_next(int c)
{
if ((uint32_t)c < 128) {
return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1;
} else {
/* ZWNJ and ZWJ are accepted in identifiers */
#ifdef CONFIG_ALL_UNICODE
return lre_is_id_continue(c) || c == 0x200C || c == 0x200D;
#else
return !lre_is_space(c) || c == 0x200C || c == 0x200D;
#endif
}
}
#undef LRE_BOOL
#endif /* LIBREGEXP_H */

4449
libunicode-table.h Normal file

File diff suppressed because it is too large Load diff

1557
libunicode.c Normal file

File diff suppressed because it is too large Load diff

124
libunicode.h Normal file
View file

@ -0,0 +1,124 @@
/*
* Unicode utilities
*
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef LIBUNICODE_H
#define LIBUNICODE_H
#include <inttypes.h>
#define LRE_BOOL int /* for documentation purposes */
/* define it to include all the unicode tables (40KB larger) */
#define CONFIG_ALL_UNICODE
#define LRE_CC_RES_LEN_MAX 3
typedef enum {
UNICODE_NFC,
UNICODE_NFD,
UNICODE_NFKC,
UNICODE_NFKD,
} UnicodeNormalizationEnum;
int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
LRE_BOOL lre_is_cased(uint32_t c);
LRE_BOOL lre_is_case_ignorable(uint32_t c);
/* char ranges */
typedef struct {
int len; /* in points, always even */
int size;
uint32_t *points; /* points sorted by increasing value */
void *mem_opaque;
void *(*realloc_func)(void *opaque, void *ptr, size_t size);
} CharRange;
typedef enum {
CR_OP_UNION,
CR_OP_INTER,
CR_OP_XOR,
} CharRangeOpEnum;
void cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
void cr_free(CharRange *cr);
int cr_realloc(CharRange *cr, int size);
int cr_copy(CharRange *cr, const CharRange *cr1);
static inline int cr_add_point(CharRange *cr, uint32_t v)
{
if (cr->len >= cr->size) {
if (cr_realloc(cr, cr->len + 1))
return -1;
}
cr->points[cr->len++] = v;
return 0;
}
static inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2)
{
if ((cr->len + 2) > cr->size) {
if (cr_realloc(cr, cr->len + 2))
return -1;
}
cr->points[cr->len++] = c1;
cr->points[cr->len++] = c2;
return 0;
}
int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len);
static inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2)
{
uint32_t b_pt[2];
b_pt[0] = c1;
b_pt[1] = c2 + 1;
return cr_union1(cr, b_pt, 2);
}
int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
const uint32_t *b_pt, int b_len, int op);
int cr_invert(CharRange *cr);
#ifdef CONFIG_ALL_UNICODE
LRE_BOOL lre_is_id_start(uint32_t c);
LRE_BOOL lre_is_id_continue(uint32_t c);
int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
UnicodeNormalizationEnum n_type,
void *opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
/* Unicode character range functions */
int unicode_script(CharRange *cr,
const char *script_name, LRE_BOOL is_ext);
int unicode_general_category(CharRange *cr, const char *gc_name);
int unicode_prop(CharRange *cr, const char *prop_name);
#endif /* CONFIG_ALL_UNICODE */
#undef LRE_BOOL
#endif /* LIBUNICODE_H */

115
search.c
View file

@ -26,6 +26,18 @@
#include "qe.h"
#include "variables.h"
#ifdef CONFIG_REGEX
#include "libregexp.h"
BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size) {
return FALSE;
}
void *lre_realloc(void *opaque, void *ptr, size_t size) {
return qe_realloc(&ptr, size);
}
#endif
/* Search stuff */
#define SEARCH_FLAG_DEFAULT SEARCH_FLAG_SMARTCASE
@ -164,6 +176,93 @@ static int eb_search(EditBuffer *b, int dir, int flags,
}
}
#ifdef CONFIG_REGEX
if (flags & SEARCH_FLAG_REGEX) {
char error_message[100];
char source[SEARCH_LENGTH];
int source_len;
uint8_t *regexp_bytes = NULL;
int regexp_len;
uint8_t **capture = NULL;
int capture_num;
int res = 0;
int re_flags = 0;
int found;
re_flags |= LRE_FLAG_MULTILINE;
if (flags & SEARCH_FLAG_IGNORECASE)
re_flags |= LRE_FLAG_IGNORECASE;
if (dir < 0)
re_flags |= LRE_FLAG_STICKY;
source_len = char32_to_utf8(source, countof(source), buf, len);
if (source_len >= countof(source))
return -1;
regexp_bytes = lre_compile(&regexp_len, error_message, sizeof(error_message),
source, source_len, re_flags, NULL);
if (regexp_bytes == NULL) {
//put_status(NULL, "regexp compile error: %s", error_message);
return -1;
}
capture_num = lre_get_capture_count(regexp_bytes);
capture = qe_malloc_array(uint8_t *, 2 * capture_num);
if (capture_num == 0 || capture == NULL) {
qe_free(&regexp_bytes);
qe_free(&capture);
//put_status(NULL, "cannot allocate capture array for %d entries", capture_num);
return -1;
}
for (offset1 = offset;;) {
if (dir < 0) {
if (offset == 0)
break;
offset = eb_prev(b, offset);
} else {
offset = offset1;
if (offset >= end_offset)
break;
offset1 = eb_next(b, offset);
}
if ((offset & 0xffff) == 0) {
/* check for search abort every 64K */
if (abort_func && abort_func(abort_opaque)) {
res = -1;
break;
}
}
/* Pass boundary characters to match $ and \b or \B */
found = lre_exec(capture, regexp_bytes,
(const uint8_t *)b, offset, end_offset, 0, NULL,
eb_prevc(b, offset, &offset3), eb_nextc(b, end_offset, &offset3),
(unsigned int (*)(const uint8_t *bc_buf, int offset, int *offsetp))eb_nextc,
(unsigned int (*)(const uint8_t *bc_buf, int offset, int *offsetp))eb_prevc);
if (found < 0) {
res = -1;
break;
}
if (found > 0) {
int start = capture[0] - (uint8_t *)(void *)b;
int end = capture[1] - (uint8_t *)(void *)b;
if ((dir >= 0 || end <= end_offset)
&& (!(flags & SEARCH_FLAG_WORD) ||
(qe_isword(eb_prevc(b, start, &offset3)) &&
qe_isword(eb_nextc(b, end, &offset3)))))
{
*found_offset = start;
*found_end = end;
res = 1;
break;
}
}
if (dir >= 0)
break;
}
qe_free(&regexp_bytes);
qe_free(&capture);
return res;
}
#endif
for (offset1 = offset;;) {
if (dir < 0) {
if (offset == 0)
@ -385,6 +484,12 @@ static void isearch_run(ISearchState *is) {
s->region_style = 0;
is->found_offset = -1;
} else {
if (search_offset == is->found_offset
&& search_offset == is->found_end) {
/* zero width match: skip one character */
if (is->dir > 0)
search_offset = eb_next(s->b, search_offset);
}
if (eb_search(s->b, is->dir, flags,
search_offset, s->b->total_size,
is->search_u32, is->search_u32_len,
@ -856,6 +961,14 @@ void isearch_colorize_matches(EditState *s, char32_t *buf, int len,
if (found_offset >= offset_end)
break;
if (found_end <= found_offset) {
/* zero width match: skip one character.
* for example `a*` finds matches everywhere but should highlight
* all sequences of letters a
*/
offset = eb_next(b, found_end);
continue;
}
if (found_end > offset_start) {
/* Compute character positions */
start = 0;
@ -892,7 +1005,7 @@ typedef struct QueryReplaceState {
char32_t search_u32[SEARCH_LENGTH]; /* code points */
/* query-replace */
char replace_str[SEARCH_LENGTH * 3]; /* may be in hex */
char32_t replace_u32[SEARCH_LENGTH]; /* code points (useless?) */
char32_t replace_u32[SEARCH_LENGTH]; /* code points */
} QueryReplaceState;
static void query_replace_help(QueryReplaceState *is) {