Coverage Report

Created: 2026-10-16 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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(&reg, wsplit, cflags)))
958
0
    reg_report(rc, &reg, 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(&reg, 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(&reg, 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(&reg);
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(&reg, split, cflags);
1043
280
      else
1044
280
    rc = tre_regcomp(&reg, split, cflags);
1045
1046
1.54k
      if(rc) reg_report(rc, &reg, 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(&reg, 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(&reg, 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(&reg, bufp, 1, regmatch, 0);
1103
52.5k
        else rc = tre_regexec(&reg, 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(&reg);
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(&reg, spat, cflags);
1371
0
  else
1372
0
      rc = tre_regwcomp(&reg, wpat, cflags);
1373
159k
  if (rc) reg_report(rc, &reg, 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(&reg, s, 0, NULL, 0);
1433
0
    else
1434
0
        rc = tre_regwexec(&reg, 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(&reg);
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(&reg, (const char*) RAW(pat), LENGTH(pat), cflags);
1743
0
    if (rc) reg_report(rc, &reg, 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(&reg, (const char*) RAW(text) + offset, LENGTH(text) - offset, 1, &ptag, 0);
1748
0
  tre_regfree(&reg);
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(&reg, (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(&reg, (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(&reg);
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, &reg, tables, re, mdata, mcontext)
2129
#else
2130
# define GSUB_FREE_PATTERN() \
2131
    gsub_free_pattern(fixed_opt, perl_opt, &reg, 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(&reg, spat, cflags);
2267
53.3k
      if (rc) reg_report(rc, &reg, spat);
2268
53.3k
      replen = strlen(srep);
2269
53.3k
  } else {
2270
1.83k
      rc  = tre_regwcomp(&reg, wpat, cflags);
2271
1.83k
      if (rc) reg_report(rc, &reg, 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(&reg, 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(&reg, 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(&reg, spat, cflags);
3121
0
  else
3122
0
      rc = tre_regwcomp(&reg, wpat, cflags);
3123
0
  if (rc) reg_report(rc, &reg, 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(&reg, s, 1, regmatch, 0);
3238
0
        else
3239
0
      rc = tre_regwexec(&reg, 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(&reg, 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(&reg);
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(&reg, 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(&reg, 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(&reg, s, cflags);
3410
0
    }
3411
0
    if(rc) {
3412
0
  char errbuf[1001];
3413
0
  tre_regerror(rc, &reg, 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(&reg, 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(&reg);
3442
0
        error(_("input string %lld is invalid in this locale"),
3443
0
              (long long)i + 1);
3444
0
    }
3445
0
    rc = tre_regwexec(&reg, 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(&reg);
3452
0
        error(_("input string %lld is invalid in this locale"),
3453
0
        (long long)i + 1);
3454
0
    }
3455
0
    rc = tre_regexec(&reg, 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(&reg);
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