/src/r-source/src/main/grep.c
Line | Count | Source |
1 | | /* |
2 | | * R : A Computer Language for Statistical Data Analysis |
3 | | * Copyright (C) 1997--2026 The R Core Team |
4 | | * Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Pulic License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, a copy is available at |
18 | | * https://www.R-project.org/Licenses/ |
19 | | */ |
20 | | |
21 | | /* |
22 | | |
23 | | Support for UTF-8-encoded strings in non-UTF-8 locales |
24 | | ====================================================== |
25 | | |
26 | | strsplit grep [g]sub [g]regexpr |
27 | | handle UTF-8 directly if fixed/perl = TRUE, via wchar_t for extended |
28 | | |
29 | | As from R 4.1.0 we translate latin1 strings in a non-latin1-locale to UTF-8. |
30 | | |
31 | | */ |
32 | | |
33 | | /* It is possible to use TRE for fixed = TRUE. |
34 | | The main benefit would be code simplification: however, the |
35 | | special-purpose code is substantially faster, so we no longer |
36 | | plan to do so. |
37 | | */ |
38 | | |
39 | | /* PCRE supports only single-byte locales and UTF-8, so we convert |
40 | | inputs in all other MBCS locales to UTF-8. |
41 | | |
42 | | In [g]sub and [g]regexpr we need to know match positions in |
43 | | characters. To avoid yet more cases we handle all MBCS locales in |
44 | | wchar in ERE for those functions. (Byte positions suffice for |
45 | | [g]sub(fixed = TRUE), and [g]regexpr needs to convert to char |
46 | | positions for all MBCSs.) |
47 | | */ |
48 | | |
49 | | #ifdef HAVE_CONFIG_H |
50 | | # include <config.h> |
51 | | #endif |
52 | | |
53 | | #ifdef HAVE_SYS_TYPES_H |
54 | | # include <sys/types.h> // for size_t |
55 | | #endif |
56 | | |
57 | | /* interval at which to check interrupts */ |
58 | | /* if re-enabling, consider a power of two */ |
59 | | /* #define NINTERRUPT 1000000 */ |
60 | | |
61 | | /* How many encoding warnings to give */ |
62 | 14 | #define NWARN 5 |
63 | | |
64 | | #include <Defn.h> |
65 | | #include <Internal.h> |
66 | | #include <R_ext/RS.h> /* for R_Calloc/R_Free */ |
67 | | #include <ctype.h> |
68 | | #include <wchar.h> |
69 | | #include <wctype.h> /* for wctrans_t */ |
70 | | |
71 | | /* As from TRE 0.8.0, tre.h replaces regex.h */ |
72 | | #include <tre/tre.h> |
73 | | |
74 | | #ifdef HAVE_PCRE2 |
75 | | /* PCRE2_CODE_UNIT_WIDTH is defined to 8 via config.h */ |
76 | | # include<pcre2.h> |
77 | | #else |
78 | | /* |
79 | | Some systems might have pcre headers in a subdirectory -- not seen recently. |
80 | | */ |
81 | | # ifdef HAVE_PCRE_PCRE_H |
82 | | # include <pcre/pcre.h> |
83 | | # else |
84 | | # include <pcre.h> |
85 | | # endif |
86 | | #endif |
87 | | |
88 | | /* |
89 | | Default maximum stack size: note this is reserved but not allocated |
90 | | until needed. The help says 1M suffices, but we found more was |
91 | | needed for strings around a million bytes. |
92 | | */ |
93 | 3 | #define JIT_STACK_MAX 64*1024*1024 |
94 | | /* |
95 | | This will stay reserved until the end of the session, but at 64MB |
96 | | that is not an issue -- and most sessions will not use PCRE with |
97 | | more than 10 strings. |
98 | | */ |
99 | | |
100 | | #ifdef HAVE_PCRE2 |
101 | | static pcre2_jit_stack *jit_stack = NULL; // allocated at first use. |
102 | | #else |
103 | | static pcre_jit_stack *jit_stack = NULL; // allocated at first use. |
104 | | #endif |
105 | | |
106 | | static int jit_stack_size(void) |
107 | 3 | { |
108 | 3 | int stmax = JIT_STACK_MAX; |
109 | 3 | char *p = getenv("R_PCRE_JIT_STACK_MAXSIZE"); |
110 | 3 | if (p) { |
111 | 0 | char *endp; |
112 | 0 | double xdouble = R_strtod(p, &endp); |
113 | 0 | if (xdouble >= 0 && xdouble <= 1000) |
114 | 0 | stmax = (int)(xdouble*1024*1024); |
115 | 0 | else warning ("R_PCRE_JIT_STACK_MAXSIZE invalid and ignored"); |
116 | 0 | } |
117 | 3 | return stmax; |
118 | 3 | } |
119 | | |
120 | | #ifdef HAVE_PCRE2 |
121 | | static void setup_jit(pcre2_match_context *mcontext) |
122 | 34.0k | { |
123 | 34.0k | if (!jit_stack) |
124 | 3 | jit_stack = pcre2_jit_stack_create(32*1024, jit_stack_size(), NULL); |
125 | 34.0k | if (jit_stack) |
126 | 34.0k | pcre2_jit_stack_assign(mcontext, NULL, jit_stack); |
127 | 34.0k | } |
128 | | #else |
129 | | static void setup_jit(pcre_extra *re_pe) |
130 | | { |
131 | | if (!jit_stack) |
132 | | jit_stack = pcre_jit_stack_alloc(32*1024, jit_stack_size()); |
133 | | if (jit_stack) |
134 | | pcre_assign_jit_stack(re_pe, NULL, jit_stack); |
135 | | } |
136 | | #endif |
137 | | |
138 | | #ifndef MAX |
139 | 661k | # define MAX(a, b) ((a) > (b) ? (a) : (b)) |
140 | | #endif |
141 | | |
142 | | #ifndef isRaw |
143 | 0 | #define isRaw(x) (TYPEOF(x) == RAWSXP) |
144 | | #endif |
145 | | |
146 | | /* we allow pat == NULL if the regex cannot be safely expressed |
147 | | as a string (e.g., when using grepRaw) */ |
148 | | NORET static void reg_report(int rc, regex_t *reg, const char *pat) |
149 | 0 | { |
150 | 0 | char errbuf[1001]; |
151 | 0 | tre_regerror(rc, reg, errbuf, 1001); |
152 | 0 | if (pat) { |
153 | | /* PR#16600 - the regex may be so long that the TRE error description |
154 | | is truncated out from the message, so give also a warning */ |
155 | 0 | warning(_("TRE pattern compilation error '%s'"), errbuf); |
156 | 0 | error(_("invalid regular expression '%s', reason '%s'"), pat, errbuf); |
157 | 0 | } else |
158 | 0 | error(_("invalid regular expression, reason '%s'"), errbuf); |
159 | 0 | } |
160 | | |
161 | | /* wc must be zero-terminated, nc = wsclen(wc), maybe_ascii is TRUE if the input |
162 | | is probably pure ASCII. maybe_ascii is useful for regular expressions over |
163 | | long vectors (lines of text) where most lines are ASCII, but not all, to |
164 | | reduce the overhead of encoding conversions. */ |
165 | | static SEXP mkCharWLenASCII(const wchar_t *wc, int nc, bool maybe_ascii) |
166 | 857k | { |
167 | 857k | if (maybe_ascii) { |
168 | 759k | char *xi = R_Calloc(nc, char); |
169 | 5.53M | for(int i = 0; i < nc ; i++) { |
170 | 4.77M | unsigned int u = (unsigned int) wc[i]; |
171 | 4.77M | if (u > 127) { |
172 | 0 | R_Free(xi); |
173 | 0 | return mkCharWLenASCII(wc, nc, FALSE); |
174 | 0 | } |
175 | 4.77M | xi[i] = (char) u; |
176 | 4.77M | } |
177 | 759k | SEXP ans = mkCharLenCE(xi, nc, CE_UTF8); |
178 | 759k | R_Free(xi); |
179 | 759k | return ans; |
180 | 759k | } |
181 | | |
182 | | /* possibly not ASCII */ |
183 | 97.8k | size_t nb = ((size_t)nc + 1) * 4; |
184 | 97.8k | if (nb <= 8192) { |
185 | 97.6k | char xi[8192]; |
186 | 97.6k | nb = wcstoutf8(xi, wc, nb); |
187 | 97.6k | return mkCharLenCE(xi, (int)(nb-1), CE_UTF8); |
188 | 97.6k | } |
189 | | |
190 | 141 | nb = wcstoutf8(NULL, wc, (size_t)INT_MAX+2); |
191 | 141 | if (nb-1 > INT_MAX) |
192 | 0 | error("R character strings are limited to 2^31-1 bytes"); |
193 | 141 | char *xi = R_Calloc(nb, char); |
194 | 141 | nb = wcstoutf8(xi, wc, nb); |
195 | 141 | SEXP ans = mkCharLenCE(xi, (int)(nb-1), CE_UTF8); |
196 | 141 | R_Free(xi); |
197 | 141 | return ans; |
198 | 97.8k | } |
199 | | |
200 | | static SEXP markBytesOld(SEXP x, bool useBytes, bool haveBytesInput) |
201 | 1.90M | { |
202 | | /* If 1, mark results of gsub, sub, strsplit as "bytes" when using bytes |
203 | | and replacement, split did not happen. If 0, keep their original |
204 | | encoding flag (pre-82589 behavior, see markBytesResultIfNew). |
205 | | |
206 | | The intention of the marking (82589) was to avoid encoding flag |
207 | | instability caused by 82587, e.g. |
208 | | in gsub(weird_thing, "", useBytes=TRUE). The option is experimental |
209 | | and intended to be removed. |
210 | | |
211 | | Currently the default is the old behavior. |
212 | | */ |
213 | 1.90M | static int markBytesResultIfOld = -1; /* -1 to allow setting */ |
214 | | |
215 | 1.90M | if (markBytesResultIfOld == -1) { |
216 | 32 | char *p = getenv("_R_REGEX_MARK_OLD_RESULT_AS_BYTES_"); |
217 | 32 | markBytesResultIfOld = (p && StringTrue(p)) ? 1 : 0; |
218 | 32 | } |
219 | 1.90M | if (!markBytesResultIfOld || !haveBytesInput || |
220 | 0 | !useBytes || IS_ASCII(x) || IS_BYTES(x) || x == NA_STRING) |
221 | | |
222 | 1.90M | return x; |
223 | 0 | else |
224 | 0 | return mkCharLenCE(CHAR(x), LENGTH(x), CE_BYTES); |
225 | 1.90M | } |
226 | | |
227 | | static SEXP mkBytesNew(const char *name, bool haveBytesInput) |
228 | 4.07M | { |
229 | | /* If 1, mark results of gsub, sub, strsplit as "bytes" when using bytes |
230 | | and replacement or split happened. If 0 and no input was marked as |
231 | | "bytes", mark results as native/unknown, possibly creating an invalid |
232 | | string (pre-82587 behavior). This option is experimental and intended |
233 | | to be removed. |
234 | | |
235 | | Currently the default is the old behavior when no input is marked as |
236 | | "bytes". However, the new behavior applies when the input includes |
237 | | a string marked as "bytes". |
238 | | */ |
239 | 4.07M | static int markBytesResultIfNew = -1; |
240 | | |
241 | 4.07M | if (markBytesResultIfNew == -1) { |
242 | 32 | char *p = getenv("_R_REGEX_MARK_NEW_RESULT_AS_BYTES_"); |
243 | 32 | markBytesResultIfNew = (p && StringTrue(p)) ? 1 : 0; |
244 | 32 | } |
245 | 4.07M | if (haveBytesInput || markBytesResultIfNew) |
246 | 0 | return mkCharCE(name, CE_BYTES); |
247 | 4.07M | else |
248 | 4.07M | return mkCharCE(name, CE_NATIVE); |
249 | 4.07M | } |
250 | | |
251 | | #ifdef HAVE_PCRE2 |
252 | | static void R_pcre_exec_error(int rc, R_xlen_t i) |
253 | 8.82M | { |
254 | 8.82M | if (rc >= 0 || rc == PCRE2_ERROR_NOMATCH) |
255 | 8.82M | return; |
256 | | // too much effort to handle long-vector indices, including on Windows |
257 | 0 | char buf[256]; |
258 | 0 | pcre2_get_error_message(rc, (PCRE2_UCHAR *)buf, sizeof(buf)); |
259 | 0 | if(streql(buf, "recursion limit exceeded")) |
260 | 0 | strcat(buf, ": consider increasing the C stack size for the R process"); |
261 | 0 | warning(_("PCRE error\n\t'%s'\n\tfor element %d"), buf, (int) i + 1); |
262 | 0 | } |
263 | | #else |
264 | | static void R_pcre_exec_error(int rc, R_xlen_t i) |
265 | | { |
266 | | if (rc > -2) return; |
267 | | // too much effort to handle long-vector indices, including on Windows |
268 | | switch (rc) { |
269 | | # ifdef PCRE_ERROR_JIT_STACKLIMIT |
270 | | case PCRE_ERROR_JIT_STACKLIMIT: |
271 | | warning("JIT stack limit reached in PCRE for element %d", |
272 | | (int) i + 1); |
273 | | break; |
274 | | # endif |
275 | | case PCRE_ERROR_MATCHLIMIT: |
276 | | warning("back-tracking limit reached in PCRE for element %d", |
277 | | (int) i + 1); |
278 | | break; |
279 | | case PCRE_ERROR_RECURSIONLIMIT: |
280 | | warning("recursion limit reached in PCRE for element %d\n consider increasing the C stack size for the R process", |
281 | | (int) i + 1); |
282 | | break; |
283 | | case PCRE_ERROR_INTERNAL: |
284 | | case PCRE_ERROR_UNKNOWN_OPCODE: |
285 | | warning("unexpected internal error in PCRE for element %d", |
286 | | (int) i + 1); |
287 | | break; |
288 | | # ifdef PCRE_ERROR_RECURSELOOP |
289 | | case PCRE_ERROR_RECURSELOOP: |
290 | | warning("PCRE detected a recursive loop in the pattern for element %d", |
291 | | (int) i + 1); |
292 | | break; |
293 | | # endif |
294 | | } |
295 | | } |
296 | | #endif |
297 | | |
298 | | /* returns value allocated on R_alloc stack */ |
299 | | static const char *to_native(const char *str, bool use_UTF8) |
300 | 186 | { |
301 | 186 | return use_UTF8 ? reEnc(str, CE_UTF8, CE_NATIVE, 1) : str; |
302 | 186 | } |
303 | | |
304 | | static bool only_ascii(SEXP x, R_xlen_t len) |
305 | 1.14M | { |
306 | 1.14M | R_xlen_t i; |
307 | | |
308 | 5.87M | for(i = 0; i < len; i++) |
309 | 4.74M | if (!IS_ASCII(STRING_ELT(x, i)) && STRING_ELT(x, i) != NA_STRING) |
310 | 24.3k | return false; |
311 | 1.12M | return true; |
312 | 1.14M | } |
313 | | |
314 | | static bool have_bytes(SEXP x, R_xlen_t len) |
315 | 820k | { |
316 | 820k | R_xlen_t i; |
317 | | |
318 | 11.8M | for(i = 0; i < len; i++) |
319 | 11.0M | if (IS_BYTES(STRING_ELT(x, i))) return true; |
320 | 820k | return false; |
321 | 820k | } |
322 | | |
323 | | static bool have_utf8(SEXP x, R_xlen_t len) |
324 | 59.1k | { |
325 | 59.1k | R_xlen_t i; |
326 | | |
327 | 1.02M | for(i = 0; i < len; i++) |
328 | 985k | if (IS_UTF8(STRING_ELT(x, i))) return true; |
329 | 42.8k | return false; |
330 | 59.1k | } |
331 | | |
332 | | static bool have_latin1(SEXP x, R_xlen_t len) |
333 | 18.0k | { |
334 | 18.0k | R_xlen_t i; |
335 | | |
336 | 36.0k | for(i = 0; i < len; i++) |
337 | 18.0k | if (IS_LATIN1(STRING_ELT(x, i))) return true; |
338 | 18.0k | return false; |
339 | 18.0k | } |
340 | | |
341 | | #ifdef HAVE_PCRE2 |
342 | | # if PCRE2_MAJOR < 10 || (PCRE2_MAJOR == 10 && PCRE2_MINOR < 30) |
343 | | # define R_PCRE_LIMIT_RECURSION |
344 | | # endif |
345 | | #else |
346 | | # define R_PCRE_LIMIT_RECURSION |
347 | | #endif |
348 | | |
349 | | #ifdef R_PCRE_LIMIT_RECURSION |
350 | | static bool use_recursion_limit(SEXP subject) |
351 | | { |
352 | | bool use_limit = false; |
353 | | if (R_PCRE_limit_recursion == NA_LOGICAL) { |
354 | | // use recursion limit only on long strings |
355 | | R_xlen_t i; |
356 | | R_xlen_t len = XLENGTH(subject); |
357 | | for (i = 0 ; i < len ; i++) |
358 | | if (strlen(CHAR(STRING_ELT(subject, i))) >= 1000) { |
359 | | use_limit = true; |
360 | | break; |
361 | | } |
362 | | } else if (R_PCRE_limit_recursion) |
363 | | use_limit = true; |
364 | | return use_limit; |
365 | | } |
366 | | |
367 | | static long R_pcre_max_recursions() |
368 | | { |
369 | | uintptr_t ans, stack_used, current_frame; |
370 | | /* Approximate size of stack frame in PCRE match(), actually |
371 | | platform / compiler dependent. Estimate found at |
372 | | https://bugs.r-project.org/show_bug.cgi?id=16757 |
373 | | However, it seems that on Solaris compiled with cc, the size is |
374 | | much larger (not too surprising as that happens with R's |
375 | | parser). OTOH, OpenCSW's builds of PCRE are built to use the |
376 | | heap for recursion. |
377 | | */ |
378 | | const uintptr_t recursion_size = 600; |
379 | | |
380 | | const uintptr_t fallback_used = 10000; |
381 | | /* This is about 6MB stack, reasonable since stacks are usually >= 8MB |
382 | | OTOH, the out-of-box limit is 10000000. |
383 | | */ |
384 | | const long fallback_limit = 10000; |
385 | | /* Was PCRE compiled to use stack or heap for recursion? 1=stack */ |
386 | | int use_recursion; |
387 | | # ifdef HAVE_PCRE2 |
388 | | pcre2_config(PCRE2_CONFIG_STACKRECURSE, &use_recursion); |
389 | | /* from PCRE2 10.30, use_recursion is always false */ |
390 | | # else |
391 | | pcre_config(PCRE_CONFIG_STACKRECURSE, &use_recursion); |
392 | | # endif |
393 | | if (!use_recursion) return -1L; |
394 | | if (R_CStackLimit == -1) return fallback_limit; |
395 | | current_frame = (uintptr_t) &ans; |
396 | | /* Approximate number of bytes used in the stack, or fallback */ |
397 | | if (R_CStackDir == 1) { |
398 | | stack_used = (R_CStackStart >= current_frame) ? |
399 | | R_CStackStart - current_frame : fallback_used; |
400 | | } else { |
401 | | stack_used = (current_frame >= R_CStackStart) ? |
402 | | current_frame - R_CStackStart : fallback_used; |
403 | | } |
404 | | if (stack_used >= R_CStackLimit) return 0L; |
405 | | ans = (R_CStackLimit - stack_used) / recursion_size; |
406 | | return (long) ((ans <= LONG_MAX) ? ans : -1L); |
407 | | } |
408 | | #endif |
409 | | |
410 | | #ifdef HAVE_PCRE2 |
411 | | static void |
412 | | R_pcre2_prepare(const char *pattern, SEXP subject, bool use_UTF8, |
413 | | bool caseless, const unsigned char **tables, |
414 | | pcre2_code **re, pcre2_match_context **mcontext) |
415 | 34.1k | { |
416 | 34.1k | int errcode; |
417 | 34.1k | PCRE2_SIZE erroffset; |
418 | 34.1k | uint32_t options = 0; |
419 | 34.1k | pcre2_compile_context *ccontext = NULL; |
420 | | |
421 | 34.1k | if (use_UTF8) |
422 | 14.4k | options |= PCRE2_UTF | PCRE2_NO_UTF_CHECK; |
423 | 19.7k | else { |
424 | 19.7k | ccontext = pcre2_compile_context_create(NULL); |
425 | | /* PCRE2 internal tables by default are only for ASCII characters. |
426 | | They are needed for lower/upper case distinction and character |
427 | | classes in non-UTF mode. */ |
428 | 19.7k | if (!*tables) |
429 | 19.7k | *tables = pcre2_maketables(NULL); |
430 | 19.7k | pcre2_set_character_tables(ccontext, *tables); |
431 | 19.7k | } |
432 | 34.1k | if (caseless) |
433 | 0 | options |= PCRE2_CASELESS; |
434 | | |
435 | 34.1k | *re = pcre2_compile((PCRE2_SPTR) pattern, PCRE2_ZERO_TERMINATED, options, |
436 | 34.1k | &errcode, &erroffset, ccontext); |
437 | 34.1k | if (!*re) { |
438 | | /* not managing R_alloc stack because this ends in error */ |
439 | 93 | char buf[256]; |
440 | 93 | pcre2_get_error_message(errcode, (PCRE2_UCHAR *)buf, sizeof(buf)); |
441 | 93 | pcre2_compile_context_free(ccontext); |
442 | 93 | warning(_("PCRE pattern compilation error\n\t'%s'\n\tat '%s'\n"), buf, |
443 | 93 | to_native(pattern + erroffset, use_UTF8)); |
444 | 93 | error(_("invalid regular expression '%s'"), |
445 | 93 | to_native(pattern, use_UTF8)); |
446 | 93 | } |
447 | 34.1k | pcre2_compile_context_free(ccontext); |
448 | 34.1k | *mcontext = pcre2_match_context_create(NULL); |
449 | 34.1k | if (R_PCRE_use_JIT) { |
450 | 34.0k | int rc = pcre2_jit_compile(*re, 0); |
451 | 34.0k | if (rc && rc != PCRE2_ERROR_JIT_BADOPTION) { |
452 | | /* PCRE2_ERROR_JIT_BADOPTION is returned when JIT support is not |
453 | | compiled in PCRE2 library */ |
454 | 0 | char buf[256]; |
455 | 0 | pcre2_get_error_message(rc, (PCRE2_UCHAR *)buf, sizeof(buf)); |
456 | 0 | warning(_("PCRE JIT compilation error\n\t'%s'"), buf); |
457 | 0 | } |
458 | 34.0k | if (!rc) |
459 | 34.0k | setup_jit(*mcontext); |
460 | 34.0k | } |
461 | | # ifdef R_PCRE_LIMIT_RECURSION |
462 | | if (use_recursion_limit(subject)) |
463 | | pcre2_set_recursion_limit(*mcontext, (uint32_t) R_pcre_max_recursions()); |
464 | | |
465 | | /* we could use set_depth_limit() in newer versions, but the memory limit |
466 | | imposed then depends on the regular expression, and the values have |
467 | | different meaning from those for recursion limit in versions before |
468 | | 10.30 */ |
469 | | # endif |
470 | 34.1k | } |
471 | | #else /* ! HAVE_PCRE2 */ |
472 | | static void |
473 | | set_pcre_recursion_limit(pcre_extra **re_pe_ptr, const long limit) |
474 | | { |
475 | | if (limit >= 0) { |
476 | | pcre_extra *re_pe = *re_pe_ptr; |
477 | | if (!re_pe) { |
478 | | // this will be freed by pcre_free_study so cannot use R_Calloc |
479 | | re_pe = (pcre_extra *) calloc(1, sizeof(pcre_extra)); |
480 | | if (!re_pe) { |
481 | | warning("allocation failure in set_pcre_recursion_limit"); |
482 | | return; |
483 | | } |
484 | | re_pe->flags = PCRE_EXTRA_MATCH_LIMIT_RECURSION; |
485 | | *re_pe_ptr = re_pe; |
486 | | } else |
487 | | re_pe->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION; |
488 | | re_pe->match_limit_recursion = (unsigned long) limit; |
489 | | } |
490 | | } |
491 | | |
492 | | static void |
493 | | R_pcre_prepare(const char *pattern, SEXP subject, bool use_UTF8, |
494 | | bool caseless, bool always_study, |
495 | | const unsigned char **tables, pcre **re, pcre_extra **re_extra) |
496 | | { |
497 | | int erroffset; |
498 | | const char *errorptr; |
499 | | int options = 0; |
500 | | R_xlen_t len = XLENGTH(subject); |
501 | | bool pcre_st = always_study || |
502 | | (R_PCRE_study == -2 ? false : len >= R_PCRE_study); |
503 | | |
504 | | if (use_UTF8) |
505 | | options |= PCRE_UTF8; |
506 | | if (caseless) |
507 | | options |= PCRE_CASELESS; |
508 | | if (!*tables) |
509 | | // PCRE docs say this is not needed, but it is on Windows |
510 | | *tables = pcre_maketables(); |
511 | | *re = pcre_compile(pattern, options, &errorptr, &erroffset, *tables); |
512 | | if (!*re) { |
513 | | if (errorptr) |
514 | | warning(_("PCRE pattern compilation error\n\t'%s'\n\tat '%s'\n"), |
515 | | errorptr, to_native(pattern + erroffset, use_UTF8)); |
516 | | /* in R 3.6 and earlier strsplit reported "invalid split pattern" */ |
517 | | error(_("invalid regular expression '%s'"), |
518 | | to_native(pattern, use_UTF8)); |
519 | | } |
520 | | if (pcre_st) { |
521 | | *re_extra = pcre_study(*re, |
522 | | R_PCRE_use_JIT ? PCRE_STUDY_JIT_COMPILE : 0, |
523 | | &errorptr); |
524 | | if (errorptr) |
525 | | warning(_("PCRE pattern study error\n\t'%s'\n"), errorptr); |
526 | | else if (R_PCRE_use_JIT) |
527 | | setup_jit(*re_extra); |
528 | | } |
529 | | /* FIXME: do not set recursion limit when JIT compilation succeeded? */ |
530 | | if (use_recursion_limit(subject)) |
531 | | set_pcre_recursion_limit(re_extra, R_pcre_max_recursions()); |
532 | | } |
533 | | #endif |
534 | | |
535 | | // FIXME: Protect PCRE/PCRE2 data via contexts (as well as other data). |
536 | | // FIXME: Do not rebuild locale tables repeatedly. |
537 | | // FIXME: There is no documented way to free locale tables with PCRE2. |
538 | | // Using free() would not work on Windows if PCRE2 is dynamically |
539 | | // linked but uses a different C runtime from R. |
540 | | |
541 | | /* strsplit is going to split the strings in the first argument into |
542 | | * tokens depending on the second argument. The characters of the second |
543 | | * argument are used to split the first argument. A list of vectors is |
544 | | * returned of length equal to the input vector x, each element of the |
545 | | * list is the collection of splits for the corresponding element of x. |
546 | | */ |
547 | | |
548 | | attribute_hidden SEXP do_strsplit(SEXP call, SEXP op, SEXP args, SEXP env) |
549 | 294k | { |
550 | 294k | SEXP args0 = args, ans, tok, x; |
551 | 294k | R_xlen_t i, itok, len, tlen; |
552 | 294k | size_t j, ntok; |
553 | 294k | bool fixed_opt, perl_opt, useBytes; |
554 | 294k | char *pt = NULL; wchar_t *wpt = NULL; |
555 | 294k | const char *buf, *split = "", *bufp; |
556 | 294k | const unsigned char *tables = NULL; |
557 | 294k | bool use_UTF8 = false; |
558 | 294k | const void *vmax, *vmax2; |
559 | 294k | int nwarn = 0; |
560 | 294k | bool haveBytesInput; |
561 | | |
562 | 294k | checkArity(op, args); |
563 | 294k | x = CAR(args); args = CDR(args); |
564 | 294k | tok = CAR(args); args = CDR(args); |
565 | 294k | fixed_opt = asBool2(CAR(args), call); args = CDR(args); |
566 | 294k | perl_opt = asBool2(CAR(args), call); args = CDR(args); |
567 | 294k | useBytes = asBool2(CAR(args), call); |
568 | 294k | if (fixed_opt && perl_opt) { |
569 | 0 | warning(_("argument '%s' will be ignored"), "perl = TRUE"); |
570 | 0 | perl_opt = 0; |
571 | 0 | } |
572 | | |
573 | 294k | if (!isString(x) || !isString(tok)) error(_("non-character argument")); |
574 | | |
575 | | |
576 | 294k | len = XLENGTH(x); |
577 | 294k | tlen = XLENGTH(tok); |
578 | | |
579 | | /* treat split = NULL as split = "" */ |
580 | 294k | if (!tlen) { tlen = 1; SETCADR(args0, tok = mkString("")); } |
581 | 294k | PROTECT(tok); |
582 | | |
583 | 294k | haveBytesInput = have_bytes(tok, tlen) || have_bytes(x, len); |
584 | 294k | if (!useBytes) |
585 | 294k | useBytes = only_ascii(tok, tlen) && only_ascii(x, len); |
586 | 294k | if (!useBytes) |
587 | 4.29k | useBytes = haveBytesInput; |
588 | 294k | if (!useBytes) { |
589 | | // use_UTF8 means use wchar_t* for the TRE engine |
590 | 4.29k | if (!fixed_opt && mbcslocale) use_UTF8 = true; |
591 | 4.29k | if (!use_UTF8) |
592 | 4.29k | use_UTF8 = have_utf8(tok, tlen) || have_utf8(x, len); |
593 | 4.29k | if (!use_UTF8 && !latin1locale) |
594 | 4.25k | use_UTF8 = have_latin1(tok, tlen) || have_latin1(x, len); |
595 | 4.29k | } |
596 | | |
597 | | /* group by token for efficiency with PCRE/TRE versions */ |
598 | 294k | PROTECT(ans = allocVector(VECSXP, len)); |
599 | 294k | vmax = vmaxget(); |
600 | 589k | for (itok = 0; itok < tlen; itok++) { |
601 | 294k | SEXP this = STRING_ELT(tok, itok); |
602 | | |
603 | 294k | if (this == NA_STRING) { /* NA token doesn't split */ |
604 | 0 | for (i = itok; i < len; i += tlen) |
605 | 0 | SET_VECTOR_ELT(ans, i, |
606 | 0 | ScalarString(markBytesOld(STRING_ELT(x, i), |
607 | 0 | useBytes, |
608 | 0 | haveBytesInput))); |
609 | 0 | continue; |
610 | 294k | } else if (!CHAR(this)[0]) { /* empty */ |
611 | 131k | vmax2 = vmaxget(); |
612 | 318k | for (i = itok; i < len; i += tlen) { |
613 | 187k | SEXP t; |
614 | 187k | if (STRING_ELT(x, i) == NA_STRING) { |
615 | 0 | SET_VECTOR_ELT(ans, i, ScalarString(NA_STRING)); |
616 | 0 | continue; |
617 | 0 | } |
618 | 187k | if (useBytes) |
619 | 185k | buf = CHAR(STRING_ELT(x, i)); |
620 | 1.29k | else if (use_UTF8) { |
621 | 0 | buf = trCharUTF82(STRING_ELT(x, i)); |
622 | 0 | if (!buf || !utf8Valid(buf)) { |
623 | 0 | if(nwarn++ < NWARN) |
624 | 0 | warning(_("input string %lld is invalid UTF-8"), |
625 | 0 | (long long)i+1); |
626 | 0 | SET_VECTOR_ELT(ans, i, ScalarString(NA_STRING)); |
627 | 0 | continue; |
628 | 0 | } |
629 | 1.29k | } else { |
630 | 1.29k | buf = translateCharFP2(STRING_ELT(x, i)); |
631 | 1.29k | if (!buf || (mbcslocale && !mbcsValid(buf))) { |
632 | 0 | if(nwarn++ < NWARN) |
633 | 0 | warning(_("input string %lld is invalid in this locale"), |
634 | 0 | (long long)i+1); |
635 | 0 | SET_VECTOR_ELT(ans, i, ScalarString(NA_STRING)); |
636 | 0 | continue; |
637 | 0 | } |
638 | 1.29k | } |
639 | 187k | if (!useBytes && (use_UTF8 || mbcslocale) && |
640 | 0 | !IS_ASCII(STRING_ELT(x, i))) { |
641 | | |
642 | | /* split into individual characters (not bytes) */ |
643 | 0 | char bf[20 /* > R_MB_CUR_MAX */]; |
644 | 0 | const char *p = buf; |
645 | 0 | size_t used; |
646 | 0 | mbstate_t mb_st; |
647 | 0 | ssize_t nt; /* need to check error on size_t */ |
648 | |
|
649 | 0 | if (use_UTF8) { |
650 | 0 | for (ntok = 0; *p; p += used, ntok++) |
651 | 0 | used = utf8clen(*p); |
652 | 0 | p = buf; |
653 | 0 | PROTECT(t = allocVector(STRSXP, ntok)); |
654 | 0 | for (j = 0; j < ntok; j++, p += used) { |
655 | 0 | used = utf8clen(*p); |
656 | 0 | memcpy(bf, p, used); bf[used] = '\0'; |
657 | 0 | SET_STRING_ELT(t, j, mkCharCE(bf, CE_UTF8)); |
658 | 0 | } |
659 | 0 | } else if ((nt = mbstowcs(NULL, buf, 0)) < 0) { |
660 | 0 | PROTECT(t = ScalarString(NA_STRING)); |
661 | 0 | } else { |
662 | 0 | ntok = nt; |
663 | 0 | mbs_init(&mb_st); |
664 | 0 | PROTECT(t = allocVector(STRSXP, ntok)); |
665 | 0 | for (j = 0; j < ntok; j++, p += used) { |
666 | | /* This is valid as we have already checked */ |
667 | 0 | used = mbrtowc(NULL, p, R_MB_CUR_MAX, &mb_st); |
668 | 0 | memcpy(bf, p, used); bf[used] = '\0'; |
669 | 0 | SET_STRING_ELT(t, j, markKnown(bf, STRING_ELT(x, i))); |
670 | 0 | } |
671 | 0 | } |
672 | 187k | } else { |
673 | | /* useBytes or ASCII or |
674 | | single-byte locale and not marked as UTF-8 */ |
675 | 187k | char bf[2]; |
676 | 187k | ntok = strlen(buf); |
677 | 187k | PROTECT(t = allocVector(STRSXP, ntok)); |
678 | 187k | bf[1] = '\0'; |
679 | 187k | if(useBytes) { |
680 | 2.50M | for (j = 0; j < ntok; j++) { |
681 | 2.32M | bf[0] = buf[j]; |
682 | 2.32M | SET_STRING_ELT(t, j, mkBytesNew(bf, haveBytesInput)); |
683 | 2.32M | } |
684 | 185k | } else { |
685 | 2.41M | for (j = 0; j < ntok; j++) { |
686 | 2.41M | bf[0] = buf[j]; |
687 | 2.41M | SET_STRING_ELT(t, j, markKnown(bf, STRING_ELT(x, i))); |
688 | 2.41M | } |
689 | 1.29k | } |
690 | 187k | } |
691 | 187k | SET_VECTOR_ELT(ans, i, t); |
692 | 187k | UNPROTECT(1); |
693 | 187k | vmaxset(vmax2); |
694 | 187k | } |
695 | 163k | } else if (fixed_opt) { |
696 | 156k | const char *laststart, *ebuf; |
697 | 156k | if (useBytes) |
698 | 155k | split = CHAR(STRING_ELT(tok, itok)); |
699 | 1.08k | else if (use_UTF8) { // includes Latin-1 support |
700 | 25 | split = trCharUTF82(STRING_ELT(tok, itok)); |
701 | 25 | if (!split || !utf8Valid(split)) |
702 | 4 | error(_("'split' string %lld is invalid UTF-8"), |
703 | 4 | (long long)itok+1); |
704 | 1.06k | } else { |
705 | 1.06k | split = translateCharFP2(STRING_ELT(tok, itok)); |
706 | 1.06k | if (!split || (mbcslocale && !mbcsValid(split))) |
707 | 0 | error(_("'split' string %lld is invalid in this locale"), |
708 | 0 | (long long)itok+1); |
709 | 1.06k | } |
710 | 156k | int slen = (int) strlen(split); |
711 | | |
712 | 156k | vmax2 = vmaxget(); |
713 | 640k | for (i = itok; i < len; i += tlen) { |
714 | 483k | SEXP t; |
715 | 483k | if (STRING_ELT(x, i) == NA_STRING) { |
716 | 0 | SET_VECTOR_ELT(ans, i, ScalarString(NA_STRING)); |
717 | 0 | continue; |
718 | 0 | } |
719 | | |
720 | 483k | if (useBytes) |
721 | 482k | buf = CHAR(STRING_ELT(x, i)); |
722 | 1.08k | else if (use_UTF8) { |
723 | 21 | buf = trCharUTF82(STRING_ELT(x, i)); |
724 | 21 | if (!buf || !utf8Valid(buf)) { |
725 | 9 | if(nwarn++ < NWARN) |
726 | 9 | warning(_("input string %lld is invalid UTF-8"), |
727 | 9 | (long long)i+1); |
728 | 9 | SET_VECTOR_ELT(ans, i, ScalarString(NA_STRING)); |
729 | 9 | continue; |
730 | 9 | } |
731 | 1.06k | } else { |
732 | 1.06k | buf = translateCharFP2(STRING_ELT(x, i)); |
733 | 1.06k | if (!buf || (mbcslocale && !mbcsValid(buf))) { |
734 | 0 | if(nwarn++ < NWARN) |
735 | 0 | warning(_("input string %lld is invalid in this locale"), |
736 | 0 | (long long)i+1); |
737 | 0 | SET_VECTOR_ELT(ans, i, ScalarString(NA_STRING)); |
738 | 0 | continue; |
739 | 0 | } |
740 | 1.06k | } |
741 | | /* find out how many splits there will be */ |
742 | 483k | size_t ntok = 0; |
743 | | /* This is UTF-8 safe since it compares whole strings */ |
744 | 483k | laststart = buf; |
745 | 483k | ebuf = buf + strlen(buf); |
746 | 5.02M | for (bufp = buf; bufp < ebuf; bufp++) { |
747 | 4.54M | if ((slen == 1 && *bufp != *split) || |
748 | 4.35M | (slen > 1 && strncmp(bufp, split, slen))) continue; |
749 | 189k | ntok++; |
750 | 189k | bufp += MAX(slen - 1, 0); |
751 | 189k | laststart = bufp+1; |
752 | 189k | } |
753 | 483k | bufp = laststart; |
754 | 483k | SET_VECTOR_ELT(ans, i, |
755 | 483k | t = allocVector(STRSXP, ntok + (*bufp ? 1 : 0))); |
756 | | /* and fill with the splits */ |
757 | 483k | laststart = bufp = buf; |
758 | 483k | pt = R_Realloc(pt, strlen(buf)+1, char); |
759 | 672k | for (size_t j = 0; j < ntok; j++) { |
760 | | /* This is UTF-8 safe since it compares whole |
761 | | strings, but <MBCS-FIXME> it would be more |
762 | | efficient to skip along by chars. |
763 | | */ |
764 | 1.85M | for (; bufp < ebuf; bufp++) { |
765 | 1.85M | if ((slen == 1 && *bufp != *split) || |
766 | 1.66M | (slen > 1 && strncmp(bufp, split, slen))) continue; |
767 | 189k | if (slen) { |
768 | 189k | if (bufp > laststart) |
769 | 133k | memcpy(pt, laststart, bufp - laststart); |
770 | 189k | pt[bufp - laststart] = '\0'; |
771 | 189k | } else { |
772 | 0 | pt[0] = *bufp; pt[1] ='\0'; |
773 | 0 | } |
774 | 189k | bufp += MAX(slen-1, 0); |
775 | 189k | laststart = bufp+1; |
776 | 189k | if (useBytes) |
777 | 115k | SET_STRING_ELT(t, j, mkBytesNew(pt, haveBytesInput)); |
778 | 73.5k | else if (use_UTF8) |
779 | 66 | SET_STRING_ELT(t, j, mkCharCE(pt, CE_UTF8)); |
780 | 73.5k | else |
781 | 73.5k | SET_STRING_ELT(t, j, markKnown(pt, STRING_ELT(x, i))); |
782 | 189k | break; |
783 | 1.85M | } |
784 | 189k | bufp = laststart; |
785 | 189k | } |
786 | 483k | if (*bufp) { |
787 | 483k | if (useBytes) |
788 | 482k | SET_STRING_ELT(t, ntok, mkBytesNew(bufp, haveBytesInput)); |
789 | 997 | else if (use_UTF8) |
790 | 12 | SET_STRING_ELT(t, ntok, mkCharCE(bufp, CE_UTF8)); |
791 | 985 | else |
792 | 985 | SET_STRING_ELT(t, ntok, markKnown(bufp, STRING_ELT(x, i))); |
793 | 483k | } |
794 | 483k | vmaxset(vmax2); |
795 | 483k | } |
796 | 156k | } else if (perl_opt) { |
797 | 5.39k | if (useBytes) |
798 | 3.76k | split = CHAR(STRING_ELT(tok, itok)); |
799 | 1.62k | else if (use_UTF8) { |
800 | 16 | split = trCharUTF82(STRING_ELT(tok, itok)); |
801 | 16 | if (!split || !utf8Valid(split)) |
802 | 4 | error(_("'split' string %lld is invalid UTF-8"), |
803 | 4 | (long long)itok+1); |
804 | 1.61k | } else { |
805 | 1.61k | split = translateCharFP2(STRING_ELT(tok, itok)); |
806 | 1.61k | if (!split || (mbcslocale && !mbcsValid(split))) |
807 | 0 | error(_("'split' string %lld is invalid in this locale"), |
808 | 0 | (long long)itok+1); |
809 | 1.61k | } |
810 | 5.39k | #ifdef HAVE_PCRE2 |
811 | 5.39k | pcre2_code *re = NULL; |
812 | 5.39k | pcre2_match_context *mcontext = NULL; |
813 | 5.39k | PCRE2_SIZE *ovector = NULL; |
814 | 5.39k | uint32_t ovecsize = 10; |
815 | 5.39k | R_pcre2_prepare(split, x, use_UTF8, false, &tables, &re, &mcontext); |
816 | 5.39k | pcre2_match_data *mdata = pcre2_match_data_create(ovecsize, NULL); |
817 | 5.39k | uint32_t eflag = 0; |
818 | 5.39k | if (use_UTF8) eflag |= PCRE2_NO_UTF_CHECK; |
819 | | #else |
820 | | pcre *re_pcre = NULL; |
821 | | pcre_extra *re_pe = NULL; |
822 | | int ovecsize = 30; |
823 | | int ovector[ovecsize]; |
824 | | |
825 | | R_pcre_prepare(split, x, use_UTF8, false, true, &tables, &re_pcre, |
826 | | &re_pe); |
827 | | #endif |
828 | 5.39k | vmax2 = vmaxget(); |
829 | 10.6k | for (i = itok; i < len; i += tlen) { |
830 | 5.29k | SEXP t; |
831 | 5.29k | if (STRING_ELT(x, i) == NA_STRING) { |
832 | 0 | SET_VECTOR_ELT(ans, i, ScalarString(NA_STRING)); |
833 | 0 | continue; |
834 | 0 | } |
835 | | |
836 | 5.29k | if (useBytes) |
837 | 3.68k | buf = CHAR(STRING_ELT(x, i)); |
838 | 1.61k | else if (use_UTF8) { |
839 | 10 | buf = trCharUTF82(STRING_ELT(x, i)); |
840 | 10 | if (!buf || !utf8Valid(buf)) { |
841 | 5 | if(nwarn++ < NWARN) |
842 | 5 | warning(_("input string %lld is invalid UTF-8"), |
843 | 5 | (long long)i+1); |
844 | 5 | SET_VECTOR_ELT(ans, i, ScalarString(NA_STRING)); |
845 | 5 | continue; |
846 | 5 | } |
847 | 1.60k | } else { |
848 | 1.60k | buf = translateCharFP2(STRING_ELT(x, i)); |
849 | 1.60k | if (!buf || (mbcslocale && !mbcsValid(buf))) { |
850 | 0 | if(nwarn++ < NWARN) |
851 | 0 | warning(_("input string %lld is invalid in this locale"), |
852 | 0 | (long long)i+1); |
853 | 0 | SET_VECTOR_ELT(ans, i, ScalarString(NA_STRING)); |
854 | 0 | continue; |
855 | 0 | } |
856 | 1.60k | } |
857 | | /* find out how many splits there will be */ |
858 | 5.29k | ntok = 0; |
859 | 5.29k | bufp = buf; |
860 | 5.29k | if (*bufp) { |
861 | 5.28k | int rc; |
862 | 5.28k | #ifdef HAVE_PCRE2 |
863 | 466k | while((rc = pcre2_match(re, (PCRE2_SPTR) bufp, |
864 | 466k | PCRE2_ZERO_TERMINATED, |
865 | 466k | 0, eflag, mdata, mcontext)) >= 0) { |
866 | 461k | ovector = pcre2_get_ovector_pointer(mdata); |
867 | | #else |
868 | | while((rc = pcre_exec(re_pcre, re_pe, bufp, |
869 | | (int) strlen(bufp), |
870 | | 0, 0, ovector, ovecsize)) >= 0) { |
871 | | #endif |
872 | | /* Empty matches get the next char, so move by one. */ |
873 | 461k | if (ovector[1] > 0) |
874 | 367k | bufp += ovector[1]; |
875 | 94.4k | else if (*bufp) |
876 | | /* Only use_UTF8 input has been validated as UTF-8; |
877 | | utf8clen() on an arbitrary byte claims up to 6 and |
878 | | would run past the terminator. */ |
879 | 94.4k | bufp += use_UTF8 ? utf8clen(*bufp) : 1; |
880 | 461k | ntok++; |
881 | 461k | if (*bufp == '\0') |
882 | 465 | break; |
883 | 461k | } |
884 | 5.28k | R_pcre_exec_error(rc, i); |
885 | 5.28k | } |
886 | 5.29k | SET_VECTOR_ELT(ans, i, |
887 | 5.29k | t = allocVector(STRSXP, ntok + (*bufp ? 1 : 0))); |
888 | | /* and fill with the splits */ |
889 | 5.29k | bufp = buf; |
890 | 5.29k | pt = R_Realloc(pt, strlen(buf)+1, char); |
891 | 467k | for (j = 0; j < ntok; j++) { |
892 | 461k | #ifdef HAVE_PCRE2 |
893 | 461k | int rc = pcre2_match(re, (PCRE2_SPTR) bufp, |
894 | 461k | PCRE2_ZERO_TERMINATED, |
895 | 461k | 0, eflag, mdata, mcontext); |
896 | | #else |
897 | | int rc = pcre_exec(re_pcre, re_pe, bufp, |
898 | | (int) strlen(bufp), 0, 0, |
899 | | ovector, ovecsize); |
900 | | #endif |
901 | 461k | R_pcre_exec_error(rc, i); |
902 | 461k | if (ovector[1] > 0) { |
903 | | /* Match was non-empty. */ |
904 | 367k | if (ovector[0] > 0) |
905 | 366k | strncpy(pt, bufp, ovector[0]); |
906 | 367k | pt[ovector[0]] = '\0'; |
907 | 367k | bufp += ovector[1]; |
908 | 367k | } else { |
909 | | /* Match was empty. */ |
910 | 94.4k | int clen = use_UTF8 ? utf8clen(*bufp) : 1; |
911 | 94.4k | strncpy(pt, bufp, clen); |
912 | 94.4k | pt[clen] = '\0'; |
913 | 94.4k | bufp += clen; |
914 | 94.4k | } |
915 | 461k | if (useBytes) |
916 | 249k | SET_STRING_ELT(t, j, mkBytesNew(pt, haveBytesInput)); |
917 | 212k | else if (use_UTF8) |
918 | 4 | SET_STRING_ELT(t, j, mkCharCE(pt, CE_UTF8)); |
919 | 212k | else |
920 | 212k | SET_STRING_ELT(t, j, markKnown(pt, STRING_ELT(x, i))); |
921 | 461k | } |
922 | 5.29k | if (*bufp) { |
923 | 4.82k | if (useBytes) |
924 | 3.30k | SET_STRING_ELT(t, ntok, mkBytesNew(bufp, haveBytesInput)); |
925 | 1.51k | else if (use_UTF8) |
926 | 4 | SET_STRING_ELT(t, ntok, mkCharCE(bufp, CE_UTF8)); |
927 | 1.50k | else |
928 | 1.50k | SET_STRING_ELT(t, ntok, markKnown(bufp, STRING_ELT(x, i))); |
929 | 4.82k | } |
930 | 5.29k | vmaxset(vmax2); |
931 | 5.29k | } |
932 | 5.39k | #ifdef HAVE_PCRE2 |
933 | 5.39k | pcre2_match_data_free(mdata); |
934 | 5.39k | pcre2_code_free(re); |
935 | 5.39k | pcre2_match_context_free(mcontext); |
936 | | #else |
937 | | if(re_pe) pcre_free_study(re_pe); |
938 | | pcre_free(re_pcre); |
939 | | #endif |
940 | 5.39k | } else if (!useBytes && use_UTF8) { /* ERE in wchar_t */ |
941 | 0 | regex_t reg; |
942 | 0 | regmatch_t regmatch[1]; |
943 | 0 | int rc; |
944 | 0 | int cflags = REG_EXTENDED; |
945 | 0 | const wchar_t *wbuf, *wbufp, *wsplit; |
946 | | |
947 | | /* Careful: need to distinguish empty (rm_eo == 0) from |
948 | | non-empty (rm_eo > 0) matches. In the former case, the |
949 | | token extracted is the next character. Otherwise, it is |
950 | | everything before the start of the match, which may be |
951 | | the empty string (not a ``token'' in the strict sense). |
952 | | */ |
953 | |
|
954 | 0 | wsplit = wtransChar2(STRING_ELT(tok, itok)); |
955 | 0 | if (!wsplit) |
956 | 0 | error(_("'split' string %lld is invalid"), (long long)itok+1); |
957 | 0 | if ((rc = tre_regwcomp(®, wsplit, cflags))) |
958 | 0 | reg_report(rc, ®, translateChar(STRING_ELT(tok, itok))); |
959 | 0 | bool ascii_split = IS_ASCII(STRING_ELT(tok, itok)); |
960 | |
|
961 | 0 | vmax2 = vmaxget(); |
962 | 0 | for (i = itok; i < len; i += tlen) { |
963 | 0 | SEXP t; |
964 | 0 | if (STRING_ELT(x, i) == NA_STRING) { |
965 | 0 | SET_VECTOR_ELT(ans, i, ScalarString(NA_STRING)); |
966 | 0 | continue; |
967 | 0 | } |
968 | 0 | wbuf = wtransChar2(STRING_ELT(x, i)); |
969 | 0 | bool ascii_xi = IS_ASCII(STRING_ELT(x, i)); |
970 | 0 | if (!wbuf) { |
971 | 0 | if(nwarn++ < NWARN) |
972 | 0 | warning(_("input string %lld is invalid"), |
973 | 0 | (long long)i+1); |
974 | 0 | SET_VECTOR_ELT(ans, i, ScalarString(NA_STRING)); |
975 | 0 | continue; |
976 | 0 | } |
977 | | |
978 | | /* find out how many splits there will be */ |
979 | 0 | ntok = 0; |
980 | 0 | wbufp = wbuf; |
981 | 0 | if (*wbufp) { |
982 | 0 | while(tre_regwexec(®, wbufp, 1, regmatch, 0) == 0) { |
983 | | /* Empty matches get the next char, so move by one. */ |
984 | 0 | wbufp += MAX(regmatch[0].rm_eo, 1); |
985 | 0 | ntok++; |
986 | 0 | if (!*wbufp) break; |
987 | 0 | } |
988 | 0 | } |
989 | 0 | SET_VECTOR_ELT(ans, i, |
990 | 0 | t = allocVector(STRSXP, ntok + (*wbufp ? 1 : 0))); |
991 | | /* and fill with the splits */ |
992 | 0 | wbufp = wbuf; |
993 | 0 | wpt = R_Realloc(wpt, wcslen(wbuf)+1, wchar_t); |
994 | 0 | for (j = 0; j < ntok; j++) { |
995 | 0 | tre_regwexec(®, wbufp, 1, regmatch, 0); |
996 | 0 | if (regmatch[0].rm_eo > 0) { |
997 | | /* Match was non-empty. */ |
998 | 0 | if (regmatch[0].rm_so > 0) |
999 | 0 | wcsncpy(wpt, wbufp, regmatch[0].rm_so); |
1000 | 0 | wpt[regmatch[0].rm_so] = 0; |
1001 | 0 | wbufp += regmatch[0].rm_eo; |
1002 | 0 | } else { |
1003 | | /* Match was empty. */ |
1004 | 0 | wpt[0] = *wbufp; |
1005 | 0 | wpt[1] = 0; |
1006 | 0 | wbufp++; |
1007 | 0 | } |
1008 | 0 | SET_STRING_ELT(t, j, |
1009 | 0 | mkCharWLenASCII(wpt, regmatch[0].rm_so, |
1010 | 0 | ascii_split && ascii_xi)); |
1011 | 0 | } |
1012 | 0 | if (*wbufp) |
1013 | 0 | SET_STRING_ELT(t, ntok, |
1014 | 0 | mkCharWLenASCII(wbufp, (int) wcslen(wbufp), |
1015 | 0 | ascii_split && ascii_xi)); |
1016 | 0 | vmaxset(vmax2); |
1017 | 0 | } |
1018 | 0 | tre_regfree(®); |
1019 | 1.54k | } else { /* ERE in normal chars -- single byte */ |
1020 | | /* previously used also with MBCS */ |
1021 | 1.54k | regex_t reg; |
1022 | 1.54k | regmatch_t regmatch[1]; |
1023 | 1.54k | int rc; |
1024 | 1.54k | int cflags = REG_EXTENDED; |
1025 | | |
1026 | | /* Careful: need to distinguish empty (rm_eo == 0) from |
1027 | | non-empty (rm_eo > 0) matches. In the former case, the |
1028 | | token extracted is the next character. Otherwise, it is |
1029 | | everything before the start of the match, which may be |
1030 | | the empty string (not a ``token'' in the strict sense). |
1031 | | */ |
1032 | | /* never use_UTF8 */ |
1033 | 1.54k | if (useBytes) |
1034 | 1.26k | split = CHAR(STRING_ELT(tok, itok)); |
1035 | 280 | else { |
1036 | 280 | split = translateCharFP2(STRING_ELT(tok, itok)); |
1037 | 280 | if (!split || (mbcslocale && !mbcsValid(split))) |
1038 | 0 | error(_("'split' string %lld is invalid in this locale"), |
1039 | 0 | (long long)itok+1); |
1040 | 280 | } |
1041 | 1.54k | if (useBytes) |
1042 | 1.26k | rc = tre_regcompb(®, split, cflags); |
1043 | 280 | else |
1044 | 280 | rc = tre_regcomp(®, split, cflags); |
1045 | | |
1046 | 1.54k | if(rc) reg_report(rc, ®, split); |
1047 | | |
1048 | 1.54k | vmax2 = vmaxget(); |
1049 | 3.08k | for (i = itok; i < len; i += tlen) { |
1050 | 1.54k | SEXP t; |
1051 | 1.54k | if (STRING_ELT(x, i) == NA_STRING) { |
1052 | 0 | SET_VECTOR_ELT(ans, i, ScalarString(NA_STRING)); |
1053 | 0 | continue; |
1054 | 0 | } |
1055 | | /* never use_UTF8 */ |
1056 | 1.54k | if (useBytes) |
1057 | 1.26k | buf = CHAR(STRING_ELT(x, i)); |
1058 | 280 | else { |
1059 | 280 | buf = translateCharFP2(STRING_ELT(x, i)); |
1060 | 280 | if (!buf || (mbcslocale && !mbcsValid(buf))) { |
1061 | 0 | if(nwarn++ < NWARN) |
1062 | 0 | warning(_("input string %lld is invalid in this locale"), |
1063 | 0 | (long long)i+1); |
1064 | 0 | SET_VECTOR_ELT(ans, i, ScalarString(NA_STRING)); |
1065 | 0 | continue; |
1066 | 0 | } |
1067 | 280 | } |
1068 | | |
1069 | | /* find out how many splits there will be */ |
1070 | 1.54k | ntok = 0; |
1071 | 1.54k | bufp = buf; |
1072 | 1.54k | if (*bufp) { |
1073 | 1.50k | if (useBytes) { |
1074 | 231k | while(!(rc = tre_regexecb(®, bufp, 1, regmatch, 0))) { |
1075 | | /* Empty matches get the next char, so move by one. */ |
1076 | 230k | bufp += MAX(regmatch[0].rm_eo, 1); |
1077 | 230k | ntok++; |
1078 | 230k | if (*bufp == '\0') break; |
1079 | 230k | } |
1080 | 1.22k | } else { |
1081 | 52.5k | while(!(rc = tre_regexec(®, bufp, 1, regmatch, 0))) { |
1082 | | /* Empty matches get the next char, so move by one. */ |
1083 | | /* Not necessarily correct with MBCS, but only used |
1084 | | with single bytes */ |
1085 | 52.5k | bufp += MAX(regmatch[0].rm_eo, 1); |
1086 | 52.5k | ntok++; |
1087 | 52.5k | if (*bufp == '\0') break; |
1088 | 52.5k | } |
1089 | 280 | } |
1090 | | // AFAICS the only possible error report is REG_ESPACE |
1091 | 1.50k | if (rc == REG_ESPACE) |
1092 | 0 | warning("Out-of-memory error in regexp matching for element %d", |
1093 | 0 | (int) i + 1); |
1094 | 1.50k | } |
1095 | 1.54k | SET_VECTOR_ELT(ans, i, |
1096 | 1.54k | t = allocVector(STRSXP, ntok + (*bufp ? 1 : 0))); |
1097 | | /* and fill with the splits */ |
1098 | 1.54k | bufp = buf; |
1099 | 1.54k | pt = R_Realloc(pt, strlen(buf)+1, char); |
1100 | 285k | for (j = 0; j < ntok; j++) { |
1101 | 283k | int rc; |
1102 | 283k | if(useBytes) rc = tre_regexecb(®, bufp, 1, regmatch, 0); |
1103 | 52.5k | else rc = tre_regexec(®, bufp, 1, regmatch, 0); |
1104 | | |
1105 | | // AFAICS the only possible error report is REG_ESPACE |
1106 | 283k | if (rc == REG_ESPACE) |
1107 | 0 | warning("Out-of-memory error in regexp matching for element %d", |
1108 | 0 | (int) i + 1); |
1109 | 283k | if (regmatch[0].rm_eo > 0) { |
1110 | | /* Match was non-empty. */ |
1111 | 283k | if (regmatch[0].rm_so > 0) |
1112 | 278k | strncpy(pt, bufp, regmatch[0].rm_so); |
1113 | 283k | pt[regmatch[0].rm_so] = '\0'; |
1114 | 283k | bufp += regmatch[0].rm_eo; |
1115 | 283k | } else { |
1116 | | /* Match was empty. */ |
1117 | 0 | pt[0] = *bufp; |
1118 | 0 | pt[1] = '\0'; |
1119 | | /* Not necessarily correct with MBCS, but only used |
1120 | | with single bytes */ |
1121 | 0 | bufp++; |
1122 | 0 | } |
1123 | 283k | if (useBytes) |
1124 | 230k | SET_STRING_ELT(t, j, mkBytesNew(pt, haveBytesInput)); |
1125 | 52.5k | else |
1126 | 52.5k | SET_STRING_ELT(t, j, markKnown(pt, STRING_ELT(x, i))); |
1127 | 283k | } |
1128 | 1.54k | if (*bufp) { |
1129 | 704 | if (useBytes) |
1130 | 704 | SET_STRING_ELT(t, ntok, mkBytesNew(bufp, haveBytesInput)); |
1131 | 0 | else |
1132 | 0 | SET_STRING_ELT(t, ntok, markKnown(bufp, STRING_ELT(x, i))); |
1133 | 704 | } |
1134 | 1.54k | vmaxset(vmax2); |
1135 | 1.54k | } |
1136 | 1.54k | tre_regfree(®); |
1137 | 1.54k | } |
1138 | 294k | vmaxset(vmax); |
1139 | 294k | } |
1140 | | |
1141 | 294k | if (getAttrib(x, R_NamesSymbol) != R_NilValue) |
1142 | 192 | namesgets(ans, getAttrib(x, R_NamesSymbol)); |
1143 | 294k | UNPROTECT(1); |
1144 | 294k | R_Free(pt); R_Free(wpt); |
1145 | 294k | #ifdef HAVE_PCRE2 |
1146 | 294k | if (tables) free((void *)tables); |
1147 | | /* new PCRE2 will have pcre2_maketables_free() */ |
1148 | | #else |
1149 | | if (tables) pcre_free((void *)tables); |
1150 | | #endif |
1151 | 294k | UNPROTECT(1); /* tok */ |
1152 | 294k | return ans; |
1153 | 294k | } |
1154 | | |
1155 | | /* Used by grep[l] and [g]regexpr, with return value the match |
1156 | | position in characters */ |
1157 | | /* This could be faster for plen > 1 particularly in non-UTF8 mbcs, but |
1158 | | uses in R are for small strings and such mbcs should no longer be common */ |
1159 | | static int fgrep_one(const char *pat, const char *target, |
1160 | | bool useBytes, bool use_UTF8, int *next) |
1161 | 17.4k | { |
1162 | 17.4k | int plen = (int) strlen(pat), len = (int) strlen(target); |
1163 | 17.4k | int i = -1; |
1164 | 17.4k | const char *p; |
1165 | | |
1166 | 17.4k | if (plen == 0) { |
1167 | 0 | if (next != NULL) *next = 1; |
1168 | 0 | return 0; |
1169 | 0 | } |
1170 | 17.4k | if (plen == 1 && (useBytes || !(mbcslocale || use_UTF8))) { |
1171 | | /* a single byte is a common case */ |
1172 | 1.36M | for (i = 0, p = target; *p; p++, i++) |
1173 | 1.36M | if (*p == pat[0]) { |
1174 | 13.3k | if (next != NULL) *next = i + 1; |
1175 | 13.3k | return i; |
1176 | 13.3k | } |
1177 | 4.09k | return -1; |
1178 | 17.4k | } |
1179 | 0 | if (!useBytes && use_UTF8) { |
1180 | | // target is const char*, so C23 says so is the value |
1181 | 0 | const char *pos = strstr(target, pat); |
1182 | 0 | if (pos) { |
1183 | 0 | int ib = (int) (pos-target); |
1184 | 0 | int jb; |
1185 | |
|
1186 | 0 | if (next != NULL) *next = ib + plen; |
1187 | 0 | for (jb = 0, i = 0; jb < ib; jb++) |
1188 | | /* count leading UTF-8 bytes */ |
1189 | 0 | if ((target[jb] & 0xc0) != 0x80) i++; |
1190 | 0 | return i; |
1191 | 0 | } |
1192 | 0 | } else if (!useBytes && mbcslocale) { /* skip along by chars */ |
1193 | 0 | mbstate_t mb_st; |
1194 | 0 | int ib, used; |
1195 | 0 | mbs_init(&mb_st); |
1196 | 0 | for (ib = 0, i = 0; ib <= len-plen; i++) { |
1197 | 0 | if (strncmp(pat, target+ib, plen) == 0) { |
1198 | 0 | if (next != NULL) *next = ib + plen; |
1199 | 0 | return i; |
1200 | 0 | } |
1201 | 0 | used = (int) Mbrtowc(NULL, target+ib, R_MB_CUR_MAX, &mb_st); |
1202 | 0 | if (used <= 0) break; |
1203 | 0 | ib += used; |
1204 | 0 | } |
1205 | 0 | } else { |
1206 | | // target is const char*, so C23 says so is the value |
1207 | 0 | const char *pos = strstr(target, pat); |
1208 | 0 | if (pos) { |
1209 | 0 | i = (int) (pos-target); |
1210 | 0 | if (next != NULL) *next = i + plen; |
1211 | 0 | return i; |
1212 | 0 | } |
1213 | 0 | } |
1214 | 0 | return -1; |
1215 | 0 | } |
1216 | | |
1217 | | /* Returns the match position in bytes, for use in [g]sub. |
1218 | | len is the length (strlen) of target. |
1219 | | patlen is the length (strlen) of pat. (FIXME: should be size_t) |
1220 | | */ |
1221 | | |
1222 | | static int fgrep_one_bytes(const char *pat, size_t patlen, const char *target, |
1223 | | int len, bool useBytes, bool use_UTF8) |
1224 | 512 | { |
1225 | 512 | int i = -1; |
1226 | 512 | const char *p; |
1227 | | |
1228 | 512 | if (patlen == 0) return 0; |
1229 | | |
1230 | | /* UTF-8 allows for byte-based search of valid pattern string inside |
1231 | | valid target string, because lead and continuation bytes are taken |
1232 | | from distinct ranges. */ |
1233 | 512 | if (patlen == 1 && (useBytes || use_UTF8 || !mbcslocale)) { |
1234 | | /* a single byte is a common case */ |
1235 | 0 | for (i = 0, p = target; *p; p++, i++) |
1236 | 0 | if (*p == pat[0]) return i; |
1237 | 0 | return -1; |
1238 | 0 | } |
1239 | 512 | if (!use_UTF8 && !useBytes && mbcslocale) { /* skip along by chars */ |
1240 | 0 | mbstate_t mb_st; |
1241 | 0 | int ib, used; |
1242 | 0 | mbs_init(&mb_st); |
1243 | 0 | for (ib = 0, i = 0; ib <= len-patlen; i++) { |
1244 | 0 | if (strncmp(pat, target+ib, patlen) == 0) return ib; |
1245 | 0 | used = (int) Mbrtowc(NULL, target+ib, R_MB_CUR_MAX, &mb_st); |
1246 | 0 | if (used <= 0) break; |
1247 | 0 | ib += used; |
1248 | 0 | } |
1249 | 512 | } else { |
1250 | | // target is const char*, so C23 says so is the value |
1251 | 512 | const char *pos = strstr(target, pat); |
1252 | 512 | if (pos) return (int) (pos-target); |
1253 | 512 | } |
1254 | 320 | return -1; |
1255 | 512 | } |
1256 | | |
1257 | | attribute_hidden SEXP do_grep(SEXP call, SEXP op, SEXP args, SEXP env) |
1258 | 175k | { |
1259 | 175k | SEXP pat, text, ind, ans; |
1260 | 175k | regex_t reg; |
1261 | 175k | R_xlen_t i, j, n; |
1262 | 175k | int nmatches = 0, rc; |
1263 | 175k | bool igcase_opt, value_opt, perl_opt, fixed_opt, useBytes, invert; |
1264 | 175k | const char *spat = NULL; |
1265 | 175k | const wchar_t *wpat = NULL; |
1266 | 175k | const unsigned char *tables = NULL /* -Wall */; |
1267 | 175k | #ifdef HAVE_PCRE2 |
1268 | 175k | pcre2_code *re = NULL; |
1269 | 175k | pcre2_match_context *mcontext = NULL; |
1270 | 175k | uint32_t ovecsize = 1; |
1271 | 175k | pcre2_match_data *mdata = NULL; |
1272 | | #else |
1273 | | pcre *re_pcre = NULL /* -Wall */; |
1274 | | pcre_extra *re_pe = NULL; |
1275 | | int ovecsize = 3; |
1276 | | int ov[ovecsize]; |
1277 | | #endif |
1278 | 175k | bool use_UTF8 = false, use_WC = false; |
1279 | 175k | const void *vmax; |
1280 | 175k | int nwarn = 0; |
1281 | | |
1282 | 175k | checkArity(op, args); |
1283 | 175k | pat = CAR(args); args = CDR(args); |
1284 | 175k | text = CAR(args); args = CDR(args); |
1285 | 175k | igcase_opt = asBool2(CAR(args), call); args = CDR(args); |
1286 | 175k | value_opt = asBool2(CAR(args), call); args = CDR(args); |
1287 | 175k | perl_opt = asBool2(CAR(args), call); args = CDR(args); |
1288 | 175k | fixed_opt = asBool2(CAR(args), call); args = CDR(args); |
1289 | 175k | useBytes = asBool2(CAR(args), call); args = CDR(args); |
1290 | 175k | invert = asBool2(CAR(args), call); |
1291 | 175k | if (fixed_opt && igcase_opt) |
1292 | 0 | warning(_("argument '%s' will be ignored"), "ignore.case = TRUE"); |
1293 | 175k | if (fixed_opt && perl_opt) { |
1294 | 0 | warning(_("argument '%s' will be ignored"), "perl = TRUE"); |
1295 | 0 | perl_opt = 0; |
1296 | 0 | } |
1297 | | |
1298 | 175k | if (!isString(pat) || LENGTH(pat) < 1) |
1299 | 0 | error(_("invalid '%s' argument"), "pattern"); |
1300 | 175k | if (LENGTH(pat) > 1) |
1301 | 0 | warning(_("argument '%s' has length > 1 and only the first element will be used"), "pattern"); |
1302 | | |
1303 | 175k | if (!isString(text)) |
1304 | 0 | error(_("invalid '%s' argument"), "text"); |
1305 | | |
1306 | 175k | n = XLENGTH(text); |
1307 | 175k | if (STRING_ELT(pat, 0) == NA_STRING) { |
1308 | 0 | if (value_opt) { |
1309 | 0 | SEXP nmold = PROTECT(getAttrib(text, R_NamesSymbol)); |
1310 | 0 | PROTECT(ans = allocVector(STRSXP, n)); |
1311 | 0 | for (i = 0; i < n; i++) SET_STRING_ELT(ans, i, NA_STRING); |
1312 | 0 | if (!isNull(nmold)) |
1313 | 0 | setAttrib(ans, R_NamesSymbol, duplicate(nmold)); |
1314 | 0 | UNPROTECT(2); /* ans, nmold */ |
1315 | 0 | } else if (PRIMVAL(op)) { // grepl case |
1316 | 0 | ans = allocVector(LGLSXP, n); |
1317 | 0 | for (i = 0; i < n; i++) LOGICAL(ans)[i] = NA_LOGICAL; |
1318 | 0 | } else { |
1319 | 0 | ans = allocVector(INTSXP, n); |
1320 | 0 | for (i = 0; i < n; i++) INTEGER(ans)[i] = NA_INTEGER; |
1321 | 0 | } |
1322 | 0 | return ans; |
1323 | 0 | } |
1324 | | |
1325 | 175k | if (!useBytes) |
1326 | 173k | useBytes = only_ascii(pat, 1) && only_ascii(text, n); |
1327 | 175k | if (!useBytes) |
1328 | 9.49k | useBytes = have_bytes(pat, 1) || have_bytes(text, n); |
1329 | 175k | if (!useBytes) { |
1330 | | /* As from R 2.10.0 we use UTF-8 mode in PCRE in all MBCS locales */ |
1331 | | /* if we have non-ASCII text in a DBCS locale, we need to use wchar in TRE */ |
1332 | 9.49k | if (!fixed_opt && mbcslocale) use_UTF8 = true; |
1333 | 9.49k | if (!use_UTF8) |
1334 | 9.49k | use_UTF8 = have_utf8(pat, 1) || have_utf8(text, n); |
1335 | 9.49k | if (!use_UTF8 && !latin1locale) |
1336 | 1.89k | use_UTF8 = have_latin1(pat, 1) || have_latin1(text, n); |
1337 | 9.49k | } |
1338 | | |
1339 | 175k | if (!fixed_opt && !perl_opt) { |
1340 | 159k | use_WC = use_UTF8; use_UTF8 = false; |
1341 | 159k | } |
1342 | 175k | if (useBytes) |
1343 | 166k | spat = CHAR(STRING_ELT(pat, 0)); |
1344 | 9.49k | else if (use_WC) { |
1345 | 0 | wpat = wtransChar2(STRING_ELT(pat, 0)); |
1346 | 0 | if (!wpat) error(_("regular expression is invalid")); |
1347 | 9.49k | } else if (use_UTF8) { |
1348 | 7.59k | spat = trCharUTF82(STRING_ELT(pat, 0)); |
1349 | 7.59k | if (!spat || !utf8Valid(spat)) error(_("regular expression is invalid UTF-8")); |
1350 | 7.59k | } else { |
1351 | 1.89k | spat = translateCharFP2(STRING_ELT(pat, 0)); |
1352 | 1.89k | if (!spat || (mbcslocale && !mbcsValid(spat))) |
1353 | 0 | error(_("regular expression is invalid in this locale")); |
1354 | 1.89k | } |
1355 | | |
1356 | 175k | if (fixed_opt) ; |
1357 | 172k | else if (perl_opt) { |
1358 | 13.3k | #ifdef HAVE_PCRE2 |
1359 | 13.3k | R_pcre2_prepare(spat, text, use_UTF8, igcase_opt, &tables, &re, |
1360 | 13.3k | &mcontext); |
1361 | 13.3k | mdata = pcre2_match_data_create(ovecsize, NULL); |
1362 | | #else |
1363 | | R_pcre_prepare(spat, text, use_UTF8, igcase_opt, false, &tables, |
1364 | | &re_pcre, &re_pe); |
1365 | | #endif |
1366 | 159k | } else { |
1367 | 159k | int cflags = REG_NOSUB | REG_EXTENDED; |
1368 | 159k | if (igcase_opt) cflags |= REG_ICASE; |
1369 | 159k | if (!use_WC) |
1370 | 159k | rc = tre_regcompb(®, spat, cflags); |
1371 | 0 | else |
1372 | 0 | rc = tre_regwcomp(®, wpat, cflags); |
1373 | 159k | if (rc) reg_report(rc, ®, spat); |
1374 | 159k | } |
1375 | | |
1376 | 175k | PROTECT(ind = allocVector(LGLSXP, n)); |
1377 | 175k | vmax = vmaxget(); |
1378 | 5.66M | for (i = 0 ; i < n ; i++) { |
1379 | | // if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt(); |
1380 | 5.49M | LOGICAL(ind)[i] = 0; |
1381 | 5.49M | if (STRING_ELT(text, i) != NA_STRING) { |
1382 | 5.49M | const char *s = NULL; |
1383 | 5.49M | const wchar_t *ws = NULL; |
1384 | 5.49M | if (useBytes) |
1385 | 1.48M | s = CHAR(STRING_ELT(text, i)); |
1386 | 4.00M | else if (use_WC) { |
1387 | 0 | ws = wtransChar2(STRING_ELT(text, i)); |
1388 | 0 | if (!ws) { |
1389 | 0 | if(nwarn++ < NWARN) |
1390 | 0 | warning(_("input string %lld is invalid"), |
1391 | 0 | (long long)i+1); |
1392 | 0 | continue; |
1393 | 0 | } |
1394 | 4.00M | } else if (use_UTF8) { |
1395 | 4.00M | s = trCharUTF82(STRING_ELT(text, i)); |
1396 | 4.00M | if (!s || !utf8Valid(s)) { |
1397 | 0 | if(nwarn++ < NWARN) |
1398 | 0 | warning(_("input string %lld is invalid UTF-8"), |
1399 | 0 | (long long)i+1); |
1400 | 0 | continue; |
1401 | 0 | } |
1402 | 4.00M | } else { |
1403 | 1.89k | s = translateCharFP2(STRING_ELT(text, i)); |
1404 | 1.89k | if (!s || (mbcslocale && !mbcsValid(s))) { |
1405 | 0 | if(nwarn++ < NWARN) |
1406 | 0 | warning(_("input string %lld is invalid in this locale"), |
1407 | 0 | (long long)i+1); |
1408 | 0 | continue; |
1409 | 0 | } |
1410 | 1.89k | } |
1411 | | |
1412 | 5.49M | if (fixed_opt) |
1413 | 11.5k | LOGICAL(ind)[i] = fgrep_one(spat, s, useBytes, use_UTF8, NULL) >= 0; |
1414 | 5.48M | else if (perl_opt) { |
1415 | 4.79M | #ifdef HAVE_PCRE2 |
1416 | 4.79M | uint32_t eflag = 0; |
1417 | 4.79M | if (use_UTF8) eflag |= PCRE2_NO_UTF_CHECK; |
1418 | | |
1419 | 4.79M | int rc = pcre2_match(re, (PCRE2_SPTR) s, PCRE2_ZERO_TERMINATED, |
1420 | 4.79M | 0, eflag, mdata, mcontext); |
1421 | | #else |
1422 | | int rc = |
1423 | | pcre_exec(re_pcre, re_pe, s, (int) strlen(s), 0, 0, ov, 0); |
1424 | | #endif |
1425 | 4.79M | if(rc >= 0) LOGICAL(ind)[i] = 1; |
1426 | 3.57M | else { |
1427 | 3.57M | LOGICAL(ind)[i] = 0; |
1428 | 3.57M | R_pcre_exec_error(rc, i); |
1429 | 3.57M | } |
1430 | 4.79M | } else { |
1431 | 685k | if (!use_WC) |
1432 | 685k | rc = tre_regexecb(®, s, 0, NULL, 0); |
1433 | 0 | else |
1434 | 0 | rc = tre_regwexec(®, ws, 0, NULL, 0); |
1435 | 685k | if (rc == 0) LOGICAL(ind)[i] = 1; |
1436 | | // AFAICS the only possible error report is REG_ESPACE |
1437 | 685k | if (rc == REG_ESPACE) |
1438 | 0 | warning("Out-of-memory error in regexp matching for element %d", |
1439 | 0 | (int) i + 1); |
1440 | 685k | } |
1441 | 5.49M | } |
1442 | 5.49M | vmaxset(vmax); |
1443 | 5.49M | if (invert ^ LOGICAL(ind)[i]) nmatches++; |
1444 | 5.49M | } |
1445 | | |
1446 | 175k | if (fixed_opt); |
1447 | 172k | else if (perl_opt) { |
1448 | 13.3k | #ifdef HAVE_PCRE2 |
1449 | 13.3k | pcre2_match_data_free(mdata); |
1450 | 13.3k | pcre2_code_free(re); |
1451 | 13.3k | pcre2_match_context_free(mcontext); |
1452 | 13.3k | if (tables) |
1453 | | /* new PCRE2 will have pcre2_maketables_free() */ |
1454 | 5.79k | free((void *)tables); |
1455 | | #else |
1456 | | if (re_pe) pcre_free_study(re_pe); |
1457 | | pcre_free(re_pcre); |
1458 | | pcre_free((void *)tables); |
1459 | | #endif |
1460 | 13.3k | } else |
1461 | 159k | tre_regfree(®); |
1462 | | |
1463 | 175k | if (PRIMVAL(op)) {/* grepl case */ |
1464 | 13.9k | UNPROTECT(1); /* ind */ |
1465 | 13.9k | return ind; |
1466 | 13.9k | } |
1467 | | |
1468 | 161k | if (value_opt) { |
1469 | 128 | SEXP nmold = PROTECT(getAttrib(text, R_NamesSymbol)), nm; |
1470 | 128 | PROTECT(ans = allocVector(STRSXP, nmatches)); |
1471 | 72.6k | for (i = 0, j = 0; i < n ; i++) |
1472 | 72.4k | if (invert ^ LOGICAL(ind)[i]) |
1473 | 4.92k | SET_STRING_ELT(ans, j++, STRING_ELT(text, i)); |
1474 | | /* copy across names and subset */ |
1475 | 128 | if (!isNull(nmold)) { |
1476 | 0 | nm = allocVector(STRSXP, nmatches); |
1477 | 0 | for (i = 0, j = 0; i < n ; i++) |
1478 | 0 | if (invert ^ LOGICAL(ind)[i]) |
1479 | 0 | SET_STRING_ELT(nm, j++, STRING_ELT(nmold, i)); |
1480 | 0 | setAttrib(ans, R_NamesSymbol, nm); |
1481 | 0 | } |
1482 | 128 | UNPROTECT(2); /* ans, nmold */ |
1483 | 161k | } else { |
1484 | 161k | #ifdef LONG_VECTOR_SUPPORT |
1485 | 161k | if (n > INT_MAX) { |
1486 | 0 | ans = allocVector(REALSXP, nmatches); |
1487 | 0 | j = 0; |
1488 | 0 | for (i = 0 ; i < n ; i++) |
1489 | 0 | if (invert ^ LOGICAL(ind)[i]) REAL(ans)[j++] = (double)(i + 1); |
1490 | 0 | } else |
1491 | 161k | #endif |
1492 | 161k | { |
1493 | 161k | ans = allocVector(INTSXP, nmatches); |
1494 | 161k | j = 0; |
1495 | 2.43M | for (i = 0 ; i < n ; i++) |
1496 | 2.27M | if (invert ^ LOGICAL(ind)[i]) |
1497 | 157k | INTEGER(ans)[j++] = (int) (i + 1); |
1498 | 161k | } |
1499 | 161k | } |
1500 | 161k | UNPROTECT(1); /* ind */ |
1501 | 161k | return ans; |
1502 | 175k | } |
1503 | | |
1504 | | |
1505 | | /* fixed, single binary search, no error checking; -1 = no match, otherwise offset |
1506 | | NOTE: all offsets here (in & out) are 0-based !! */ |
1507 | 0 | static R_size_t fgrepraw1(SEXP pat, SEXP text, R_size_t offset) { |
1508 | 0 | Rbyte *haystack = RAW(text), *needle = RAW(pat); |
1509 | 0 | R_size_t n = LENGTH(text); |
1510 | 0 | R_size_t ncmp = LENGTH(pat); |
1511 | 0 | if (n < ncmp) |
1512 | 0 | return (R_size_t) -1; |
1513 | 0 | switch (ncmp) { /* it may be silly but we optimize small needle |
1514 | | searches, because they can be used to match |
1515 | | single UTF8 chars (up to 3 bytes) */ |
1516 | 0 | case 1: |
1517 | 0 | { |
1518 | 0 | Rbyte c = needle[0]; |
1519 | 0 | while (offset < n) { |
1520 | 0 | if (haystack[offset] == c) |
1521 | 0 | return offset; |
1522 | 0 | offset++; |
1523 | 0 | } |
1524 | 0 | return (R_size_t) -1; |
1525 | 0 | } |
1526 | 0 | case 2: |
1527 | 0 | { |
1528 | 0 | n--; |
1529 | 0 | while (offset < n) { |
1530 | 0 | if (haystack[offset ] == needle[0] && |
1531 | 0 | haystack[offset + 1] == needle[1]) |
1532 | 0 | return offset; |
1533 | 0 | offset++; |
1534 | 0 | } |
1535 | 0 | return (R_size_t) -1; |
1536 | 0 | } |
1537 | 0 | case 3: |
1538 | 0 | { |
1539 | 0 | n -= 2; |
1540 | 0 | while (offset < n) { |
1541 | 0 | if (haystack[offset ] == needle[0] && |
1542 | 0 | haystack[offset + 1] == needle[1] && |
1543 | 0 | haystack[offset + 2] == needle[2]) |
1544 | 0 | return offset; |
1545 | 0 | offset++; |
1546 | 0 | } |
1547 | 0 | return (R_size_t) -1; |
1548 | 0 | } |
1549 | 0 | default: |
1550 | 0 | { |
1551 | 0 | ncmp--; |
1552 | 0 | n -= ncmp; |
1553 | 0 | while (offset < n) { |
1554 | 0 | if (haystack[offset] == needle[0] && |
1555 | 0 | !memcmp(haystack + offset + 1, needle + 1, ncmp)) |
1556 | 0 | return offset; |
1557 | 0 | offset++; |
1558 | 0 | } |
1559 | 0 | } |
1560 | 0 | } |
1561 | 0 | return (R_size_t) -1; |
1562 | 0 | } |
1563 | | |
1564 | | /* grepRaw(pattern, text, offset, ignore.case, fixed, value, all, invert) */ |
1565 | | // FIXME: allow long vectors. |
1566 | | attribute_hidden SEXP do_grepraw(SEXP call, SEXP op, SEXP args, SEXP env) |
1567 | 0 | { |
1568 | 0 | SEXP pat, text, ans, res_head, res_tail; |
1569 | 0 | regex_t reg; |
1570 | 0 | int nmatches = 0, rc, cflags, eflags = 0; |
1571 | 0 | int *res_val; |
1572 | 0 | int res_alloc = 512; /* must be divisible by 2 since we may store |
1573 | | offset+length it is the initial size of |
1574 | | the integer vector of matches */ |
1575 | 0 | R_size_t res_ptr, offset, i; |
1576 | 0 | bool igcase_opt, fixed_opt, all, value, invert; |
1577 | |
|
1578 | 0 | checkArity(op, args); |
1579 | 0 | pat = CAR(args); args = CDR(args); |
1580 | 0 | text = CAR(args); args = CDR(args); |
1581 | 0 | offset = asInteger(CAR(args)); args = CDR(args); |
1582 | 0 | igcase_opt = asBool2(CAR(args), call); args = CDR(args); |
1583 | 0 | fixed_opt = asBool2(CAR(args), call); args = CDR(args); |
1584 | 0 | value = asBool2(CAR(args), call); args = CDR(args); |
1585 | 0 | all = asBool2(CAR(args), call); args = CDR(args); |
1586 | 0 | invert = asBool2(CAR(args), call); |
1587 | 0 | if (fixed_opt && igcase_opt) |
1588 | 0 | warning(_("argument '%s' will be ignored"), "ignore.case = TRUE"); |
1589 | | |
1590 | | /* invert=TRUE, value=FALSE will really give you a headache |
1591 | | thinking about it so we better not go there (the code below |
1592 | | will actually respect it for all cases except for fixed=FALSE, |
1593 | | all=TRUE so we could support it at some point but I fail to see |
1594 | | any real use of it) */ |
1595 | 0 | if (invert && !value) { |
1596 | 0 | warning(_("argument '%s' will be ignored"), "invert = TRUE"); |
1597 | 0 | invert = 0; |
1598 | 0 | } |
1599 | | |
1600 | | /* currently we support only offset >= 1 */ |
1601 | 0 | if (offset < 1) |
1602 | 0 | error(_("invalid '%s' argument"), "offset"); |
1603 | 0 | if (!isRaw(pat)) |
1604 | 0 | error(_("invalid '%s' argument"), "pattern"); |
1605 | 0 | if (!isRaw(text)) |
1606 | 0 | error(_("invalid '%s' argument"), "text"); |
1607 | 0 | if (offset > LENGTH(text)) |
1608 | 0 | return allocVector(INTSXP, 0); |
1609 | | |
1610 | 0 | offset--; /* reduce offset to base 0 */ |
1611 | | |
1612 | | /* TRE fails miserably for REG_LITERAL -- not only is it slow but |
1613 | | it doesn't handle embedded NULs properly (e.g., compile |
1614 | | goes into an infinite loop with "\00" pattern) -- so we have |
1615 | | to do it by hand */ |
1616 | 0 | if (fixed_opt) { |
1617 | 0 | if (LENGTH(pat) == 0) |
1618 | 0 | return allocVector(value ? (all ? VECSXP : RAWSXP) : INTSXP, 0); |
1619 | 0 | if (!all) { |
1620 | 0 | R_size_t res = fgrepraw1(pat, text, offset); |
1621 | 0 | if (invert) { |
1622 | 0 | Rbyte *ansp; |
1623 | 0 | if (res == -1) return value ? text : ScalarInteger(1); |
1624 | 0 | if (!value) return ScalarInteger(((res == 0) ? LENGTH(pat) : 0) + 1); |
1625 | 0 | ans = allocVector(RAWSXP, LENGTH(text) - LENGTH(pat)); |
1626 | 0 | ansp = RAW(ans); |
1627 | 0 | if (res) { |
1628 | 0 | memcpy(ansp, RAW(text), res); |
1629 | 0 | ansp += res; |
1630 | 0 | } |
1631 | 0 | res += LENGTH(pat); |
1632 | 0 | if (res < LENGTH(text)) |
1633 | 0 | memcpy(ansp, RAW(text) + res, LENGTH(text) - res); |
1634 | 0 | return ans; |
1635 | 0 | } |
1636 | 0 | if (res == -1) return allocVector(value ? RAWSXP : INTSXP, 0); |
1637 | 0 | if (!value) return ScalarInteger((int)(res + 1)); |
1638 | | /* value=TRUE doesn't really make sense for anything other than |
1639 | | match/nomatch detection since we just return the pattern */ |
1640 | 0 | return pat; |
1641 | 0 | } else { |
1642 | | /* There are two ways to do it: two pass or one pass. We |
1643 | | use the latter with TRE below, but for a sequential |
1644 | | search I assume it's fast enough so it's not worth the |
1645 | | hassle. We just special-case really tiny matches which |
1646 | | should be the most common case anyway. |
1647 | | */ |
1648 | 0 | #define MAX_MATCHES_MINIBUF 32 |
1649 | 0 | int matches[MAX_MATCHES_MINIBUF]; |
1650 | 0 | int n = LENGTH(text); |
1651 | 0 | while (offset < n) { |
1652 | 0 | offset = fgrepraw1(pat, text, offset); |
1653 | 0 | if (offset == -1) |
1654 | 0 | break; |
1655 | 0 | if (nmatches < MAX_MATCHES_MINIBUF) |
1656 | 0 | matches[nmatches] = (int)(offset + 1); |
1657 | 0 | nmatches++; |
1658 | 0 | offset += LENGTH(pat); |
1659 | 0 | } |
1660 | 0 | if (value) { |
1661 | 0 | if (invert) { /* invert is actually useful here as it |
1662 | | is performing something like strsplit */ |
1663 | 0 | R_size_t pos = 0; |
1664 | 0 | SEXP elt, mvec = NULL; |
1665 | 0 | int *fmatches = (int*) matches; /* either the minbuffer or an allocated maxibuffer */ |
1666 | 0 | int nprotect = 0; |
1667 | |
|
1668 | 0 | if (!nmatches) return text; |
1669 | | |
1670 | | /* if there are more matches than in the buffer, |
1671 | | we actually need to get them first */ |
1672 | 0 | if (nmatches > MAX_MATCHES_MINIBUF) { |
1673 | 0 | PROTECT(mvec = allocVector(INTSXP, nmatches)); |
1674 | 0 | nprotect++; |
1675 | 0 | fmatches = INTEGER(mvec); |
1676 | 0 | memcpy(fmatches, matches, sizeof(matches)); |
1677 | 0 | nmatches = MAX_MATCHES_MINIBUF; |
1678 | 0 | offset = matches[MAX_MATCHES_MINIBUF - 1] + LENGTH(pat) - 1; |
1679 | 0 | while (offset < n) { |
1680 | 0 | offset = fgrepraw1(pat, text, offset); |
1681 | 0 | if (offset == -1) |
1682 | 0 | break; |
1683 | 0 | INTEGER(mvec)[nmatches++] = (int)(offset + 1); |
1684 | 0 | offset += LENGTH(pat); |
1685 | 0 | } |
1686 | 0 | } |
1687 | | |
1688 | | /* there are always nmatches + 1 pieces (unlike strsplit) */ |
1689 | 0 | ans = PROTECT(allocVector(VECSXP, nmatches + 1)); |
1690 | 0 | nprotect++; |
1691 | | /* add all pieces before matches */ |
1692 | 0 | for (i = 0; i < nmatches; i++) { |
1693 | 0 | R_size_t elt_size = fmatches[i] - 1 - pos; |
1694 | 0 | elt = allocVector(RAWSXP, elt_size); |
1695 | 0 | SET_VECTOR_ELT(ans, i, elt); |
1696 | 0 | if (elt_size) |
1697 | 0 | memcpy(RAW(elt), RAW(text) + pos, elt_size); |
1698 | 0 | pos = fmatches[i] - 1 + LENGTH(pat); |
1699 | 0 | } |
1700 | | /* add the rest after last match */ |
1701 | 0 | elt = allocVector(RAWSXP, LENGTH(text) - (fmatches[nmatches - 1] - 1 + LENGTH(pat))); |
1702 | 0 | SET_VECTOR_ELT(ans, nmatches, elt); |
1703 | 0 | if (LENGTH(elt)) |
1704 | 0 | memcpy(RAW(elt), RAW(text) + LENGTH(text) - LENGTH(elt), LENGTH(elt)); |
1705 | 0 | UNPROTECT(nprotect); |
1706 | 0 | return ans; |
1707 | 0 | } |
1708 | | |
1709 | | /* value=TRUE is pathetic for fixed=TRUE without |
1710 | | invert as it is just rep(pat, nmatches) */ |
1711 | 0 | ans = PROTECT(allocVector(VECSXP, nmatches)); |
1712 | 0 | for (i = 0; i < nmatches; i++) |
1713 | 0 | SET_VECTOR_ELT(ans, i, pat); |
1714 | 0 | UNPROTECT(1); |
1715 | 0 | return ans; |
1716 | 0 | } |
1717 | 0 | ans = allocVector(INTSXP, nmatches); |
1718 | 0 | if (nmatches <= MAX_MATCHES_MINIBUF) { /* our min-buffer was enough, great */ |
1719 | 0 | if (nmatches) memcpy(INTEGER(ans), matches, nmatches * sizeof(int)); |
1720 | 0 | return ans; |
1721 | 0 | } |
1722 | | /* more matches than we could remember, time for pass 2 */ |
1723 | 0 | memcpy(INTEGER(ans), matches, sizeof(matches)); |
1724 | | /* but we are not completely stupid - we can continue |
1725 | | where amnesia hit us */ |
1726 | 0 | nmatches = MAX_MATCHES_MINIBUF; |
1727 | 0 | offset = matches[MAX_MATCHES_MINIBUF - 1] + LENGTH(pat) - 1; /* matches are 1-based, we are 0-based hence - 1 */ |
1728 | 0 | while (offset < n) { |
1729 | 0 | offset = fgrepraw1(pat, text, offset); |
1730 | 0 | if (offset == -1) |
1731 | 0 | break; |
1732 | 0 | INTEGER(ans)[nmatches++] = (int)(offset + 1); |
1733 | 0 | offset += LENGTH(pat); |
1734 | 0 | } |
1735 | 0 | return ans; |
1736 | 0 | } |
1737 | 0 | } |
1738 | | |
1739 | 0 | cflags = REG_EXTENDED; |
1740 | 0 | if (igcase_opt) cflags |= REG_ICASE; |
1741 | |
|
1742 | 0 | rc = tre_regncompb(®, (const char*) RAW(pat), LENGTH(pat), cflags); |
1743 | 0 | if (rc) reg_report(rc, ®, NULL /* pat is not necessarily a C string */ ); |
1744 | |
|
1745 | 0 | if (!all) { /* match only once */ |
1746 | 0 | regmatch_t ptag; |
1747 | 0 | rc = tre_regnexecb(®, (const char*) RAW(text) + offset, LENGTH(text) - offset, 1, &ptag, 0); |
1748 | 0 | tre_regfree(®); |
1749 | 0 | if (value) { |
1750 | 0 | if (rc != REG_OK || ptag.rm_eo == ptag.rm_so) /* TODO: is this good enough? it is the same as matching an empty string ... */ |
1751 | 0 | return invert ? text : allocVector(RAWSXP, 0); |
1752 | 0 | if (invert) { |
1753 | 0 | Rbyte *ansp; |
1754 | 0 | R_size_t len; |
1755 | 0 | ans = allocVector(RAWSXP, LENGTH(text) - (ptag.rm_eo - ptag.rm_so)); |
1756 | 0 | ansp = RAW(ans); |
1757 | 0 | if (ptag.rm_so) { |
1758 | 0 | memcpy(ansp, RAW(text), ptag.rm_so); |
1759 | 0 | ansp += ptag.rm_so; |
1760 | 0 | } |
1761 | 0 | len = LENGTH(text) - ptag.rm_eo; |
1762 | 0 | if (len) |
1763 | 0 | memcpy(ansp, RAW(text) + ptag.rm_eo, len); |
1764 | 0 | } else { |
1765 | 0 | ans = allocVector(RAWSXP, ptag.rm_eo - ptag.rm_so); |
1766 | 0 | memcpy(RAW(ans), RAW(text) + offset + ptag.rm_so, ptag.rm_eo - ptag.rm_so); |
1767 | 0 | } |
1768 | 0 | return ans; |
1769 | 0 | } |
1770 | 0 | return (rc == REG_OK) ? ScalarInteger((int)(ptag.rm_so + 1 + offset)) : allocVector(INTSXP, 0); |
1771 | 0 | } |
1772 | | |
1773 | | /* match all - we use a pairlist of integer arrays to expand the result |
1774 | | to allow use on big binary strings with many matches (it could be done |
1775 | | by re-allocating a temp buffer but I chose sequential allocations to |
1776 | | reduce possible fragmentation) */ |
1777 | 0 | res_head = res_tail = PROTECT(list1(allocVector(INTSXP, res_alloc))); |
1778 | 0 | res_val = INTEGER(CAR(res_tail)); |
1779 | 0 | res_ptr = 0; |
1780 | 0 | while (1) { |
1781 | 0 | regmatch_t ptag; |
1782 | 0 | rc = tre_regnexecb(®, (const char*) RAW(text) + offset, LENGTH(text) - offset, 1, &ptag, eflags); |
1783 | 0 | if (rc) |
1784 | 0 | break; |
1785 | 0 | if (!nmatches) eflags |= REG_NOTBOL; |
1786 | 0 | if (res_ptr >= res_alloc) { |
1787 | | /* double the buffer size, but limit to 32Mb */ |
1788 | 0 | if (res_alloc < 33554432) res_alloc <<= 1; |
1789 | 0 | SETCDR(res_tail, list1(allocVector(INTSXP, res_alloc))); |
1790 | 0 | res_tail = CDR(res_tail); |
1791 | 0 | res_val = INTEGER(CAR(res_tail)); |
1792 | 0 | res_ptr = 0; |
1793 | 0 | } |
1794 | 0 | res_val[res_ptr++] = (int)(ptag.rm_so + 1 + offset); |
1795 | 0 | if (value) res_val[res_ptr++] = ptag.rm_eo - ptag.rm_so; |
1796 | 0 | offset += ptag.rm_eo; |
1797 | 0 | nmatches++; |
1798 | 0 | if (ptag.rm_eo == 0) { /* empty string matched => trouble; FIXME: we may want to consider just advancing anyway */ |
1799 | 0 | int infinite_match = 1; |
1800 | | /* the only place where this is acceptable is "^" as that will go away in the next step */ |
1801 | 0 | if (nmatches == 1) { /* to see if that is true, re-run the match with REG_NOTBOL (added above) */ |
1802 | 0 | rc = tre_regnexecb(®, (const char*) RAW(text) + offset, LENGTH(text) - offset, 1, &ptag, eflags); |
1803 | 0 | if (rc != REG_OK || ptag.rm_eo != 0) |
1804 | 0 | infinite_match = 0; |
1805 | 0 | } |
1806 | 0 | if (infinite_match) |
1807 | 0 | warning(_("pattern matches an empty string infinitely, returning first match only")); |
1808 | 0 | break; |
1809 | 0 | } |
1810 | 0 | if (offset >= LENGTH(text)) break; |
1811 | 0 | } |
1812 | |
|
1813 | 0 | if (value) { /* for values we store in fact the absolute start offsets and length in the integer vector */ |
1814 | 0 | SEXP vec = CAR(res_head); |
1815 | 0 | R_size_t entry = 0, cptr = 0, clen = (CDR(res_head) == R_NilValue) ? res_ptr : LENGTH(vec); |
1816 | 0 | R_size_t inv_start = 0; /* 0-based start position of the pieces for invert */ |
1817 | 0 | res_val = INTEGER(vec); |
1818 | 0 | ans = PROTECT(allocVector(VECSXP, invert ? (nmatches + 1) : nmatches)); |
1819 | 0 | while (entry < nmatches) { |
1820 | 0 | if (invert) { /* for invert=TRUE store the current piece up to the match */ |
1821 | 0 | SEXP rvec = allocVector(RAWSXP, res_val[cptr] - 1 - inv_start); |
1822 | 0 | SET_VECTOR_ELT(ans, entry, rvec); |
1823 | 0 | entry++; |
1824 | 0 | if (LENGTH(rvec)) |
1825 | 0 | memcpy(RAW(rvec), RAW(text) + inv_start, LENGTH(rvec)); |
1826 | 0 | inv_start = res_val[cptr] - 1 + res_val[cptr + 1]; |
1827 | 0 | } else { /* for invert=FALSE store the matched piece */ |
1828 | 0 | SEXP rvec = allocVector(RAWSXP, res_val[cptr + 1]); |
1829 | 0 | SET_VECTOR_ELT(ans, entry, rvec); |
1830 | 0 | entry++; |
1831 | 0 | if (LENGTH(rvec)) |
1832 | 0 | memcpy(RAW(rvec), RAW(text) + res_val[cptr] - 1, LENGTH(rvec)); |
1833 | 0 | } |
1834 | | /* advance in the elements -- possibly jumping to the next list block */ |
1835 | 0 | cptr += 2; |
1836 | 0 | if (cptr >= clen) { |
1837 | 0 | res_head = CDR(res_head); |
1838 | 0 | if (res_head == R_NilValue) break; |
1839 | 0 | vec = CAR(res_head); |
1840 | 0 | res_val = INTEGER(vec); |
1841 | 0 | cptr = 0; |
1842 | 0 | clen = (CDR(res_head) == R_NilValue) ? res_ptr : LENGTH(vec); |
1843 | 0 | } |
1844 | 0 | } |
1845 | 0 | if (invert) { /* add the last piece after the last match */ |
1846 | 0 | SEXP lvec = allocVector(RAWSXP, LENGTH(text) - inv_start); |
1847 | 0 | SET_VECTOR_ELT(ans, nmatches, lvec); |
1848 | 0 | if (LENGTH(lvec)) |
1849 | 0 | memcpy(RAW(lvec), RAW(text) + inv_start, LENGTH(lvec)); |
1850 | 0 | } |
1851 | 0 | UNPROTECT(1); |
1852 | 0 | } else { /* if values are not needed, we just collect all the start offsets */ |
1853 | 0 | ans = allocVector(INTSXP, nmatches); |
1854 | 0 | res_val = INTEGER(ans); |
1855 | 0 | while (res_head != R_NilValue) { |
1856 | 0 | SEXP vec = CAR(res_head); |
1857 | 0 | R_size_t len = (CDR(res_head) == R_NilValue) ? res_ptr : LENGTH(vec); |
1858 | 0 | if (len) memcpy(res_val, INTEGER(vec), len * sizeof(int)); |
1859 | 0 | res_val += len; |
1860 | 0 | res_head = CDR(res_head); |
1861 | 0 | } |
1862 | 0 | } |
1863 | 0 | UNPROTECT(1); |
1864 | |
|
1865 | 0 | tre_regfree(®); |
1866 | |
|
1867 | 0 | return ans; |
1868 | 0 | } |
1869 | | |
1870 | | /* The following R functions do substitution for regular expressions, |
1871 | | * either once or globally. |
1872 | | * The functions are loosely patterned on the "sub" and "gsub" in "nawk". */ |
1873 | | |
1874 | | static char *string_adj(char *target, const char *orig, const char *repl, |
1875 | | regmatch_t *regmatch) |
1876 | 526k | { |
1877 | 526k | int i, k; |
1878 | 526k | const char *p = repl; char *t = target; |
1879 | | |
1880 | 1.38M | while (*p) { |
1881 | 857k | if (*p == '\\') { |
1882 | 427k | if ('1' <= p[1] && p[1] <= '9') { |
1883 | 427k | k = p[1] - '0'; |
1884 | 1.57M | for (i = regmatch[k].rm_so ; i < regmatch[k].rm_eo ; i++) |
1885 | 1.14M | *t++ = orig[i]; |
1886 | 427k | p += 2; |
1887 | 427k | } |
1888 | 0 | else if (p[1] == 0) p++; else {p++; *t++ = *p++;} |
1889 | 427k | } |
1890 | 429k | else *t++ = *p++; |
1891 | 857k | } |
1892 | 526k | return t; |
1893 | 526k | } |
1894 | | |
1895 | | /* used for single-byte locales, and UTF-8 for perl = TRUE */ |
1896 | | static int count_subs(const char *repl) |
1897 | 5.00M | { |
1898 | 5.00M | int i = 0; |
1899 | 5.00M | const char *p = repl; |
1900 | 5.26M | while (*p) { |
1901 | 256k | if (*p == '\\') { |
1902 | 123k | if ('1' <= p[1] && p[1] <= '9') {i++; p += 2;} |
1903 | 448 | else if (p[1] == 0) p++; else p += 2; |
1904 | 123k | } |
1905 | 132k | else p++; |
1906 | 256k | } |
1907 | 5.00M | return i; |
1908 | 5.00M | } |
1909 | | |
1910 | | /* FIXME: use UCP for upper/lower conversion |
1911 | | could use pcre2_substitute which will take care of that and also |
1912 | | supports \u, \l |
1913 | | */ |
1914 | | #ifdef HAVE_PCRE2 |
1915 | | static |
1916 | | char *R_pcre_string_adj(char *target, const char *orig, const char *repl, |
1917 | | PCRE2_SIZE *ovec, bool use_UTF8, int ncap) |
1918 | | #else |
1919 | | static |
1920 | | char *R_pcre_string_adj(char *target, const char *orig, const char *repl, |
1921 | | int *ovec, bool use_UTF8, int ncap) |
1922 | | #endif |
1923 | 2.88M | { |
1924 | 2.88M | uint64_t i, nb; |
1925 | 2.88M | int k; |
1926 | 2.88M | const char *p = repl; |
1927 | 2.88M | char *t = target, c; |
1928 | 2.88M | bool upper = false, lower = false; |
1929 | | |
1930 | 2.88M | while (*p) { |
1931 | 0 | if (*p == '\\') { |
1932 | 0 | if ('1' <= p[1] && p[1] <= '9') { |
1933 | 0 | k = p[1] - '0'; |
1934 | 0 | if (k >= ncap) { |
1935 | | /* back-reference to a group that has not been captured, |
1936 | | treat it as an empty string; the special case is needed |
1937 | | for PCRE2, but not for PCRE where the length of the |
1938 | | matched group will appear to be zero because ovector |
1939 | | is zeroed */ |
1940 | 0 | p += 2; |
1941 | 0 | continue; |
1942 | 0 | } |
1943 | | /* Here we need to work in chars */ |
1944 | 0 | nb = ovec[2*k+1] - ovec[2*k]; |
1945 | | /* unused patterns will have nb == 0, both offsets -1 with PCRE |
1946 | | and PCRE2_UNSET with PCRE2 */ |
1947 | 0 | if (nb > 0 && use_UTF8 && (upper || lower)) { |
1948 | 0 | wctrans_t tr = wctrans(upper ? "toupper" : "tolower"); |
1949 | 0 | uint64_t j; |
1950 | 0 | int nc; |
1951 | 0 | char *xi, *p; |
1952 | 0 | wchar_t *wc; |
1953 | 0 | R_CheckStack2((nb+1)*sizeof(char)); |
1954 | 0 | p = xi = (char *) alloca((nb+1)*sizeof(char)); |
1955 | 0 | for (j = 0; j < nb; j++) *p++ = orig[ovec[2*k]+j]; |
1956 | 0 | *p = '\0'; |
1957 | 0 | nc = (int) utf8towcs(NULL, xi, 0); |
1958 | 0 | if (nc >= 0) { |
1959 | 0 | R_CheckStack2((nc+1)*sizeof(wchar_t)); |
1960 | 0 | wc = (wchar_t *) alloca((nc+1)*sizeof(wchar_t)); |
1961 | 0 | utf8towcs(wc, xi, nc + 1); |
1962 | 0 | for (j = 0; j < nc; j++) wc[j] = towctrans(wc[j], tr); |
1963 | 0 | nb = (int) wcstoutf8(NULL, wc, INT_MAX); |
1964 | 0 | wcstoutf8(xi, wc, nb); |
1965 | 0 | for (j = 0; j < nb - 1; j++) *t++ = *xi++; |
1966 | 0 | } |
1967 | 0 | } else |
1968 | 0 | for (i = ovec[2*k] ; i < ovec[2*k+1] ; i++) { |
1969 | 0 | c = orig[i]; |
1970 | 0 | *t++ = (char) (upper ? toupper(c) : (lower ? tolower(c) : c)); |
1971 | 0 | } |
1972 | 0 | p += 2; |
1973 | 0 | } else if (p[1] == 'U') { |
1974 | 0 | p += 2; |
1975 | 0 | upper = true; lower = false; |
1976 | 0 | } else if (p[1] == 'L') { |
1977 | 0 | p += 2; |
1978 | 0 | upper = false; lower = true; |
1979 | 0 | } else if (p[1] == 'E') { /* end case modification */ |
1980 | 0 | p += 2; |
1981 | 0 | upper = false; lower = false; |
1982 | 0 | } else if (p[1] == 0) { |
1983 | 0 | p += 1; |
1984 | 0 | } else { |
1985 | 0 | p += 1; |
1986 | 0 | *t++ = *p++; |
1987 | 0 | } |
1988 | 0 | } else *t++ = *p++; |
1989 | 0 | } |
1990 | 2.88M | return t; |
1991 | 2.88M | } |
1992 | | |
1993 | | static wchar_t *wstring_adj(wchar_t *target, const wchar_t *orig, |
1994 | | const wchar_t *repl, regmatch_t *regmatch) |
1995 | 857k | { |
1996 | 857k | int i, k; |
1997 | 857k | const wchar_t *p = repl; |
1998 | 857k | wchar_t *t = target; |
1999 | | |
2000 | 857k | while (*p) { |
2001 | 0 | if (*p == L'\\') { |
2002 | 0 | if (L'1' <= p[1] && p[1] <= L'9') { |
2003 | 0 | k = p[1] - L'0'; |
2004 | 0 | for (i = regmatch[k].rm_so ; i < regmatch[k].rm_eo ; i++) |
2005 | 0 | *t++ = orig[i]; |
2006 | 0 | p += 2; |
2007 | 0 | } |
2008 | 0 | else if (p[1] == 0) p++; else {p++; *t++ = *p++;} |
2009 | 0 | } |
2010 | 0 | else *t++ = *p++; |
2011 | 0 | } |
2012 | 857k | return t; |
2013 | 857k | } |
2014 | | |
2015 | | static int wcount_subs(const wchar_t *repl) |
2016 | 857k | { |
2017 | 857k | int i = 0; |
2018 | 857k | const wchar_t *p = repl; |
2019 | 857k | while (*p) { |
2020 | 0 | if (*p == '\\') { |
2021 | 0 | if ('1' <= p[1] && p[1] <= '9') {i++; p += 2;} |
2022 | 0 | else if (p[1] == 0) p++; else p += 2; |
2023 | 0 | } |
2024 | 0 | else p++; |
2025 | 0 | } |
2026 | 857k | return i; |
2027 | 857k | } |
2028 | | |
2029 | | static int sub_buffer_check_overflow(double d) |
2030 | 16.1M | { |
2031 | | /* 2147483647 is a length limit for R strings and 32-bit ints can be |
2032 | | precisely represented in IEEE double (but not 64-bit ints) */ |
2033 | 16.1M | if (!(d < INT_MAX) || !(d < 2147483647)) |
2034 | 0 | error(_("result string is too long")); |
2035 | 16.1M | return (int)d; |
2036 | 16.1M | } |
2037 | | |
2038 | | static void |
2039 | | sub_buffer_size_init(size_t replen, int ns, int nsubs, int global, |
2040 | | int *nns, int *maxrep) |
2041 | 5.86M | { |
2042 | | /* worst possible scenario is to put a copy of the |
2043 | | replacement after every character, unless there are |
2044 | | backrefs */ |
2045 | 5.86M | *maxrep = sub_buffer_check_overflow((double)replen + (ns-2.) * nsubs); |
2046 | 5.86M | if (global) { |
2047 | 121k | double dnns = (double)ns * (*maxrep + 1.) + 1000.; |
2048 | 121k | if (dnns > 10000) dnns = 2.*ns + (double)replen + 1000.; |
2049 | 121k | *nns = sub_buffer_check_overflow(dnns); |
2050 | 121k | } else |
2051 | 5.74M | *nns = sub_buffer_check_overflow((double)ns + |
2052 | 5.74M | (double)*maxrep + 1000.); |
2053 | 5.86M | } |
2054 | | |
2055 | | static int |
2056 | | sub_buffer_size_expand(double needed, int *nns) |
2057 | 4.39M | { |
2058 | 4.39M | int ineeded = sub_buffer_check_overflow(needed); |
2059 | 4.39M | if (*nns < ineeded) { |
2060 | | /* This could fail at smaller value on a 32-bit platform: |
2061 | | it is merely an integer overflow check */ |
2062 | 84 | if (*nns < INT_MAX/2) |
2063 | 84 | (*nns) *= 2; |
2064 | 84 | if (*nns < ineeded) |
2065 | 0 | (*nns) = ineeded; |
2066 | 84 | return 1; |
2067 | 84 | } else |
2068 | 4.39M | return 0; |
2069 | 4.39M | } |
2070 | | |
2071 | | static void |
2072 | | sub_buffer_expand(double needed, int *nns, char **cbuf, char **u) |
2073 | 3.53M | { |
2074 | 3.53M | if (sub_buffer_size_expand(needed, nns)) { |
2075 | 84 | char *tmp; |
2076 | 84 | tmp = R_Realloc(*cbuf, *nns, char); |
2077 | 84 | *u = tmp + (*u - *cbuf); |
2078 | 84 | *cbuf = tmp; |
2079 | 84 | } |
2080 | 3.53M | } |
2081 | | |
2082 | | static void |
2083 | | wsub_buffer_expand(double needed, int *nns, wchar_t **cbuf, wchar_t **u) |
2084 | 857k | { |
2085 | 857k | if (sub_buffer_size_expand(needed, nns)) { |
2086 | 0 | wchar_t *tmp; |
2087 | 0 | tmp = R_Realloc(*cbuf, *nns, wchar_t); |
2088 | 0 | *u = tmp + (*u - *cbuf); |
2089 | 0 | *cbuf = tmp; |
2090 | 0 | } |
2091 | 857k | } |
2092 | | |
2093 | | /* The following R functions do substitution for regular expressions, |
2094 | | * either once or globally. |
2095 | | * The functions are loosely patterned on the "sub" and "gsub" in "nawk". */ |
2096 | | |
2097 | | /* Release whatever do_gsub() compiled. Also called before an error is |
2098 | | signalled part-way through the text vector, since the unwind would |
2099 | | otherwise leak the compiled pattern. */ |
2100 | | static void gsub_free_pattern(bool fixed_opt, bool perl_opt, regex_t *reg, |
2101 | | const unsigned char *tables, |
2102 | | #ifdef HAVE_PCRE2 |
2103 | | pcre2_code *re, pcre2_match_data *mdata, |
2104 | | pcre2_match_context *mcontext) |
2105 | | #else |
2106 | | pcre *re_pcre, pcre_extra *re_pe) |
2107 | | #endif |
2108 | 70.6k | { |
2109 | 70.6k | if (fixed_opt) ; |
2110 | 70.5k | else if (perl_opt) { |
2111 | 15.3k | #ifdef HAVE_PCRE2 |
2112 | 15.3k | pcre2_match_data_free(mdata); |
2113 | 15.3k | pcre2_code_free(re); |
2114 | 15.3k | pcre2_match_context_free(mcontext); |
2115 | 15.3k | if (tables) |
2116 | | /* new PCRE2 will have pcre2_maketables_free() */ |
2117 | 8.55k | free((void *)tables); |
2118 | | #else |
2119 | | if (re_pe) pcre_free_study(re_pe); |
2120 | | pcre_free(re_pcre); |
2121 | | pcre_free((void *)tables); |
2122 | | #endif |
2123 | 55.1k | } else tre_regfree(reg); |
2124 | 70.6k | } |
2125 | | |
2126 | | #ifdef HAVE_PCRE2 |
2127 | | # define GSUB_FREE_PATTERN() \ |
2128 | 70.6k | gsub_free_pattern(fixed_opt, perl_opt, ®, tables, re, mdata, mcontext) |
2129 | | #else |
2130 | | # define GSUB_FREE_PATTERN() \ |
2131 | | gsub_free_pattern(fixed_opt, perl_opt, ®, tables, re_pcre, re_pe) |
2132 | | #endif |
2133 | | |
2134 | | attribute_hidden SEXP do_gsub(SEXP call, SEXP op, SEXP args, SEXP env) |
2135 | 70.6k | { |
2136 | 70.6k | SEXP pat, rep, text, ans; |
2137 | 70.6k | regex_t reg; |
2138 | 70.6k | regmatch_t regmatch[10]; |
2139 | 70.6k | R_xlen_t i, n; |
2140 | 70.6k | int j, ns, nns, nmatch, offset, rc; |
2141 | 70.6k | bool global, igcase_opt, perl_opt, fixed_opt, useBytes; |
2142 | 70.6k | int eflags, last_end; |
2143 | 70.6k | char *u, *cbuf; |
2144 | 70.6k | const char *spat = NULL, *srep = NULL, *s = NULL; |
2145 | 70.6k | size_t patlen = 0, replen = 0; |
2146 | 70.6k | bool use_UTF8 = false, use_WC = false; |
2147 | 70.6k | bool ascii_patrep = false; |
2148 | 70.6k | const wchar_t *wpat = NULL, *wrep = NULL, *ws = NULL; |
2149 | 70.6k | const unsigned char *tables = NULL; |
2150 | 70.6k | #ifdef HAVE_PCRE2 |
2151 | 70.6k | uint32_t ovecsize = 10; |
2152 | 70.6k | pcre2_code *re = NULL; |
2153 | 70.6k | pcre2_match_context *mcontext = NULL; |
2154 | 70.6k | pcre2_match_data *mdata = NULL; |
2155 | | #else |
2156 | | int ovecsize = 30; |
2157 | | pcre *re_pcre = NULL; |
2158 | | pcre_extra *re_pe = NULL; |
2159 | | #endif |
2160 | 70.6k | const void *vmax = vmaxget(); |
2161 | 70.6k | bool haveBytesInput; |
2162 | | |
2163 | 70.6k | checkArity(op, args); |
2164 | | |
2165 | 70.6k | global = (bool) PRIMVAL(op); |
2166 | | |
2167 | 70.6k | pat = CAR(args); args = CDR(args); |
2168 | 70.6k | rep = CAR(args); args = CDR(args); |
2169 | 70.6k | text = CAR(args); args = CDR(args); |
2170 | 70.6k | igcase_opt = asBool2(CAR(args), call); args = CDR(args); |
2171 | 70.6k | perl_opt = asBool2(CAR(args), call); args = CDR(args); |
2172 | 70.6k | fixed_opt = asBool2(CAR(args), call); args = CDR(args); |
2173 | 70.6k | useBytes = asBool2(CAR(args), call); args = CDR(args); |
2174 | 70.6k | if (fixed_opt && igcase_opt) |
2175 | 0 | warning(_("argument '%s' will be ignored"), "ignore.case = TRUE"); |
2176 | 70.6k | if (fixed_opt && perl_opt) { |
2177 | 0 | warning(_("argument '%s' will be ignored"), "perl = TRUE"); |
2178 | 0 | perl_opt = 0; |
2179 | 0 | } |
2180 | | |
2181 | 70.6k | if (!isString(pat) || LENGTH(pat) < 1) |
2182 | 0 | error(_("invalid '%s' argument"), "pattern"); |
2183 | 70.6k | if (LENGTH(pat) > 1) |
2184 | 0 | warning(_("argument '%s' has length > 1 and only the first element will be used"), "pattern"); |
2185 | 70.6k | if (!isString(rep) || LENGTH(rep) < 1) |
2186 | 0 | error(_("invalid '%s' argument"), "replacement"); |
2187 | 70.6k | if (LENGTH(rep) > 1) |
2188 | 0 | warning(_("argument '%s' has length > 1 and only the first element will be used"), "replacement"); |
2189 | | |
2190 | 70.6k | if (!isString(text)) |
2191 | 0 | error(_("invalid '%s' argument"), "text"); |
2192 | | |
2193 | 70.6k | n = XLENGTH(text); |
2194 | | /* This contradicts the code below that has NA matching NA */ |
2195 | 70.6k | if (STRING_ELT(pat, 0) == NA_STRING) { |
2196 | 0 | PROTECT(ans = allocVector(STRSXP, n)); |
2197 | 0 | for (i = 0; i < n; i++) SET_STRING_ELT(ans, i, NA_STRING); |
2198 | |
|
2199 | 0 | goto exit_gsub; |
2200 | 0 | } |
2201 | 70.6k | haveBytesInput = have_bytes(pat, 1) || have_bytes(rep, 1) || |
2202 | 70.6k | have_bytes(text, n); |
2203 | | |
2204 | 70.6k | if (!useBytes) |
2205 | 70.6k | useBytes = only_ascii(pat, 1) && only_ascii(rep, 1) && |
2206 | 70.6k | only_ascii(text, n); |
2207 | 70.6k | if (!useBytes) |
2208 | 10.5k | useBytes = haveBytesInput; |
2209 | 70.6k | if (!useBytes) { |
2210 | | /* if we have non-ASCII text in a DBCS locale, we need to use wchar in TRE */ |
2211 | 10.5k | if (!fixed_opt && mbcslocale) use_UTF8 = true; |
2212 | 10.5k | if (!use_UTF8) |
2213 | 10.5k | use_UTF8 = have_utf8(pat, 1) || have_utf8(rep, 1) || |
2214 | 10.5k | have_utf8(text, n); |
2215 | 10.5k | if (!use_UTF8 && !latin1locale) |
2216 | 1.90k | use_UTF8 = have_latin1(pat, 1) || have_latin1(rep, 1) || |
2217 | 1.90k | have_latin1(text, n); |
2218 | 10.5k | } |
2219 | | |
2220 | 70.6k | if (!fixed_opt && !perl_opt) { |
2221 | 55.1k | use_WC = use_UTF8; use_UTF8 = false; |
2222 | 55.1k | } |
2223 | | |
2224 | 70.6k | if (useBytes) { |
2225 | 60.1k | spat = CHAR(STRING_ELT(pat, 0)); |
2226 | 60.1k | srep = CHAR(STRING_ELT(rep, 0)); |
2227 | 60.1k | } else if (use_WC) { |
2228 | 1.83k | wpat = wtransChar2(STRING_ELT(pat, 0)); |
2229 | 1.83k | if (!wpat) error(_("'pattern' is invalid")); |
2230 | 1.83k | wrep = wtransChar2(STRING_ELT(rep, 0)); |
2231 | 1.83k | if (!wrep) error(_("'replacement' is invalid")); |
2232 | 1.83k | ascii_patrep = (IS_ASCII(STRING_ELT(pat, 0)) && |
2233 | 1.83k | IS_ASCII(STRING_ELT(rep, 0))); |
2234 | 8.70k | } else if (use_UTF8) { |
2235 | 6.80k | spat = trCharUTF82(STRING_ELT(pat, 0)); |
2236 | 6.80k | if (!spat || !utf8Valid(spat)) error(_("'pattern' is invalid UTF-8")); |
2237 | 6.80k | srep = trCharUTF82(STRING_ELT(rep, 0)); |
2238 | 6.80k | if (!srep || !utf8Valid(srep)) error(_("'replacement' is invalid UTF-8")); |
2239 | 6.80k | } else { |
2240 | 1.90k | spat = translateCharFP2(STRING_ELT(pat, 0)); |
2241 | 1.90k | if (!spat || (mbcslocale && !mbcsValid(spat))) |
2242 | 0 | error(_("'pattern' is invalid in this locale")); |
2243 | 1.90k | srep = translateCharFP2(STRING_ELT(rep, 0)); |
2244 | 1.90k | if (!srep || (mbcslocale && !mbcsValid(srep))) |
2245 | 0 | error(_("'replacement' is invalid in this locale")); |
2246 | 1.90k | } |
2247 | | |
2248 | 70.6k | if (fixed_opt) { |
2249 | 128 | patlen = strlen(spat); |
2250 | 128 | if (!patlen) error(_("zero-length pattern")); |
2251 | 128 | replen = strlen(srep); |
2252 | 70.5k | } else if (perl_opt) { |
2253 | 15.3k | #ifdef HAVE_PCRE2 |
2254 | 15.3k | R_pcre2_prepare(spat, text, use_UTF8, igcase_opt, &tables, &re, |
2255 | 15.3k | &mcontext); |
2256 | 15.3k | mdata = pcre2_match_data_create(ovecsize, NULL); |
2257 | | #else |
2258 | | R_pcre_prepare(spat, text, use_UTF8, igcase_opt, false, &tables, |
2259 | | &re_pcre, &re_pe); |
2260 | | #endif |
2261 | 15.3k | replen = strlen(srep); |
2262 | 55.1k | } else { |
2263 | 55.1k | int cflags = REG_EXTENDED; |
2264 | 55.1k | if (igcase_opt) cflags |= REG_ICASE; |
2265 | 55.1k | if (!use_WC) { |
2266 | 53.3k | rc = tre_regcompb(®, spat, cflags); |
2267 | 53.3k | if (rc) reg_report(rc, ®, spat); |
2268 | 53.3k | replen = strlen(srep); |
2269 | 53.3k | } else { |
2270 | 1.83k | rc = tre_regwcomp(®, wpat, cflags); |
2271 | 1.83k | if (rc) reg_report(rc, ®, translateChar(STRING_ELT(pat, 0))); |
2272 | 1.83k | replen = wcslen(wrep); |
2273 | 1.83k | } |
2274 | 55.1k | } |
2275 | | |
2276 | 70.6k | PROTECT(ans = allocVector(STRSXP, n)); |
2277 | 70.6k | vmax = vmaxget(); |
2278 | 5.93M | for (i = 0 ; i < n ; i++) { |
2279 | | // if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt(); |
2280 | | /* NA pattern was handled above */ |
2281 | 5.86M | if (STRING_ELT(text, i) == NA_STRING) { |
2282 | 0 | SET_STRING_ELT(ans, i, NA_STRING); |
2283 | 0 | continue; |
2284 | 0 | } |
2285 | | |
2286 | 5.86M | if (useBytes) |
2287 | 1.02M | s = CHAR(STRING_ELT(text, i)); |
2288 | 4.84M | else if (use_WC) { |
2289 | 857k | ws = wtransChar2(STRING_ELT(text, i)); |
2290 | 857k | if (!ws) { |
2291 | 0 | GSUB_FREE_PATTERN(); |
2292 | 0 | error(_("input string %lld is invalid"), (long long)i+1); |
2293 | 0 | } |
2294 | 3.98M | } else if (use_UTF8) { |
2295 | 3.98M | s = trCharUTF82(STRING_ELT(text, i)); |
2296 | 3.98M | if (!s || !utf8Valid(s)) { |
2297 | 0 | GSUB_FREE_PATTERN(); |
2298 | 0 | error(_("input string %lld is invalid UTF-8"), |
2299 | 0 | (long long)i+1); |
2300 | 0 | } |
2301 | 3.98M | } else { |
2302 | 1.90k | s = translateCharFP2(STRING_ELT(text, i)); |
2303 | 1.90k | if (!s || (mbcslocale && !mbcsValid(s))) { |
2304 | 0 | GSUB_FREE_PATTERN(); |
2305 | 0 | error(_("input string %lld is invalid in this locale"), |
2306 | 0 | (long long)i+1); |
2307 | 0 | } |
2308 | 1.90k | } |
2309 | | |
2310 | 5.86M | if (fixed_opt) { |
2311 | 512 | int st, nr, slen = (int) strlen(s); |
2312 | 512 | ns = slen; |
2313 | 512 | st = fgrep_one_bytes(spat, patlen, s, ns, useBytes, use_UTF8); |
2314 | 512 | if (st < 0) |
2315 | 320 | SET_STRING_ELT(ans, i, markBytesOld(STRING_ELT(text, i), |
2316 | 320 | useBytes, haveBytesInput)); |
2317 | 192 | else if (STRING_ELT(rep, 0) == NA_STRING) |
2318 | 0 | SET_STRING_ELT(ans, i, NA_STRING); |
2319 | 192 | else { |
2320 | 192 | if (global) { /* need to find max number of matches */ |
2321 | 0 | const char *ss= s; |
2322 | 0 | int sst = st; |
2323 | 0 | nr = 0; |
2324 | 0 | do { |
2325 | 0 | nr++; |
2326 | 0 | ss += sst+patlen; |
2327 | 0 | slen -= (int)(sst+patlen); |
2328 | 0 | } while((sst = fgrep_one_bytes(spat, patlen, ss, slen, |
2329 | 0 | useBytes, use_UTF8)) >= 0); |
2330 | 192 | } else nr = 1; |
2331 | 192 | cbuf = u = R_Calloc(ns + nr*(replen - patlen) + 1, char); |
2332 | 192 | *u = '\0'; |
2333 | 192 | slen = ns; |
2334 | 192 | do { |
2335 | 192 | strncpy(u, s, st); |
2336 | 192 | u += st; |
2337 | 192 | s += st+patlen; |
2338 | 192 | slen -= (int)(st+patlen); |
2339 | 192 | strncpy(u, srep, replen); |
2340 | 192 | u += replen; |
2341 | 192 | } while(global && (st = fgrep_one_bytes(spat, patlen, s, slen, |
2342 | 0 | useBytes, use_UTF8)) >= 0); |
2343 | 192 | strcpy(u, s); |
2344 | 192 | if (useBytes) |
2345 | 192 | SET_STRING_ELT(ans, i, mkBytesNew(cbuf, haveBytesInput)); |
2346 | 0 | else if (use_UTF8) |
2347 | 0 | SET_STRING_ELT(ans, i, mkCharCE(cbuf, CE_UTF8)); |
2348 | 0 | else |
2349 | 0 | SET_STRING_ELT(ans, i, markKnown(cbuf, STRING_ELT(text, i))); |
2350 | 192 | R_Free(cbuf); |
2351 | 192 | } |
2352 | 5.86M | } else if (perl_opt) { |
2353 | 4.78M | int ncap, maxrep; |
2354 | 4.78M | #ifdef HAVE_PCRE2 |
2355 | 4.78M | uint32_t eflag; |
2356 | 4.78M | PCRE2_SIZE *ovector = NULL; |
2357 | | #else |
2358 | | int eflag; |
2359 | | int ovector[ovecsize]; |
2360 | | /* zero for unknown patterns; this is done to make sure that back |
2361 | | references to unset groups return an empty string, but it is |
2362 | | not needed anymore as ncap is being checked due to PCRE2 */ |
2363 | | memset(ovector, 0, ovecsize*sizeof(int)); |
2364 | | #endif |
2365 | 4.78M | ns = (int) strlen(s); |
2366 | 4.78M | sub_buffer_size_init(replen, ns, count_subs(srep), global, |
2367 | 4.78M | &nns, &maxrep); |
2368 | 4.78M | u = cbuf = R_Calloc(nns, char); |
2369 | 4.78M | offset = 0; nmatch = 0; eflag = 0; last_end = -1; |
2370 | | /* ncap is one more than the number of capturing patterns */ |
2371 | 4.78M | #ifdef HAVE_PCRE2 |
2372 | 4.78M | if (use_UTF8) eflag |= PCRE2_NO_UTF_CHECK; |
2373 | | /* PCRE2 has also pcre2_substitute */ |
2374 | 4.78M | while ((rc = pcre2_match(re, (PCRE2_SPTR) s, (PCRE2_SIZE) ns, |
2375 | 4.78M | (PCRE2_SIZE) offset, eflag, mdata, |
2376 | 4.78M | mcontext)) >= 0 ) { |
2377 | | |
2378 | 2.88M | ovector = pcre2_get_ovector_pointer(mdata); |
2379 | | #else |
2380 | | while ((rc = pcre_exec(re_pcre, re_pe, s, ns, offset, eflag, |
2381 | | ovector, 30)) >= 0) { |
2382 | | #endif |
2383 | | /* printf("%s, %d, %d %d\n", s, offset, |
2384 | | ovector[0], ovector[1]); */ |
2385 | 2.88M | nmatch++; |
2386 | 11.4M | for (j = offset; j < ovector[0]; j++) *u++ = s[j]; |
2387 | 2.88M | ncap = rc > 0 ? rc : 10; |
2388 | 2.88M | if (last_end == -1 /* for PCRE2 */ || ovector[1] > last_end) { |
2389 | 2.88M | u = R_pcre_string_adj(u, s, srep, ovector, use_UTF8, ncap); |
2390 | 2.88M | last_end = (int) ovector[1]; |
2391 | 2.88M | } |
2392 | 2.88M | offset = (int) ovector[1]; |
2393 | 2.88M | if (s[offset] == '\0' || !global) break; |
2394 | 0 | if (ovector[1] == ovector[0]) { |
2395 | | /* advance by a char */ |
2396 | 0 | if (use_UTF8) { |
2397 | 0 | int used, pos = 0; |
2398 | 0 | while( (used = utf8clen(s[pos])) ) { |
2399 | 0 | pos += used; |
2400 | 0 | if (pos > offset) { |
2401 | 0 | for (j = offset; j < pos; j++) *u++ = s[j]; |
2402 | 0 | offset = pos; |
2403 | 0 | break; |
2404 | 0 | } |
2405 | 0 | } |
2406 | 0 | } else |
2407 | 0 | *u++ = s[offset++]; |
2408 | 0 | } |
2409 | 0 | double needed = (double)(u-cbuf) + (double)(ns-offset) |
2410 | 0 | + (double)maxrep + 100.; |
2411 | 0 | sub_buffer_expand(needed, &nns, &cbuf, &u); |
2412 | 0 | #ifdef HAVE_PCRE2 |
2413 | 0 | eflag = PCRE2_NOTBOL; /* probably not needed */ |
2414 | 0 | if (use_UTF8) eflag |= PCRE2_NO_UTF_CHECK; |
2415 | | #else |
2416 | | eflag = PCRE_NOTBOL; /* probably not needed */ |
2417 | | #endif |
2418 | 0 | } |
2419 | 4.78M | R_pcre_exec_error(rc, i); |
2420 | 4.78M | if (nmatch == 0) |
2421 | 1.89M | SET_STRING_ELT(ans, i, markBytesOld(STRING_ELT(text, i), |
2422 | 1.89M | useBytes, haveBytesInput)); |
2423 | 2.88M | else if (STRING_ELT(rep, 0) == NA_STRING) |
2424 | 0 | SET_STRING_ELT(ans, i, NA_STRING); |
2425 | 2.88M | else { |
2426 | | /* copy the tail */ |
2427 | 2.88M | double needed = (double)(u-cbuf) + (double)(ns-offset) + 1.0; |
2428 | 2.88M | sub_buffer_expand(needed, &nns, &cbuf, &u); |
2429 | 19.2M | for (j = offset ; s[j] ; j++) *u++ = s[j]; |
2430 | 2.88M | *u = '\0'; |
2431 | 2.88M | if (useBytes) |
2432 | 448k | SET_STRING_ELT(ans, i, mkBytesNew(cbuf, haveBytesInput)); |
2433 | 2.43M | else if (use_UTF8) |
2434 | 2.43M | SET_STRING_ELT(ans, i, mkCharCE(cbuf, CE_UTF8)); |
2435 | 0 | else |
2436 | 0 | SET_STRING_ELT(ans, i, markKnown(cbuf, STRING_ELT(text, i))); |
2437 | 2.88M | } |
2438 | 4.78M | R_Free(cbuf); |
2439 | 4.78M | } else if (!use_WC) { |
2440 | 228k | int maxrep; |
2441 | | /* extended regexp in bytes */ |
2442 | | |
2443 | 228k | ns = (int) strlen(s); |
2444 | 228k | sub_buffer_size_init(replen, ns, count_subs(srep), global, |
2445 | 228k | &nns, &maxrep); |
2446 | 228k | u = cbuf = R_Calloc(nns, char); |
2447 | 228k | offset = 0; nmatch = 0; eflags = 0; last_end = -1; |
2448 | 654k | while ((rc = tre_regexecb(®, s+offset, 10, regmatch, eflags)) |
2449 | 654k | == 0) { |
2450 | | /* printf("%s, %d %d\n", &s[offset], |
2451 | | regmatch[0].rm_so, regmatch[0].rm_eo); */ |
2452 | 526k | nmatch++; |
2453 | 4.18M | for (j = 0; j < regmatch[0].rm_so ; j++) |
2454 | 3.65M | *u++ = s[offset+j]; |
2455 | 526k | if (offset+regmatch[0].rm_eo > last_end) { |
2456 | 526k | u = string_adj(u, s+offset, srep, regmatch); |
2457 | 526k | last_end = offset+regmatch[0].rm_eo; |
2458 | 526k | } |
2459 | 526k | offset += regmatch[0].rm_eo; |
2460 | 526k | if (s[offset] == '\0' || !global) break; |
2461 | 426k | if (regmatch[0].rm_eo == regmatch[0].rm_so) |
2462 | 91 | *u++ = s[offset++]; |
2463 | 426k | double needed = (double)(u-cbuf) + (double)(ns-offset) |
2464 | 426k | + (double)maxrep + 100.; |
2465 | 426k | sub_buffer_expand(needed, &nns, &cbuf, &u); |
2466 | 426k | eflags = REG_NOTBOL; |
2467 | 426k | } |
2468 | | // AFAICS the only possible error report is REG_ESPACE |
2469 | 228k | if (rc == REG_ESPACE) |
2470 | 0 | warning("Out-of-memory error in regexp matching for element %d", |
2471 | 0 | (int) i + 1); |
2472 | | |
2473 | 228k | if (nmatch == 0) |
2474 | 7.54k | SET_STRING_ELT(ans, i, markBytesOld(STRING_ELT(text, i), |
2475 | 7.54k | useBytes, haveBytesInput)); |
2476 | 221k | else if (STRING_ELT(rep, 0) == NA_STRING) |
2477 | 0 | SET_STRING_ELT(ans, i, NA_STRING); |
2478 | 221k | else { |
2479 | | /* copy the tail */ |
2480 | 221k | double needed = (double)(u-cbuf) + (double)(ns-offset) + 1.0; |
2481 | 221k | sub_buffer_expand(needed, &nns, &cbuf, &u); |
2482 | 919k | for (j = offset ; s[j] ; j++) *u++ = s[j]; |
2483 | 221k | *u = '\0'; |
2484 | 221k | if (useBytes) |
2485 | 219k | SET_STRING_ELT(ans, i, mkBytesNew(cbuf, haveBytesInput)); |
2486 | 1.35k | else |
2487 | 1.35k | SET_STRING_ELT(ans, i, markKnown(cbuf, STRING_ELT(text, i))); |
2488 | 221k | } |
2489 | 228k | R_Free(cbuf); |
2490 | 857k | } else { |
2491 | | /* extended regexp in wchar_t */ |
2492 | 857k | wchar_t *u, *cbuf; |
2493 | 857k | int maxrep; |
2494 | 857k | bool ascii_texti = IS_ASCII(STRING_ELT(text, i)); |
2495 | | |
2496 | 857k | ns = (int) wcslen(ws); |
2497 | 857k | sub_buffer_size_init(replen, ns, wcount_subs(wrep), global, |
2498 | 857k | &nns, &maxrep); |
2499 | 857k | u = cbuf = R_Calloc(nns, wchar_t); |
2500 | 857k | offset = 0; nmatch = 0; eflags = 0; last_end = -1; |
2501 | 857k | while (tre_regwexec(®, ws+offset, 10, regmatch, eflags) == 0) { |
2502 | 857k | nmatch++; |
2503 | 9.42M | for (j = 0; j < regmatch[0].rm_so ; j++) |
2504 | 8.56M | *u++ = ws[offset+j]; |
2505 | 857k | if (offset+regmatch[0].rm_eo > last_end) { |
2506 | 857k | u = wstring_adj(u, ws+offset, wrep, regmatch); |
2507 | 857k | last_end = offset+regmatch[0].rm_eo; |
2508 | 857k | } |
2509 | 857k | offset += regmatch[0].rm_eo; |
2510 | 857k | if (ws[offset] == L'\0' || !global) break; |
2511 | 0 | if (regmatch[0].rm_eo == regmatch[0].rm_so) |
2512 | 0 | *u++ = ws[offset++]; |
2513 | 0 | double needed = (double)(u-cbuf) + (double)(ns-offset) |
2514 | 0 | + (double)maxrep + 100.; |
2515 | 0 | wsub_buffer_expand(needed, &nns, &cbuf, &u); |
2516 | 0 | eflags = REG_NOTBOL; |
2517 | 0 | } |
2518 | 857k | if (nmatch == 0) |
2519 | 0 | SET_STRING_ELT(ans, i, markBytesOld(STRING_ELT(text, i), |
2520 | 0 | useBytes, haveBytesInput)); |
2521 | 857k | else if (STRING_ELT(rep, 0) == NA_STRING) |
2522 | 0 | SET_STRING_ELT(ans, i, NA_STRING); |
2523 | 857k | else { |
2524 | | /* copy the tail */ |
2525 | 857k | double needed = (double)(u-cbuf) + (double)(ns-offset) + 1.; |
2526 | 857k | wsub_buffer_expand(needed, &nns, &cbuf, &u); |
2527 | 857k | for (j = offset ; ws[j] ; j++) *u++ = ws[j]; |
2528 | 857k | *u = L'\0'; |
2529 | 857k | SET_STRING_ELT(ans, i, |
2530 | 857k | mkCharWLenASCII(cbuf, (int)(u-cbuf), |
2531 | 857k | ascii_patrep && ascii_texti)); |
2532 | 857k | } |
2533 | 857k | R_Free(cbuf); |
2534 | 857k | } |
2535 | 5.86M | vmaxset(vmax); |
2536 | 5.86M | } |
2537 | | |
2538 | 70.6k | GSUB_FREE_PATTERN(); |
2539 | | |
2540 | 70.6k | exit_gsub: |
2541 | 70.6k | SHALLOW_DUPLICATE_ATTRIB(ans, text); |
2542 | | /* This also copied the class, if any */ |
2543 | 70.6k | UNPROTECT(1); |
2544 | 70.6k | return ans; |
2545 | 70.6k | } |
2546 | | |
2547 | | static int getNc(const char *s, int st) |
2548 | 0 | { |
2549 | 0 | int i, nc = 0; |
2550 | 0 | for(i = 0; i < st; i += utf8clen(s[i])) |
2551 | 0 | nc++; |
2552 | 0 | return nc; |
2553 | 0 | } |
2554 | | |
2555 | | static SEXP gregexpr_BadStringAns(void); |
2556 | | |
2557 | | static SEXP |
2558 | | gregexpr_Regexc(const regex_t *reg, SEXP sstr, int useBytes, int use_WC, |
2559 | | R_xlen_t i, SEXP itype, int *nwarn) |
2560 | 0 | { |
2561 | 0 | int matchIndex = -1, j, st, foundAll = 0, foundAny = 0; |
2562 | 0 | size_t len, offset = 0; |
2563 | 0 | regmatch_t regmatch[10]; |
2564 | 0 | SEXP ans, matchlen; /* Return vect and its attribute */ |
2565 | 0 | SEXP matchbuf, matchlenbuf; /* Buffers for storing multiple matches */ |
2566 | 0 | int bufsize = 1024; /* Starting size for buffers */ |
2567 | 0 | int eflags = 0; |
2568 | 0 | const char *string = NULL; |
2569 | 0 | const wchar_t *ws = NULL; |
2570 | |
|
2571 | 0 | PROTECT(matchbuf = allocVector(INTSXP, bufsize)); |
2572 | 0 | PROTECT(matchlenbuf = allocVector(INTSXP, bufsize)); |
2573 | |
|
2574 | 0 | if (useBytes) { |
2575 | 0 | string = CHAR(sstr); |
2576 | 0 | len = strlen(string); |
2577 | 0 | use_WC = false; /* to be sure */ |
2578 | 0 | } else if (!use_WC) { |
2579 | 0 | string = translateCharFP2(sstr); |
2580 | 0 | if (!string || (mbcslocale && !mbcsValid(string))) { |
2581 | 0 | if ((*nwarn)++ < NWARN) |
2582 | 0 | warning(_("input string %lld is invalid in this locale"), |
2583 | 0 | (long long)i+1); |
2584 | 0 | return gregexpr_BadStringAns(); |
2585 | 0 | } |
2586 | 0 | len = strlen(string); |
2587 | 0 | } else { |
2588 | 0 | ws = wtransChar2(sstr); |
2589 | 0 | if (!ws) { |
2590 | 0 | if ((*nwarn)++ < NWARN) |
2591 | 0 | warning(_("input string %lld is invalid"), (long long)i+1); |
2592 | 0 | return gregexpr_BadStringAns(); |
2593 | 0 | } |
2594 | 0 | len = wcslen(ws); |
2595 | 0 | } |
2596 | | |
2597 | 0 | while (!foundAll) { |
2598 | 0 | int rc = REG_OK; // in case offset>=len (e.g., when len==0) |
2599 | 0 | if ( offset < len && |
2600 | 0 | (rc = !use_WC ? tre_regexecb(reg, string+offset, 1, regmatch, eflags) : |
2601 | 0 | tre_regwexec(reg, ws+offset, 1, regmatch, eflags)) |
2602 | 0 | == REG_OK) { |
2603 | 0 | if ((matchIndex + 1) == bufsize) { |
2604 | | /* Reallocate match buffers */ |
2605 | 0 | int newbufsize = bufsize * 2; |
2606 | 0 | SEXP tmp; |
2607 | 0 | tmp = allocVector(INTSXP, 2 * bufsize); |
2608 | 0 | for (j = 0; j < bufsize; j++) |
2609 | 0 | INTEGER(tmp)[j] = INTEGER(matchlenbuf)[j]; |
2610 | 0 | UNPROTECT(1); |
2611 | 0 | matchlenbuf = tmp; |
2612 | 0 | PROTECT(matchlenbuf); |
2613 | 0 | tmp = allocVector(INTSXP, 2 * bufsize); |
2614 | 0 | for (j = 0; j < bufsize; j++) |
2615 | 0 | INTEGER(tmp)[j] = INTEGER(matchbuf)[j]; |
2616 | 0 | matchbuf = tmp; |
2617 | 0 | UNPROTECT(2); |
2618 | 0 | PROTECT(matchbuf); |
2619 | 0 | PROTECT(matchlenbuf); |
2620 | 0 | bufsize = newbufsize; |
2621 | 0 | } |
2622 | 0 | matchIndex++; |
2623 | 0 | foundAny = 1; |
2624 | 0 | st = regmatch[0].rm_so; |
2625 | 0 | INTEGER(matchbuf)[matchIndex] = (int)(offset + st + 1); /* index from one */ |
2626 | 0 | INTEGER(matchlenbuf)[matchIndex] = regmatch[0].rm_eo - st; |
2627 | 0 | if (INTEGER(matchlenbuf)[matchIndex] == 0) |
2628 | 0 | offset += st + 1; |
2629 | 0 | else |
2630 | 0 | offset += regmatch[0].rm_eo; |
2631 | 0 | } else { |
2632 | 0 | foundAll = 1; |
2633 | 0 | if (!foundAny) { |
2634 | 0 | matchIndex++; |
2635 | 0 | INTEGER(matchbuf)[matchIndex] = -1; |
2636 | 0 | INTEGER(matchlenbuf)[matchIndex] = -1; |
2637 | 0 | } |
2638 | 0 | } |
2639 | 0 | eflags = REG_NOTBOL; |
2640 | | // AFAICS the only possible error report is REG_ESPACE |
2641 | 0 | if (rc == REG_ESPACE) |
2642 | 0 | warning("Out-of-memory error in regexp matching for element %d", |
2643 | 0 | (int) i + 1); |
2644 | 0 | } |
2645 | 0 | PROTECT(ans = allocVector(INTSXP, matchIndex + 1)); |
2646 | 0 | PROTECT(matchlen = allocVector(INTSXP, matchIndex + 1)); |
2647 | | /* copy from buffers */ |
2648 | 0 | for (j = 0; j <= matchIndex; j++) { |
2649 | 0 | INTEGER(ans)[j] = INTEGER(matchbuf)[j]; |
2650 | 0 | INTEGER(matchlen)[j] = INTEGER(matchlenbuf)[j]; |
2651 | 0 | } |
2652 | 0 | setAttrib(ans, install("match.length"), matchlen); |
2653 | 0 | if(useBytes) { |
2654 | 0 | setAttrib(ans, install("index.type"), itype); |
2655 | 0 | setAttrib(ans, install("useBytes"), R_TrueValue); |
2656 | 0 | } |
2657 | 0 | UNPROTECT(4); |
2658 | 0 | return ans; |
2659 | 0 | } |
2660 | | |
2661 | | static SEXP |
2662 | | gregexpr_fixed(const char *pattern, const char *string, |
2663 | | bool useBytes, bool use_UTF8, SEXP itype) |
2664 | 0 | { |
2665 | 0 | int patlen, matchIndex, st = 0, foundAll = 0, foundAny = 0, j, |
2666 | 0 | ansSize, nb = 0; |
2667 | 0 | size_t curpos = 0, slen; |
2668 | 0 | SEXP ans, matchlen; /* return vect and its attribute */ |
2669 | 0 | SEXP matchbuf, matchlenbuf; /* buffers for storing multiple matches */ |
2670 | 0 | int bufsize = 1024; /* starting size for buffers */ |
2671 | 0 | PROTECT(matchbuf = allocVector(INTSXP, bufsize)); |
2672 | 0 | PROTECT(matchlenbuf = allocVector(INTSXP, bufsize)); |
2673 | 0 | if (!useBytes && use_UTF8) |
2674 | 0 | patlen = (int) utf8towcs(NULL, pattern, 0); |
2675 | 0 | else if (!useBytes && mbcslocale) |
2676 | 0 | patlen = (int) mbstowcs(NULL, pattern, 0); |
2677 | 0 | else |
2678 | 0 | patlen = (int) strlen(pattern); |
2679 | 0 | slen = strlen(string); |
2680 | 0 | st = fgrep_one(pattern, string, useBytes, use_UTF8, &nb); |
2681 | 0 | matchIndex = -1; |
2682 | 0 | if (st < 0) { |
2683 | 0 | INTEGER(matchbuf)[0] = -1; |
2684 | 0 | INTEGER(matchlenbuf)[0] = -1; |
2685 | 0 | } else { |
2686 | 0 | foundAny = 1; |
2687 | 0 | matchIndex++; |
2688 | 0 | INTEGER(matchbuf)[matchIndex] = st + 1; /* index from one */ |
2689 | 0 | INTEGER(matchlenbuf)[matchIndex] = patlen; |
2690 | 0 | while(!foundAll) { |
2691 | 0 | string += nb; |
2692 | 0 | if (patlen == 0) |
2693 | 0 | curpos += st + 1; |
2694 | 0 | else |
2695 | 0 | curpos += st + patlen; |
2696 | 0 | if (curpos >= slen) |
2697 | 0 | break; |
2698 | 0 | st = fgrep_one(pattern, string, useBytes, use_UTF8, &nb); |
2699 | 0 | if (st >= 0) { |
2700 | 0 | if ((matchIndex + 1) == bufsize) { |
2701 | | /* Reallocate match buffers */ |
2702 | 0 | int newbufsize = bufsize * 2; |
2703 | 0 | SEXP tmp; |
2704 | 0 | tmp = allocVector(INTSXP, 2 * bufsize); |
2705 | 0 | for (j = 0; j < bufsize; j++) |
2706 | 0 | INTEGER(tmp)[j] = INTEGER(matchlenbuf)[j]; |
2707 | 0 | UNPROTECT(1); |
2708 | 0 | matchlenbuf = tmp; |
2709 | 0 | PROTECT(matchlenbuf); |
2710 | 0 | tmp = allocVector(INTSXP, 2 * bufsize); |
2711 | 0 | for (j = 0; j < bufsize; j++) |
2712 | 0 | INTEGER(tmp)[j] = INTEGER(matchbuf)[j]; |
2713 | 0 | matchbuf = tmp; |
2714 | 0 | UNPROTECT(2); |
2715 | 0 | PROTECT(matchbuf); |
2716 | 0 | PROTECT(matchlenbuf); |
2717 | 0 | bufsize = newbufsize; |
2718 | 0 | } |
2719 | 0 | matchIndex++; |
2720 | | /* index from one */ |
2721 | 0 | INTEGER(matchbuf)[matchIndex] = (int)(curpos + st + 1); |
2722 | 0 | INTEGER(matchlenbuf)[matchIndex] = patlen; |
2723 | 0 | } else foundAll = 1; |
2724 | 0 | } |
2725 | 0 | } |
2726 | 0 | ansSize = foundAny ? (matchIndex + 1) : 1; |
2727 | 0 | PROTECT(ans = allocVector(INTSXP, ansSize)); |
2728 | 0 | PROTECT(matchlen = allocVector(INTSXP, ansSize)); |
2729 | | /* copy from buffers */ |
2730 | 0 | for (j = 0; j < ansSize; j++) { |
2731 | 0 | INTEGER(ans)[j] = INTEGER(matchbuf)[j]; |
2732 | 0 | INTEGER(matchlen)[j] = INTEGER(matchlenbuf)[j]; |
2733 | 0 | } |
2734 | 0 | setAttrib(ans, install("match.length"), matchlen); |
2735 | 0 | if(useBytes) { |
2736 | 0 | setAttrib(ans, install("index.type"), itype); |
2737 | 0 | setAttrib(ans, install("useBytes"), R_TrueValue); |
2738 | 0 | } |
2739 | 0 | UNPROTECT(4); |
2740 | 0 | return ans; |
2741 | 0 | } |
2742 | | |
2743 | | /* This function is used to convert a single ovector (match_start, |
2744 | | match_end) pair (in bytes) to a pair of (match_start in 1-indexed |
2745 | | unicode characters stored in mptr, match_length in number of |
2746 | | unicode characters stored in lenptr) |
2747 | | |
2748 | | We have to do this once for the match and once for every group, so |
2749 | | I generalized the method and call it twice from |
2750 | | extract_match_and_groups to avoid repetitive code. |
2751 | | |
2752 | | Toby Dylan Hocking 2011-03-10 |
2753 | | */ |
2754 | | #ifdef HAVE_PCRE2 |
2755 | | static bool |
2756 | | ovector_extract_start_length(bool use_UTF8,PCRE2_SIZE *ovector, |
2757 | | int *mptr,int *lenptr,const char *string) |
2758 | | #else |
2759 | | static bool |
2760 | | ovector_extract_start_length(bool use_UTF8,int *ovector, |
2761 | | int *mptr,int *lenptr,const char *string) |
2762 | | #endif |
2763 | 0 | { |
2764 | 0 | bool foundAll = false; |
2765 | | /* FIXME: what if the match is unused? */ |
2766 | 0 | int st = (int) ovector[0]; |
2767 | 0 | *mptr = st + 1; /* index from one */ |
2768 | 0 | *lenptr = (int) ovector[1] - st; |
2769 | 0 | if (use_UTF8) { |
2770 | | /* Unfortunately these are in bytes */ |
2771 | 0 | if (st > 0) { |
2772 | 0 | *mptr = 1 + getNc(string, st); |
2773 | 0 | if (*mptr <= 0) { /* an invalid string */ |
2774 | | /* FIXME: seems unreachable */ |
2775 | 0 | *mptr = NA_INTEGER; |
2776 | 0 | foundAll = true; /* if we get here, we are done */ |
2777 | 0 | } |
2778 | 0 | } |
2779 | 0 | *lenptr = getNc(string + st, *lenptr); |
2780 | 0 | if (*lenptr < 0) {/* an invalid string */ |
2781 | | /* FIXME: seems unreachable */ |
2782 | 0 | *lenptr = NA_INTEGER; |
2783 | 0 | foundAll = true; |
2784 | 0 | } |
2785 | 0 | } |
2786 | 0 | return foundAll; |
2787 | 0 | } |
2788 | | |
2789 | | /* this function generalizes the parsing of the "ovector" from pcre |
2790 | | which contains the match and group start and end bytes. it is |
2791 | | organized as follows: match_start match_end group1_start group1_end |
2792 | | group2_start group2_end ... we process these in regexpr and |
2793 | | gregexpr, so I made this function to avoid duplicating code between |
2794 | | the 2. |
2795 | | |
2796 | | Toby Dylan Hocking 2011-03-10 */ |
2797 | | #ifdef HAVE_PCRE2 |
2798 | | static bool |
2799 | | extract_match_and_groups(bool use_UTF8, PCRE2_SIZE *ovector, int capture_count, |
2800 | | int *mptr, int *lenptr, int *cptr, int *clenptr, |
2801 | | const char *string, int capture_stride) |
2802 | | #else |
2803 | | static bool |
2804 | | extract_match_and_groups(bool use_UTF8, int *ovector, int capture_count, |
2805 | | int *mptr, int *lenptr, int *cptr, int *clenptr, |
2806 | | const char *string, int capture_stride) |
2807 | | #endif |
2808 | 0 | { |
2809 | 0 | bool foundAll = |
2810 | 0 | ovector_extract_start_length(use_UTF8, ovector, mptr, lenptr, string); |
2811 | | /* also extract capture locations */ |
2812 | 0 | for(int i = 0; i < capture_count; i++) { |
2813 | 0 | int ind = capture_stride*i; |
2814 | 0 | ovector_extract_start_length(use_UTF8, ovector+2*(i+1), |
2815 | 0 | cptr+ind, clenptr+ind, string); |
2816 | 0 | } |
2817 | 0 | return foundAll; |
2818 | 0 | } |
2819 | | |
2820 | | #ifdef HAVE_PCRE2 |
2821 | | static SEXP |
2822 | | R_pcre2_gregexpr(const char *pattern, const char *string, |
2823 | | pcre2_code *re, bool useBytes, bool use_UTF8, |
2824 | | pcre2_match_data *mdata, pcre2_match_context *mcontext, |
2825 | | int capture_count, SEXP capture_names, R_xlen_t n, SEXP itype) |
2826 | | #else |
2827 | | static SEXP |
2828 | | R_pcre_gregexpr(const char *pattern, const char *string, |
2829 | | pcre *re_pcre, pcre_extra *re_pe, |
2830 | | bool useBytes, bool use_UTF8, |
2831 | | int *ovector, int ovector_size, |
2832 | | int capture_count, SEXP capture_names, R_xlen_t n, |
2833 | | SEXP itype) |
2834 | | #endif |
2835 | 0 | { |
2836 | 0 | bool foundAll = false, foundAny = false; |
2837 | 0 | int matchIndex = -1, start = 0; |
2838 | 0 | SEXP ans, matchlen; /* return vect and its attribute */ |
2839 | 0 | SEXP capturebuf, capturelenbuf; |
2840 | 0 | SEXP matchbuf, matchlenbuf; /* buffers for storing multiple matches */ |
2841 | 0 | int bufsize = 1024; /* starting size for buffers */ |
2842 | 0 | int slen = (int) strlen(string); |
2843 | 0 | PROTECT_INDEX cb, clb, mb, mlb; |
2844 | |
|
2845 | 0 | PROTECT_WITH_INDEX(capturebuf = |
2846 | 0 | allocVector(INTSXP, bufsize*capture_count), &cb); |
2847 | 0 | PROTECT_WITH_INDEX(capturelenbuf = |
2848 | 0 | allocVector(INTSXP, bufsize*capture_count), &clb); |
2849 | 0 | PROTECT_WITH_INDEX(matchbuf = allocVector(INTSXP, bufsize), &mb); |
2850 | 0 | PROTECT_WITH_INDEX(matchlenbuf = allocVector(INTSXP, bufsize), &mlb); |
2851 | |
|
2852 | 0 | while (!foundAll) { |
2853 | 0 | #ifdef HAVE_PCRE2 |
2854 | 0 | uint32_t eflag = 0; |
2855 | 0 | if (use_UTF8) eflag |= PCRE2_NO_UTF_CHECK; |
2856 | 0 | int rc = pcre2_match(re, (PCRE2_SPTR) string, slen, start, eflag, |
2857 | 0 | mdata, mcontext); |
2858 | 0 | PCRE2_SIZE* ovector = pcre2_get_ovector_pointer(mdata); |
2859 | | #else |
2860 | | int rc = pcre_exec(re_pcre, re_pe, string, slen, start, 0, ovector, |
2861 | | ovector_size); |
2862 | | #endif |
2863 | 0 | R_pcre_exec_error(rc, n); |
2864 | 0 | if (rc >= 0) { |
2865 | 0 | if ((matchIndex + 1) == bufsize) { |
2866 | | /* Reallocate match buffers */ |
2867 | 0 | int newbufsize = bufsize * 2; |
2868 | 0 | SEXP tmp; |
2869 | 0 | tmp = allocVector(INTSXP, newbufsize); |
2870 | 0 | for (int j = 0; j < bufsize; j++) /* or use memcpy */ |
2871 | 0 | INTEGER(tmp)[j] = INTEGER(matchlenbuf)[j]; |
2872 | 0 | REPROTECT(matchlenbuf = tmp, mlb); |
2873 | 0 | tmp = allocVector(INTSXP, newbufsize); |
2874 | 0 | for (int j = 0; j < bufsize; j++) /* or use memcpy */ |
2875 | 0 | INTEGER(tmp)[j] = INTEGER(matchbuf)[j]; |
2876 | 0 | REPROTECT(matchbuf = tmp, mb); |
2877 | 0 | if (capture_count) { |
2878 | 0 | tmp = allocVector(INTSXP, newbufsize*capture_count); |
2879 | 0 | for(int j = 0; j < bufsize; j++) |
2880 | 0 | for(int i = 0; i < capture_count; i++) |
2881 | 0 | INTEGER(tmp)[j + newbufsize*i] = |
2882 | 0 | INTEGER(capturebuf)[j + bufsize*i]; |
2883 | 0 | REPROTECT(capturebuf = tmp, cb); |
2884 | 0 | tmp = allocVector(INTSXP, newbufsize*capture_count); |
2885 | 0 | for(int j = 0; j < bufsize; j++) |
2886 | 0 | for(int i = 0; i < capture_count; i++) |
2887 | 0 | INTEGER(tmp)[j + newbufsize*i] = |
2888 | 0 | INTEGER(capturelenbuf)[j + bufsize*i]; |
2889 | 0 | REPROTECT(capturelenbuf = tmp, clb); |
2890 | 0 | } |
2891 | 0 | bufsize = newbufsize; |
2892 | 0 | } |
2893 | 0 | matchIndex++; |
2894 | 0 | foundAny = true; |
2895 | 0 | foundAll = |
2896 | 0 | extract_match_and_groups(use_UTF8, ovector, capture_count, |
2897 | 0 | INTEGER(matchbuf) + matchIndex, |
2898 | 0 | INTEGER(matchlenbuf) + matchIndex, |
2899 | 0 | INTEGER(capturebuf) + matchIndex, |
2900 | 0 | INTEGER(capturelenbuf) + matchIndex, |
2901 | 0 | string, bufsize); |
2902 | | /* we need to advance 'start' in bytes */ |
2903 | 0 | if (ovector[1] - ovector[0] == 0) |
2904 | 0 | start = (int) ovector[0] + 1; |
2905 | 0 | else |
2906 | 0 | start = (int) ovector[1]; |
2907 | 0 | if (start >= slen) foundAll = 1; |
2908 | 0 | } else { |
2909 | 0 | foundAll = true; |
2910 | 0 | if (!foundAny) matchIndex = 0; |
2911 | 0 | } |
2912 | 0 | } |
2913 | 0 | PROTECT(ans = allocVector(INTSXP, matchIndex + 1)); |
2914 | | /* Protect in case install("match.length") allocates */ |
2915 | 0 | PROTECT(matchlen = allocVector(INTSXP, matchIndex + 1)); |
2916 | 0 | setAttrib(ans, install("match.length"), matchlen); |
2917 | 0 | if(useBytes) { |
2918 | 0 | setAttrib(ans, install("index.type"), itype); |
2919 | 0 | setAttrib(ans, install("useBytes"), R_TrueValue); |
2920 | 0 | } |
2921 | 0 | UNPROTECT(1); |
2922 | 0 | if (foundAny) { |
2923 | 0 | for (int j = 0; j <= matchIndex; j++) { |
2924 | 0 | INTEGER(ans)[j] = INTEGER(matchbuf)[j]; |
2925 | 0 | INTEGER(matchlen)[j] = INTEGER(matchlenbuf)[j]; |
2926 | 0 | } |
2927 | 0 | } else |
2928 | 0 | INTEGER(ans)[0] = INTEGER(matchlen)[0] = -1; |
2929 | |
|
2930 | 0 | if (capture_count) { |
2931 | 0 | SEXP capture, capturelen, dmn; |
2932 | 0 | PROTECT(capture = allocMatrix(INTSXP, matchIndex+1, capture_count)); |
2933 | 0 | PROTECT(capturelen = allocMatrix(INTSXP, matchIndex+1, capture_count)); |
2934 | 0 | PROTECT(dmn = allocVector(VECSXP, 2)); |
2935 | 0 | SET_VECTOR_ELT(dmn, 1, capture_names); |
2936 | 0 | setAttrib(capture, R_DimNamesSymbol, dmn); |
2937 | 0 | setAttrib(capturelen, R_DimNamesSymbol, dmn); |
2938 | 0 | if (foundAny) { |
2939 | 0 | for (int j = 0; j <= matchIndex; j++) |
2940 | 0 | for(int i = 0; i < capture_count; i++) { |
2941 | 0 | int return_index = j + (matchIndex+1) * i; |
2942 | 0 | int buffer_index = j + bufsize * i; |
2943 | 0 | INTEGER(capture)[return_index] = |
2944 | 0 | INTEGER(capturebuf)[buffer_index]; |
2945 | 0 | INTEGER(capturelen)[return_index] = |
2946 | 0 | INTEGER(capturelenbuf)[buffer_index]; |
2947 | 0 | } |
2948 | 0 | } else |
2949 | 0 | for(int i = 0; i < capture_count; i++) |
2950 | 0 | INTEGER(capture)[i] = INTEGER(capturelen)[i] = -1; |
2951 | 0 | setAttrib(ans, install("capture.start"), capture); |
2952 | 0 | setAttrib(ans, install("capture.length"), capturelen); |
2953 | 0 | setAttrib(ans, install("capture.names"), capture_names); |
2954 | 0 | UNPROTECT(3); |
2955 | 0 | } |
2956 | 0 | UNPROTECT(5); /* 4 with indices, ans */ |
2957 | 0 | return ans; |
2958 | 0 | } |
2959 | | |
2960 | | static SEXP gregexpr_NAInputAns(void) |
2961 | 0 | { |
2962 | 0 | SEXP ans, matchlen; |
2963 | 0 | PROTECT(ans = allocVector(INTSXP, 1)); |
2964 | 0 | PROTECT(matchlen = allocVector(INTSXP, 1)); |
2965 | 0 | INTEGER(ans)[0] = INTEGER(matchlen)[0] = R_NaInt; |
2966 | 0 | setAttrib(ans, install("match.length"), matchlen); |
2967 | 0 | UNPROTECT(2); |
2968 | 0 | return ans; |
2969 | 0 | } |
2970 | | |
2971 | | static SEXP gregexpr_BadStringAns(void) |
2972 | 0 | { |
2973 | 0 | SEXP ans, matchlen; |
2974 | 0 | PROTECT(ans = allocVector(INTSXP, 1)); |
2975 | 0 | PROTECT(matchlen = allocVector(INTSXP, 1)); |
2976 | 0 | INTEGER(ans)[0] = INTEGER(matchlen)[0] = -1; |
2977 | 0 | setAttrib(ans, install("match.length"), matchlen); |
2978 | 0 | UNPROTECT(2); |
2979 | 0 | return ans; |
2980 | 0 | } |
2981 | | |
2982 | | attribute_hidden SEXP do_regexpr(SEXP call, SEXP op, SEXP args, SEXP env) |
2983 | 163 | { |
2984 | 163 | SEXP pat, text, ans, itype; |
2985 | 163 | regex_t reg; |
2986 | 163 | regmatch_t regmatch[10]; |
2987 | 163 | R_xlen_t i, n; |
2988 | 163 | bool igcase_opt, perl_opt, fixed_opt, useBytes; |
2989 | 163 | const char *spat = NULL; /* -Wall */ |
2990 | 163 | const wchar_t *wpat = NULL; |
2991 | 163 | const char *s = NULL; |
2992 | 163 | const wchar_t *ws = NULL; |
2993 | 163 | const unsigned char *tables = NULL /* -Wall */; |
2994 | 163 | #ifdef HAVE_PCRE2 |
2995 | 163 | pcre2_code *re = NULL; |
2996 | 163 | pcre2_match_context *mcontext = NULL; |
2997 | 163 | pcre2_match_data *mdata = NULL; |
2998 | 163 | PCRE2_SIZE *ovector = NULL; |
2999 | 163 | uint32_t name_count, name_entry_size, capture_count; |
3000 | | #else |
3001 | | pcre *re_pcre = NULL /* -Wall */; |
3002 | | pcre_extra *re_pe = NULL; |
3003 | | int *ovector = NULL, name_count, name_entry_size, capture_count; |
3004 | | #endif |
3005 | 163 | bool use_UTF8 = false, use_WC = false; |
3006 | 163 | char *name_table; |
3007 | 163 | const void *vmax; |
3008 | 163 | int info_code, ovector_size = 0; /* -Wall */ |
3009 | 163 | SEXP capture_names = R_NilValue; |
3010 | 163 | int nwarn = 0; |
3011 | | |
3012 | 163 | checkArity(op, args); |
3013 | 163 | pat = CAR(args); args = CDR(args); |
3014 | 163 | text = CAR(args); args = CDR(args); |
3015 | 163 | igcase_opt = asBool2(CAR(args), call); args = CDR(args); |
3016 | 163 | perl_opt = asBool2(CAR(args), call); args = CDR(args); |
3017 | 163 | fixed_opt = asBool2(CAR(args), call); args = CDR(args); |
3018 | 163 | useBytes = asBool2(CAR(args), call); args = CDR(args); |
3019 | 163 | if (fixed_opt && igcase_opt) |
3020 | 0 | warning(_("argument '%s' will be ignored"), "ignore.case = TRUE"); |
3021 | 163 | if (fixed_opt && perl_opt) { |
3022 | 0 | warning(_("argument '%s' will be ignored"), "perl = TRUE"); |
3023 | 0 | perl_opt = 0; |
3024 | 0 | } |
3025 | | |
3026 | | /* Note that excluding NAs differs from grep/sub */ |
3027 | 163 | if (!isString(pat) || LENGTH(pat) < 1 || STRING_ELT(pat, 0) == NA_STRING) |
3028 | 0 | error(_("invalid '%s' argument"), "pattern"); |
3029 | 163 | if (LENGTH(pat) > 1) |
3030 | 0 | warning(_("argument '%s' has length > 1 and only the first element will be used"), "pattern"); |
3031 | | |
3032 | 163 | if (!isString(text)) |
3033 | 0 | error(_("invalid '%s' argument"), "text"); |
3034 | | |
3035 | 163 | n = XLENGTH(text); |
3036 | 163 | if (!useBytes) |
3037 | 163 | useBytes = have_bytes(pat, 1) || have_bytes(text, n); |
3038 | 163 | PROTECT(itype = ScalarString(mkChar(useBytes ? "bytes" : "chars"))); |
3039 | | |
3040 | 163 | if (!useBytes) |
3041 | 163 | useBytes = only_ascii(pat, 1) && only_ascii(text, n); |
3042 | 163 | if (!useBytes) { |
3043 | | /* As from R 2.10.0 we use UTF-8 mode in PCRE in all MBCS locales, |
3044 | | and as from 2.11.0 in TRE too. */ |
3045 | | /* if we have non-ASCII text in a DBCS locale, we need to use wchar in TRE */ |
3046 | 0 | if (!fixed_opt && mbcslocale) use_UTF8 = true; |
3047 | 0 | if (!use_UTF8) |
3048 | 0 | use_UTF8 = have_utf8(pat, 1) || have_utf8(text, n); |
3049 | 0 | if (!use_UTF8 && !latin1locale) |
3050 | 0 | use_UTF8 = have_latin1(pat, 1) || have_latin1(text, n); |
3051 | 0 | } |
3052 | | |
3053 | 163 | if (!fixed_opt && !perl_opt) { |
3054 | 0 | use_WC = use_UTF8; use_UTF8 = false; |
3055 | 0 | } |
3056 | | |
3057 | 163 | if (useBytes) |
3058 | 163 | spat = CHAR(STRING_ELT(pat, 0)); |
3059 | 0 | else if (use_WC) { |
3060 | 0 | wpat = wtransChar2(STRING_ELT(pat, 0)); |
3061 | 0 | if (!wpat) error(_("regular expression is invalid")); |
3062 | 0 | } else if (use_UTF8) { |
3063 | 0 | spat = trCharUTF82(STRING_ELT(pat, 0)); |
3064 | 0 | if (!spat || !utf8Valid(spat)) error(_("regular expression is invalid UTF-8")); |
3065 | 0 | } else { |
3066 | 0 | spat = translateCharFP2(STRING_ELT(pat, 0)); |
3067 | 0 | if (!spat || (mbcslocale && !mbcsValid(spat))) |
3068 | 0 | error(_("regular expression is invalid in this locale")); |
3069 | 0 | } |
3070 | | |
3071 | 163 | if (fixed_opt) ; |
3072 | 0 | else if (perl_opt) { |
3073 | 0 | #ifdef HAVE_PCRE2 |
3074 | 0 | R_pcre2_prepare(spat, text, use_UTF8, igcase_opt, &tables, &re, |
3075 | 0 | &mcontext); |
3076 | | |
3077 | | /* also extract info for named groups */ |
3078 | 0 | pcre2_pattern_info(re, PCRE2_INFO_NAMECOUNT, &name_count); |
3079 | 0 | pcre2_pattern_info(re, PCRE2_INFO_NAMEENTRYSIZE, &name_entry_size); |
3080 | 0 | pcre2_pattern_info(re, PCRE2_INFO_NAMETABLE, (PCRE2_SPTR**) &name_table); |
3081 | 0 | info_code = |
3082 | 0 | pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &capture_count); |
3083 | 0 | if(info_code < 0) |
3084 | | /* this should not happen, but */ |
3085 | 0 | error(_("'pcre2_patterninfo' returned '%d' "), info_code); |
3086 | 0 | ovector_size = (int) capture_count + 1; |
3087 | | /* PCRE2 also has pcre2_match_data_create_from_pattern() */ |
3088 | 0 | mdata = pcre2_match_data_create(ovector_size, NULL); |
3089 | | /* ovector_size not used below */ |
3090 | | #else |
3091 | | R_pcre_prepare(spat, text, use_UTF8, igcase_opt, false, &tables, |
3092 | | &re_pcre, &re_pe); |
3093 | | |
3094 | | /* also extract info for named groups */ |
3095 | | pcre_fullinfo(re_pcre, re_pe, PCRE_INFO_NAMECOUNT, &name_count); |
3096 | | pcre_fullinfo(re_pcre, re_pe, PCRE_INFO_NAMEENTRYSIZE, &name_entry_size); |
3097 | | pcre_fullinfo(re_pcre, re_pe, PCRE_INFO_NAMETABLE, &name_table); |
3098 | | info_code = |
3099 | | pcre_fullinfo(re_pcre, re_pe, PCRE_INFO_CAPTURECOUNT, |
3100 | | &capture_count); |
3101 | | if(info_code < 0) |
3102 | | error(_("'pcre_fullinfo' returned '%d' "), info_code); |
3103 | | ovector_size = (capture_count + 1) * 3; |
3104 | | ovector = (int *) malloc(ovector_size*sizeof(int)); |
3105 | | #endif |
3106 | 0 | SEXP thisname; |
3107 | 0 | PROTECT(capture_names = allocVector(STRSXP, (int) capture_count)); |
3108 | 0 | for(i = 0; i < name_count; i++) { |
3109 | 0 | char *entry = name_table + name_entry_size * i; |
3110 | 0 | PROTECT(thisname = mkChar(entry + 2)); |
3111 | 0 | int capture_num = ((unsigned char)entry[0]<<8) |
3112 | 0 | + (unsigned char)entry[1] - 1; |
3113 | 0 | SET_STRING_ELT(capture_names, capture_num, thisname); |
3114 | 0 | UNPROTECT(1); |
3115 | 0 | } |
3116 | 0 | } else { |
3117 | 0 | int rc, cflags = REG_EXTENDED; |
3118 | 0 | if (igcase_opt) cflags |= REG_ICASE; |
3119 | 0 | if (!use_WC) |
3120 | 0 | rc = tre_regcompb(®, spat, cflags); |
3121 | 0 | else |
3122 | 0 | rc = tre_regwcomp(®, wpat, cflags); |
3123 | 0 | if (rc) reg_report(rc, ®, spat); |
3124 | 0 | } |
3125 | | |
3126 | 163 | if (PRIMVAL(op) == 0) { /* regexpr */ |
3127 | 163 | SEXP matchlen, capture_start, capturelen; |
3128 | 163 | int *is, *il; |
3129 | 163 | PROTECT(ans = allocVector(INTSXP, n)); |
3130 | | /* Protect in case install("match.length") allocates */ |
3131 | 163 | PROTECT(matchlen = allocVector(INTSXP, n)); |
3132 | 163 | setAttrib(ans, install("match.length"), matchlen); |
3133 | 163 | if(useBytes) { |
3134 | 163 | setAttrib(ans, install("index.type"), itype); |
3135 | 163 | setAttrib(ans, install("useBytes"), R_TrueValue); |
3136 | 163 | } |
3137 | 163 | UNPROTECT(1); |
3138 | 163 | if (perl_opt && capture_count) { |
3139 | 0 | if (n > INT_MAX) error("too long a vector"); |
3140 | 0 | int nn = (int) n; |
3141 | 0 | SEXP dmn; |
3142 | 0 | PROTECT(dmn = allocVector(VECSXP, 2)); |
3143 | 0 | SET_VECTOR_ELT(dmn, 1, capture_names); |
3144 | 0 | PROTECT(capture_start = allocMatrix(INTSXP, nn, (int) capture_count)); |
3145 | 0 | setAttrib(capture_start, R_DimNamesSymbol, dmn); |
3146 | 0 | setAttrib(ans, install("capture.start"), capture_start); |
3147 | 0 | PROTECT(capturelen = allocMatrix(INTSXP, nn, (int) capture_count)); |
3148 | 0 | setAttrib(capturelen, R_DimNamesSymbol, dmn); |
3149 | 0 | setAttrib(ans, install("capture.length"), capturelen); |
3150 | 0 | setAttrib(ans, install("capture.names"), capture_names); |
3151 | 0 | UNPROTECT(3); |
3152 | 0 | is = INTEGER(capture_start); |
3153 | 0 | il = INTEGER(capturelen); |
3154 | | // initiialization needed for NA inputs: PR#16484 |
3155 | 0 | for (i = 0 ; i < n * (int) capture_count ; i++) |
3156 | 0 | is[i] = il[i] = NA_INTEGER; |
3157 | 163 | } else is = il = INTEGER(ans); // not actually used, but is + i has to be legal |
3158 | 163 | vmax = vmaxget(); |
3159 | 6.00k | for (i = 0 ; i < n ; i++) { |
3160 | | // if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt(); |
3161 | 5.84k | if (STRING_ELT(text, i) == NA_STRING) { |
3162 | 0 | INTEGER(matchlen)[i] = INTEGER(ans)[i] = NA_INTEGER; |
3163 | 5.84k | } else { |
3164 | 5.84k | if (useBytes) |
3165 | 5.84k | s = CHAR(STRING_ELT(text, i)); |
3166 | 0 | else if (use_WC) { |
3167 | 0 | ws = wtransChar2(STRING_ELT(text, i)); |
3168 | 0 | if (!ws) { |
3169 | 0 | if(nwarn++ < NWARN) |
3170 | 0 | warning(_("input string %lld is invalid"), |
3171 | 0 | (long long)i+1); |
3172 | 0 | INTEGER(ans)[i] = INTEGER(matchlen)[i] = -1; |
3173 | 0 | continue; |
3174 | 0 | } |
3175 | 0 | } else if (use_UTF8) { |
3176 | 0 | s = trCharUTF82(STRING_ELT(text, i)); |
3177 | 0 | if (!s || !utf8Valid(s)) { |
3178 | 0 | if(nwarn++ < NWARN) |
3179 | 0 | warning(_("input string %lld is invalid UTF-8"), |
3180 | 0 | (long long)i+1); |
3181 | 0 | INTEGER(ans)[i] = INTEGER(matchlen)[i] = -1; |
3182 | 0 | continue; |
3183 | 0 | } |
3184 | 0 | } else { |
3185 | 0 | s = translateCharFP2(STRING_ELT(text, i)); |
3186 | 0 | if (!s || (mbcslocale && !mbcsValid(s))) { |
3187 | 0 | if(nwarn++ < NWARN) |
3188 | 0 | warning(_("input string %lld is invalid in this locale"), |
3189 | 0 | (long long)i+1); |
3190 | 0 | INTEGER(ans)[i] = INTEGER(matchlen)[i] = -1; |
3191 | 0 | continue; |
3192 | 0 | } |
3193 | 0 | } |
3194 | 5.84k | if (fixed_opt) { |
3195 | 5.84k | int st = fgrep_one(spat, s, useBytes, use_UTF8, NULL); |
3196 | 5.84k | INTEGER(ans)[i] = (st > -1)?(st+1):-1; |
3197 | 5.84k | if (!useBytes && use_UTF8) { |
3198 | 0 | INTEGER(matchlen)[i] = INTEGER(ans)[i] >= 0 ? |
3199 | 0 | (int) utf8towcs(NULL, spat, 0):-1; |
3200 | 5.84k | } else if (!useBytes && mbcslocale) { |
3201 | 0 | INTEGER(matchlen)[i] = INTEGER(ans)[i] >= 0 ? |
3202 | 0 | (int) mbstowcs(NULL, spat, 0):-1; |
3203 | 0 | } else |
3204 | 5.84k | INTEGER(matchlen)[i] = INTEGER(ans)[i] >= 0 ? |
3205 | 5.84k | (int) strlen(spat):-1; |
3206 | 5.84k | } else if (perl_opt) { |
3207 | 0 | int rc; |
3208 | 0 | #ifdef HAVE_PCRE2 |
3209 | 0 | uint32_t eflag = 0; |
3210 | 0 | if (use_UTF8) eflag |= PCRE2_NO_UTF_CHECK; |
3211 | 0 | rc = pcre2_match(re, (PCRE2_SPTR) s, PCRE2_ZERO_TERMINATED, |
3212 | 0 | 0, eflag, mdata, mcontext); |
3213 | 0 | ovector = pcre2_get_ovector_pointer(mdata); |
3214 | | #else |
3215 | | rc = pcre_exec(re_pcre, re_pe, s, (int) strlen(s), 0, 0, |
3216 | | ovector, ovector_size); |
3217 | | #endif |
3218 | 0 | R_pcre_exec_error(rc, i); |
3219 | 0 | if (rc >= 0) { |
3220 | 0 | extract_match_and_groups(use_UTF8, ovector, |
3221 | 0 | (int) capture_count, |
3222 | | // don't use this for large i |
3223 | 0 | INTEGER(ans) + i, |
3224 | 0 | INTEGER(matchlen) + i, |
3225 | 0 | is + i, il + i, |
3226 | 0 | s, (int) n); |
3227 | 0 | } else { |
3228 | 0 | INTEGER(ans)[i] = INTEGER(matchlen)[i] = -1; |
3229 | 0 | for(int cn = 0; cn < (int) capture_count; cn++) { |
3230 | 0 | R_xlen_t ind = i + cn*n; |
3231 | 0 | is[ind] = il[ind] = -1; |
3232 | 0 | } |
3233 | 0 | } |
3234 | 0 | } else { |
3235 | 0 | int rc; |
3236 | 0 | if (!use_WC) |
3237 | 0 | rc = tre_regexecb(®, s, 1, regmatch, 0); |
3238 | 0 | else |
3239 | 0 | rc = tre_regwexec(®, ws, 1, regmatch, 0); |
3240 | 0 | if (rc == 0) { |
3241 | 0 | int st = regmatch[0].rm_so; |
3242 | 0 | INTEGER(ans)[i] = st + 1; /* index from one */ |
3243 | 0 | INTEGER(matchlen)[i] = regmatch[0].rm_eo - st; |
3244 | 0 | } else INTEGER(ans)[i] = INTEGER(matchlen)[i] = -1; |
3245 | | // AFAICS the only possible error report is REG_ESPACE |
3246 | 0 | if (rc == REG_ESPACE) |
3247 | 0 | warning("Out-of-memory error in regexp matching for element %d", |
3248 | 0 | (int) i + 1); |
3249 | 0 | } |
3250 | 5.84k | } |
3251 | 5.84k | vmaxset(vmax); |
3252 | 5.84k | } |
3253 | 163 | } else { |
3254 | 0 | SEXP elt; |
3255 | 0 | PROTECT(ans = allocVector(VECSXP, n)); |
3256 | 0 | vmax = vmaxget(); |
3257 | 0 | for (i = 0 ; i < n ; i++) { |
3258 | | // if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt(); |
3259 | 0 | if (STRING_ELT(text, i) == NA_STRING) { |
3260 | 0 | elt = gregexpr_NAInputAns(); |
3261 | 0 | } else { |
3262 | 0 | if (fixed_opt || perl_opt) { |
3263 | 0 | if (useBytes) |
3264 | 0 | s = CHAR(STRING_ELT(text, i)); |
3265 | 0 | else if (use_UTF8) { |
3266 | 0 | s = trCharUTF82(STRING_ELT(text, i)); |
3267 | 0 | if (!s || !utf8Valid(s)) { |
3268 | 0 | if (nwarn++ < NWARN) |
3269 | 0 | warning(_("input string %lld is invalid UTF-8"), |
3270 | 0 | (long long)i+1); |
3271 | 0 | s = NULL; |
3272 | 0 | } |
3273 | 0 | } else { |
3274 | 0 | s = translateCharFP2(STRING_ELT(text, i)); |
3275 | 0 | if (!s || (mbcslocale && !mbcsValid(s))) { |
3276 | 0 | if (nwarn++ < NWARN) |
3277 | 0 | warning(_("input string %lld is invalid in this locale"), |
3278 | 0 | (long long)i+1); |
3279 | 0 | s = NULL; |
3280 | 0 | } |
3281 | 0 | } |
3282 | 0 | if (!useBytes && !s) { |
3283 | 0 | elt = gregexpr_BadStringAns(); |
3284 | 0 | } else { |
3285 | 0 | if (fixed_opt) |
3286 | 0 | elt = gregexpr_fixed(spat, s, useBytes, use_UTF8, |
3287 | 0 | itype); |
3288 | 0 | else |
3289 | 0 | #ifdef HAVE_PCRE2 |
3290 | 0 | elt = R_pcre2_gregexpr(spat, s, re, useBytes, |
3291 | 0 | use_UTF8, mdata, mcontext, |
3292 | 0 | (int) capture_count, |
3293 | 0 | capture_names, i, itype); |
3294 | | #else |
3295 | | elt = R_pcre_gregexpr(spat, s, re_pcre, re_pe, |
3296 | | useBytes, use_UTF8, ovector, |
3297 | | ovector_size, |
3298 | | (int) capture_count, |
3299 | | capture_names, i, itype); |
3300 | | #endif |
3301 | 0 | } |
3302 | 0 | } else |
3303 | 0 | elt = gregexpr_Regexc(®, STRING_ELT(text, i), |
3304 | 0 | useBytes, use_WC, i, itype, &nwarn); |
3305 | 0 | } |
3306 | 0 | SET_VECTOR_ELT(ans, i, elt); |
3307 | 0 | vmaxset(vmax); |
3308 | 0 | } |
3309 | 0 | } |
3310 | | |
3311 | 163 | if (fixed_opt) ; |
3312 | 0 | else if (perl_opt) { |
3313 | 0 | #ifdef HAVE_PCRE2 |
3314 | 0 | pcre2_match_data_free(mdata); |
3315 | 0 | pcre2_code_free(re); |
3316 | 0 | pcre2_match_context_free(mcontext); |
3317 | 0 | if (tables) |
3318 | | /* new PCRE2 will have pcre2_maketables_free() */ |
3319 | 0 | free((void *)tables); |
3320 | | #else |
3321 | | if (re_pe) pcre_free_study(re_pe); |
3322 | | pcre_free(re_pcre); |
3323 | | pcre_free((void *)tables); |
3324 | | free(ovector); |
3325 | | #endif |
3326 | 0 | UNPROTECT(1); |
3327 | 0 | } else |
3328 | 0 | tre_regfree(®); |
3329 | | |
3330 | 163 | UNPROTECT(2); |
3331 | 163 | return ans; |
3332 | 163 | } |
3333 | | |
3334 | | // .Internal(regexec(pattern, text, ignore.case, fixed, useBytes)) : |
3335 | | attribute_hidden SEXP do_regexec(SEXP call, SEXP op, SEXP args, SEXP env) |
3336 | 0 | { |
3337 | 0 | SEXP pat, text, ans, matchpos, matchlen, itype; |
3338 | 0 | int opt_icase, opt_fixed, useBytes; |
3339 | |
|
3340 | 0 | bool use_WC = false; |
3341 | 0 | const char *s, *t; |
3342 | 0 | const wchar_t *ws, *wt; |
3343 | 0 | const void *vmax = NULL; |
3344 | |
|
3345 | 0 | regex_t reg; |
3346 | 0 | size_t nmatch; |
3347 | 0 | regmatch_t *pmatch; |
3348 | 0 | R_xlen_t i, n; |
3349 | 0 | int j, so; |
3350 | 0 | int rc, cflags = REG_EXTENDED; |
3351 | |
|
3352 | 0 | checkArity(op, args); |
3353 | |
|
3354 | 0 | pat = CAR(args); args = CDR(args); |
3355 | 0 | text = CAR(args); args = CDR(args); |
3356 | 0 | opt_icase = asLogical(CAR(args)); args = CDR(args); |
3357 | 0 | opt_fixed = asLogical(CAR(args)); args = CDR(args); |
3358 | 0 | useBytes = asLogical(CAR(args)); |
3359 | |
|
3360 | 0 | if(opt_icase == NA_INTEGER) opt_icase = 0; |
3361 | 0 | if(opt_fixed == NA_INTEGER) opt_fixed = 0; |
3362 | 0 | if(useBytes == NA_INTEGER) useBytes = 0; |
3363 | 0 | if(opt_fixed && opt_icase) { |
3364 | 0 | warning(_("argument '%s' will be ignored"), |
3365 | 0 | "ignore.case = TRUE"); |
3366 | 0 | opt_icase = 0; |
3367 | 0 | } |
3368 | 0 | if(opt_fixed) cflags |= REG_LITERAL; |
3369 | 0 | if(opt_icase) cflags |= REG_ICASE; |
3370 | |
|
3371 | 0 | if(!isString(pat) || |
3372 | 0 | (LENGTH(pat) < 1) || |
3373 | 0 | (STRING_ELT(pat, 0) == NA_STRING)) |
3374 | 0 | error(_("invalid '%s' argument"), "pattern"); |
3375 | 0 | if(LENGTH(pat) > 1) |
3376 | 0 | warning(_("argument '%s' has length > 1 and only the first element will be used"), "pattern"); |
3377 | |
|
3378 | 0 | if(!isString(text)) |
3379 | 0 | error(_("invalid '%s' argument"), "text"); |
3380 | |
|
3381 | 0 | n = XLENGTH(text); |
3382 | |
|
3383 | 0 | if(!useBytes) |
3384 | 0 | useBytes = have_bytes(pat, 1) || have_bytes(text, n); |
3385 | 0 | PROTECT(itype = ScalarString(mkChar(useBytes ? "bytes" : "chars"))); |
3386 | |
|
3387 | 0 | if(!useBytes) |
3388 | 0 | useBytes = only_ascii(pat, 1) && only_ascii(text, n); |
3389 | |
|
3390 | 0 | if(!useBytes) { |
3391 | 0 | if (!opt_fixed && mbcslocale) use_WC = true; |
3392 | 0 | if (!use_WC) |
3393 | 0 | use_WC = have_utf8(pat, 1) || have_utf8(text, n); |
3394 | 0 | if (!use_WC && !latin1locale) |
3395 | 0 | use_WC = have_latin1(pat, 1) || have_latin1(text, n); |
3396 | 0 | } |
3397 | |
|
3398 | 0 | if(useBytes) |
3399 | 0 | rc = tre_regcompb(®, CHAR(STRING_ELT(pat, 0)), cflags); |
3400 | 0 | else if (use_WC) { |
3401 | 0 | ws = wtransChar2(STRING_ELT(pat, 0)); |
3402 | 0 | if(!ws) |
3403 | 0 | error(_("regular expression is invalid")); |
3404 | 0 | rc = tre_regwcomp(®, ws, cflags); |
3405 | 0 | } else { |
3406 | 0 | s = translateCharFP2(STRING_ELT(pat, 0)); |
3407 | 0 | if(!s || (mbcslocale && !mbcsValid(s))) |
3408 | 0 | error(_("regular expression is invalid in this locale")); |
3409 | 0 | rc = tre_regcomp(®, s, cflags); |
3410 | 0 | } |
3411 | 0 | if(rc) { |
3412 | 0 | char errbuf[1001]; |
3413 | 0 | tre_regerror(rc, ®, errbuf, 1001); |
3414 | 0 | error(_("regcomp error: '%s'"), errbuf); |
3415 | 0 | } |
3416 | |
|
3417 | 0 | nmatch = reg.re_nsub + 1; |
3418 | |
|
3419 | 0 | pmatch = (regmatch_t *) malloc(nmatch * sizeof(regmatch_t)); |
3420 | |
|
3421 | 0 | PROTECT(ans = allocVector(VECSXP, n)); |
3422 | |
|
3423 | 0 | for(i = 0; i < n; i++) { |
3424 | | // if ((i+1) % NINTERRUPT == 0) R_CheckUserInterrupt(); |
3425 | 0 | if(STRING_ELT(text, i) == NA_STRING) { |
3426 | 0 | PROTECT(matchpos = ScalarInteger(NA_INTEGER)); |
3427 | 0 | SEXP s_match_length = install("match.length"); |
3428 | 0 | setAttrib(matchpos, s_match_length , |
3429 | 0 | ScalarInteger(NA_INTEGER)); |
3430 | 0 | SET_VECTOR_ELT(ans, i, matchpos); |
3431 | 0 | UNPROTECT(1); |
3432 | 0 | } else { |
3433 | 0 | vmax = vmaxget(); |
3434 | 0 | if(useBytes) |
3435 | 0 | rc = tre_regexecb(®, CHAR(STRING_ELT(text, i)), |
3436 | 0 | nmatch, pmatch, 0); |
3437 | 0 | else if(use_WC) { |
3438 | 0 | wt = wtransChar2(STRING_ELT(text, i)); |
3439 | 0 | if (!wt) { |
3440 | 0 | free(pmatch); |
3441 | 0 | tre_regfree(®); |
3442 | 0 | error(_("input string %lld is invalid in this locale"), |
3443 | 0 | (long long)i + 1); |
3444 | 0 | } |
3445 | 0 | rc = tre_regwexec(®, wt, nmatch, pmatch, 0); |
3446 | 0 | vmaxset(vmax); |
3447 | 0 | } else { |
3448 | 0 | t = translateCharFP2(STRING_ELT(text, i)); |
3449 | 0 | if (!t || (mbcslocale && !mbcsValid(t))) { |
3450 | 0 | free(pmatch); |
3451 | 0 | tre_regfree(®); |
3452 | 0 | error(_("input string %lld is invalid in this locale"), |
3453 | 0 | (long long)i + 1); |
3454 | 0 | } |
3455 | 0 | rc = tre_regexec(®, t, |
3456 | 0 | nmatch, pmatch, 0); |
3457 | 0 | vmaxset(vmax); |
3458 | 0 | } |
3459 | 0 | if(rc == REG_OK) { |
3460 | 0 | PROTECT(matchpos = allocVector(INTSXP, nmatch)); |
3461 | 0 | PROTECT(matchlen = allocVector(INTSXP, nmatch)); |
3462 | 0 | for(j = 0; j < nmatch; j++) { |
3463 | 0 | so = pmatch[j].rm_so; |
3464 | 0 | INTEGER(matchpos)[j] = so + 1; |
3465 | 0 | INTEGER(matchlen)[j] = pmatch[j].rm_eo - so; |
3466 | 0 | } |
3467 | 0 | setAttrib(matchpos, install("match.length"), matchlen); |
3468 | 0 | if(useBytes) { |
3469 | 0 | setAttrib(matchpos, install("index.type"), itype); |
3470 | 0 | setAttrib(matchpos, install("useBytes"), R_TrueValue); |
3471 | 0 | } |
3472 | 0 | SET_VECTOR_ELT(ans, i, matchpos); |
3473 | 0 | UNPROTECT(2); |
3474 | 0 | } else { |
3475 | | /* No match (or could there be an error?). */ |
3476 | | /* Alternatively, could return nmatch -1 values. |
3477 | | */ |
3478 | | // AFAICS the only possible error report is REG_ESPACE |
3479 | 0 | if (rc == REG_ESPACE) |
3480 | 0 | warning("Out-of-memory error in regexp matching for element %d", |
3481 | 0 | (int) i + 1); |
3482 | 0 | PROTECT(matchpos = ScalarInteger(-1)); |
3483 | 0 | PROTECT(matchlen = ScalarInteger(-1)); |
3484 | 0 | setAttrib(matchpos, install("match.length"), matchlen); |
3485 | 0 | if(useBytes) { |
3486 | 0 | setAttrib(matchpos, install("index.type"), itype); |
3487 | 0 | setAttrib(matchpos, install("useBytes"), R_TrueValue); |
3488 | 0 | } |
3489 | 0 | SET_VECTOR_ELT(ans, i, matchpos); |
3490 | 0 | UNPROTECT(2); |
3491 | 0 | } |
3492 | 0 | } |
3493 | 0 | } |
3494 | |
|
3495 | 0 | free(pmatch); |
3496 | |
|
3497 | 0 | tre_regfree(®); |
3498 | |
|
3499 | 0 | UNPROTECT(2); |
3500 | |
|
3501 | 0 | return ans; |
3502 | 0 | } |
3503 | | |
3504 | | /* pcre_config was added in PCRE 4.0, with PCRE_CONFIG_UTF8 . |
3505 | | PCRE_CONFIG_UNICODE_PROPERTIES had been added by 8.10, |
3506 | | the earliest version we allowed when coding this. |
3507 | | */ |
3508 | | #ifdef HAVE_PCRE2 |
3509 | | attribute_hidden SEXP do_pcre_config(SEXP call, SEXP op, SEXP args, SEXP env) |
3510 | 0 | { |
3511 | 0 | uint32_t res; |
3512 | |
|
3513 | 0 | checkArity(op, args); |
3514 | 0 | SEXP ans = PROTECT(allocVector(LGLSXP, 4)); |
3515 | 0 | int *lans = LOGICAL(ans); |
3516 | 0 | SEXP nm = allocVector(STRSXP, 4); |
3517 | 0 | setAttrib(ans, R_NamesSymbol, nm); |
3518 | 0 | SET_STRING_ELT(nm, 0, mkChar("UTF-8")); |
3519 | 0 | pcre2_config(PCRE2_CONFIG_UNICODE, &res); |
3520 | 0 | lans[0] = res; |
3521 | 0 | SET_STRING_ELT(nm, 1, mkChar("Unicode properties")); |
3522 | 0 | lans[1] = res; |
3523 | 0 | SET_STRING_ELT(nm, 2, mkChar("JIT")); |
3524 | 0 | pcre2_config(PCRE2_CONFIG_JIT, &res); |
3525 | 0 | lans[2] = res; |
3526 | 0 | pcre2_config(PCRE2_CONFIG_STACKRECURSE, &res); |
3527 | 0 | lans[3] = res; |
3528 | 0 | SET_STRING_ELT(nm, 3, mkChar("stack")); |
3529 | 0 | UNPROTECT(1); |
3530 | 0 | return ans; |
3531 | 0 | } |
3532 | | #else |
3533 | | attribute_hidden SEXP do_pcre_config(SEXP call, SEXP op, SEXP args, SEXP env) |
3534 | | { |
3535 | | int res; |
3536 | | |
3537 | | checkArity(op, args); |
3538 | | SEXP ans = PROTECT(allocVector(LGLSXP, 4)); |
3539 | | int *lans = LOGICAL(ans); |
3540 | | SEXP nm = allocVector(STRSXP, 4); |
3541 | | setAttrib(ans, R_NamesSymbol, nm); |
3542 | | SET_STRING_ELT(nm, 0, mkChar("UTF-8")); |
3543 | | pcre_config(PCRE_CONFIG_UTF8, &res); lans[0] = res; |
3544 | | SET_STRING_ELT(nm, 1, mkChar("Unicode properties")); |
3545 | | pcre_config(PCRE_CONFIG_UNICODE_PROPERTIES, &res); lans[1] = res; |
3546 | | SET_STRING_ELT(nm, 2, mkChar("JIT")); |
3547 | | #ifdef PCRE_CONFIG_JIT |
3548 | | // added (and JIT support) in 8.20. |
3549 | | pcre_config(PCRE_CONFIG_JIT, &res); |
3550 | | #else |
3551 | | res = false; |
3552 | | #endif |
3553 | | lans[2] = res; |
3554 | | pcre_config(PCRE_CONFIG_STACKRECURSE, &res); lans[3] = res; |
3555 | | SET_STRING_ELT(nm, 3, mkChar("stack")); |
3556 | | UNPROTECT(1); |
3557 | | return ans; |
3558 | | } |
3559 | | #endif |