Coverage Report

Created: 2026-09-14 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/kwsys/RegularExpression.cxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
3
//
4
// Copyright (C) 1991 Texas Instruments Incorporated.
5
//
6
// Permission is granted to any individual or institution to use, copy, modify
7
// and distribute this software, provided that this complete copyright and
8
// permission notice is maintained, intact, in all copies and supporting
9
// documentation.
10
//
11
// Texas Instruments Incorporated provides this software "as is" without
12
// express or implied warranty.
13
//
14
//
15
// Created: MNF 06/13/89  Initial Design and Implementation
16
// Updated: LGO 08/09/89  Inherit from Generic
17
// Updated: MBN 09/07/89  Added conditional exception handling
18
// Updated: MBN 12/15/89  Sprinkled "const" qualifiers all over the place!
19
// Updated: DLS 03/22/91  New lite version
20
//
21
22
#include "kwsysPrivate.h"
23
#include KWSYS_HEADER(RegularExpression.hxx)
24
25
// Work-around CMake dependency scanning limitation.  This must
26
// duplicate the above list of headers.
27
#if 0
28
#  include "RegularExpression.hxx.in"
29
#endif
30
31
#include <cstdio>
32
#include <cstring>
33
34
namespace KWSYS_NAMESPACE {
35
36
// RegularExpression -- Copies the given regular expression.
37
RegularExpression::RegularExpression(RegularExpression const& rxp)
38
0
{
39
0
  if (!rxp.program) {
40
0
    this->program = nullptr;
41
0
    return;
42
0
  }
43
0
  int ind;
44
0
  this->progsize = rxp.progsize;            // Copy regular expression size
45
0
  this->program = new char[this->progsize]; // Allocate storage
46
0
  for (ind = this->progsize; ind-- != 0;)   // Copy regular expression
47
0
    this->program[ind] = rxp.program[ind];
48
  // Copy pointers into last successful "find" operation
49
0
  this->regmatch = rxp.regmatch;
50
0
  this->regmust = rxp.regmust; // Copy field
51
0
  if (rxp.regmust) {
52
0
    char* dum = rxp.program;
53
0
    ind = 0;
54
0
    while (dum != rxp.regmust) {
55
0
      ++dum;
56
0
      ++ind;
57
0
    }
58
0
    this->regmust = this->program + ind;
59
0
  }
60
0
  this->regstart = rxp.regstart; // Copy starting index
61
0
  this->reganch = rxp.reganch;   // Copy remaining private data
62
0
  this->regmlen = rxp.regmlen;   // Copy remaining private data
63
0
  this->regnpar = rxp.regnpar;
64
0
}
65
66
// operator= -- Copies the given regular expression.
67
RegularExpression& RegularExpression::operator=(RegularExpression const& rxp)
68
0
{
69
0
  if (this == &rxp) {
70
0
    return *this;
71
0
  }
72
0
  if (!rxp.program) {
73
0
    this->program = nullptr;
74
0
    return *this;
75
0
  }
76
0
  int ind;
77
0
  this->progsize = rxp.progsize; // Copy regular expression size
78
0
  delete[] this->program;
79
0
  this->program = new char[this->progsize]; // Allocate storage
80
0
  for (ind = this->progsize; ind-- != 0;)   // Copy regular expression
81
0
    this->program[ind] = rxp.program[ind];
82
  // Copy pointers into last successful "find" operation
83
0
  this->regmatch = rxp.regmatch;
84
0
  this->regmust = rxp.regmust; // Copy field
85
0
  if (rxp.regmust) {
86
0
    char* dum = rxp.program;
87
0
    ind = 0;
88
0
    while (dum != rxp.regmust) {
89
0
      ++dum;
90
0
      ++ind;
91
0
    }
92
0
    this->regmust = this->program + ind;
93
0
  }
94
0
  this->regstart = rxp.regstart; // Copy starting index
95
0
  this->reganch = rxp.reganch;   // Copy remaining private data
96
0
  this->regmlen = rxp.regmlen;   // Copy remaining private data
97
0
  this->regnpar = rxp.regnpar;
98
99
0
  return *this;
100
0
}
101
102
// operator== -- Returns true if two regular expressions have the same
103
// compiled program for pattern matching.
104
bool RegularExpression::operator==(RegularExpression const& rxp) const
105
0
{
106
0
  if (this != &rxp) {         // Same address?
107
0
    int ind = this->progsize; // Get regular expression size
108
0
    if (ind != rxp.progsize)  // If different size regexp
109
0
      return false;           // Return failure
110
0
    while (ind-- != 0)        // Else while still characters
111
0
      if (this->program[ind] != rxp.program[ind]) // If regexp are different
112
0
        return false;                             // Return failure
113
0
  }
114
0
  return true; // Else same, return success
115
0
}
116
117
// deep_equal -- Returns true if have the same compiled regular expressions
118
// and the same start and end pointers.
119
120
bool RegularExpression::deep_equal(RegularExpression const& rxp) const
121
0
{
122
0
  int ind = this->progsize;                     // Get regular expression size
123
0
  if (ind != rxp.progsize)                      // If different size regexp
124
0
    return false;                               // Return failure
125
0
  while (ind-- != 0)                            // Else while still characters
126
0
    if (this->program[ind] != rxp.program[ind]) // If regexp are different
127
0
      return false;                             // Return failure
128
  // Else if same start/end ptrs, return true
129
0
  return (this->regmatch.start() == rxp.regmatch.start() &&
130
0
          this->regmatch.end() == rxp.regmatch.end());
131
0
}
132
133
// The remaining code in this file is derived from the regular expression code
134
// whose copyright statement appears below.  It has been changed to work
135
// with the class concepts of C++ and COOL.
136
137
/*
138
 * compile and find
139
 *
140
 *      Copyright (c) 1986 by University of Toronto.
141
 *      Written by Henry Spencer.  Not derived from licensed software.
142
 *
143
 *      Permission is granted to anyone to use this software for any
144
 *      purpose on any computer system, and to redistribute it freely,
145
 *      subject to the following restrictions:
146
 *
147
 *      1. The author is not responsible for the consequences of use of
148
 *              this software, no matter how awful, even if they arise
149
 *              from defects in it.
150
 *
151
 *      2. The origin of this software must not be misrepresented, either
152
 *              by explicit claim or by omission.
153
 *
154
 *      3. Altered versions must be plainly marked as such, and must not
155
 *              be misrepresented as being the original software.
156
 *
157
 * Beware that some of this code is subtly aware of the way operator
158
 * precedence is structured in regular expressions.  Serious changes in
159
 * regular-expression syntax might require a total rethink.
160
 */
161
162
/*
163
 * The "internal use only" fields in regexp.h are present to pass info from
164
 * compile to execute that permits the execute phase to run lots faster on
165
 * simple cases.  They are:
166
 *
167
 * regstart     char that must begin a match; '\0' if none obvious
168
 * reganch      is the match anchored (at beginning-of-line only)?
169
 * regmust      string (pointer into program) that match must include, or
170
 * nullptr regmlen      length of regmust string
171
 *
172
 * Regstart and reganch permit very fast decisions on suitable starting points
173
 * for a match, cutting down the work a lot.  Regmust permits fast rejection
174
 * of lines that cannot possibly match.  The regmust tests are costly enough
175
 * that compile() supplies a regmust only if the r.e. contains something
176
 * potentially expensive (at present, the only such thing detected is * or +
177
 * at the start of the r.e., which can involve a lot of backup).  Regmlen is
178
 * supplied because the test in find() needs it and compile() is computing
179
 * it anyway.
180
 */
181
182
/*
183
 * Structure for regexp "program".  This is essentially a linear encoding
184
 * of a nondeterministic finite-state machine (aka syntax charts or
185
 * "railroad normal form" in parsing technology).  Each node is an opcode
186
 * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
187
 * all nodes except BRANCH implement concatenation; a "next" pointer with
188
 * a BRANCH on both ends of it is connecting two alternatives.  (Here we
189
 * have one of the subtle syntax dependencies:  an individual BRANCH (as
190
 * opposed to a collection of them) is never concatenated with anything
191
 * because of operator precedence.)  The operand of some types of node is
192
 * a literal string; for others, it is a node leading into a sub-FSM.  In
193
 * particular, the operand of a BRANCH node is the first node of the branch.
194
 * (NB this is *not* a tree structure:  the tail of the branch connects
195
 * to the thing following the set of BRANCHes.)  The opcodes are:
196
 */
197
198
// definition   number  opnd?   meaning
199
88.7k
#define END 0   // no   End of program.
200
3.63M
#define BOL 1   // no   Match "" at beginning of line.
201
2.29M
#define EOL 2   // no   Match "" at end of line.
202
1.90M
#define ANY 3   // no   Match any one character.
203
10.1M
#define ANYOF 4 // str  Match any character in this string.
204
#define ANYBUT                                                                \
205
505k
  5 // str  Match any character not in this
206
    // string.
207
#define BRANCH                                                                \
208
34.7M
  6               // node Match this alternative, or the
209
                  // next...
210
70.3M
#define BACK 7    // no   Match "", "next" ptr points backward.
211
21.2M
#define EXACTLY 8 // str  Match this string.
212
6.29M
#define NOTHING 9 // no   Match empty string.
213
#define STAR                                                                  \
214
11.5M
  10 // node Match this (simple) thing 0 or more
215
     // times.
216
#define PLUS                                                                  \
217
10.6M
  11 // node Match this (simple) thing 1 or more
218
     // times.
219
#define OPEN                                                                  \
220
51.7M
  20 // no   Mark this point in input as start of
221
     // #n.
222
// OPEN+1 is number 1, etc.
223
46.0M
#define CLOSE 52 // no   Analogous to OPEN.
224
225
/*
226
 * Opcode notes:
227
 *
228
 * BRANCH       The set of branches constituting a single choice are hooked
229
 *              together with their "next" pointers, since precedence prevents
230
 *              anything being concatenated to any individual branch.  The
231
 *              "next" pointer of the last BRANCH in a choice points to the
232
 *              thing following the whole choice.  This is also where the
233
 *              final "next" pointer of each individual branch points; each
234
 *              branch starts with the operand node of a BRANCH node.
235
 *
236
 * BACK         Normal "next" pointers all implicitly point forward; BACK
237
 *              exists to make loop structures possible.
238
 *
239
 * STAR,PLUS    '?', and complex '*' and '+', are implemented as circular
240
 *              BRANCH structures using BACK.  Simple cases (one character
241
 *              per match) are implemented with STAR and PLUS for speed
242
 *              and to minimize recursive plunges.
243
 *
244
 * OPEN,CLOSE   ...are numbered at compile time.
245
 */
246
247
/*
248
 * A node is one char of opcode followed by two chars of "next" pointer.
249
 * "Next" pointers are stored as two 8-bit pieces, high order first.  The
250
 * value is a positive offset from the opcode of the node containing it.
251
 * An operand, if any, simply follows the node.  (Note that much of the
252
 * code generation knows about this implicit relationship.)
253
 *
254
 * Using two bytes for the "next" pointer is vast overkill for most things,
255
 * but allows patterns to get big without disasters.
256
 */
257
258
183M
#define OP(p) (*(p))
259
70.3M
#define NEXT(p) (((*((p) + 1) & 0377) << 8) + (*((p) + 2) & 0377))
260
55.2M
#define OPERAND(p) ((p) + 3)
261
262
unsigned char const MAGIC = 0234;
263
/*
264
 * Utility definitions.
265
 */
266
267
114k
#define UCHARAT(p) (reinterpret_cast<const unsigned char*>(p))[0]
268
269
1.55M
#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
270
560k
#define META "^$.[()|?+*\\"
271
272
/*
273
 * Flags to be passed up and down.
274
 */
275
2.61M
#define HASWIDTH 01 // Known never to match null string.
276
664k
#define SIMPLE 02   // Simple enough to be STAR/PLUS operand.
277
426k
#define SPSTART 04  // Starts with * or +.
278
1.41M
#define WORST 0     // Worst case.
279
280
/////////////////////////////////////////////////////////////////////////
281
//
282
//  COMPILE AND ASSOCIATED FUNCTIONS
283
//
284
/////////////////////////////////////////////////////////////////////////
285
286
/*
287
 * Read only utility variables.
288
 */
289
static char regdummy;
290
static char* const regdummyptr = &regdummy;
291
292
/*
293
 * Utility class for RegularExpression::compile().
294
 */
295
class RegExpCompile
296
{
297
public:
298
  char const* regparse; // Input-scan pointer.
299
  int regnpar;          // () count.
300
  char* regcode;        // Code-emit pointer; regdummyptr = don't.
301
  long regsize;         // Code size.
302
303
  char* reg(int, int*);
304
  char* regbranch(int*);
305
  char* regpiece(int*);
306
  char* regatom(int*);
307
  char* regnode(char);
308
  void regc(char);
309
  void reginsert(char, char*);
310
  static void regtail(char*, char const*);
311
  static void regoptail(char*, char const*);
312
};
313
314
static char const* regnext(char const*);
315
static char* regnext(char*);
316
317
#ifdef STRCSPN
318
static int strcspn();
319
#endif
320
321
/*
322
 * We can't allocate space until we know how big the compiled form will be,
323
 * but we can't compile it (and thus know how big it is) until we've got a
324
 * place to put the code.  So we cheat:  we compile it twice, once with code
325
 * generation turned off and size counting turned on, and once "for real".
326
 * This also means that we don't allocate space until we are sure that the
327
 * thing really will compile successfully, and we never have to move the
328
 * code and thus invalidate pointers into it.  (Note that it has to be in
329
 * one piece because free() must be able to free it all.)
330
 *
331
 * Beware that the optimization-preparation code in here knows about some
332
 * of the structure of the compiled regexp.
333
 */
334
335
// compile -- compile a regular expression into internal code
336
// for later pattern matching.
337
338
bool RegularExpression::compile(char const* exp)
339
6.72k
{
340
6.72k
  char const* scan;
341
6.72k
  char const* longest;
342
6.72k
  int flags;
343
344
6.72k
  if (!exp) {
345
    // RAISE Error, SYM(RegularExpression), SYM(No_Expr),
346
0
    printf("RegularExpression::compile(): No expression supplied.\n");
347
0
    return false;
348
0
  }
349
350
  // First pass: determine size, legality.
351
6.72k
  RegExpCompile comp;
352
6.72k
  comp.regparse = exp;
353
6.72k
  comp.regnpar = 1;
354
6.72k
  comp.regsize = 0L;
355
6.72k
  comp.regcode = regdummyptr;
356
6.72k
  comp.regc(static_cast<char>(MAGIC));
357
6.72k
  if (!comp.reg(0, &flags)) {
358
509
    printf("RegularExpression::compile(): Error in compile.\n");
359
509
    return false;
360
509
  }
361
6.21k
  this->regmatch.clear();
362
363
  // Small enough for pointer-storage convention?
364
6.21k
  if (comp.regsize >= 65535L) {
365
    // RAISE Error, SYM(RegularExpression), SYM(Expr_Too_Big),
366
13
    printf("RegularExpression::compile(): Expression too big.\n");
367
13
    return false;
368
13
  }
369
370
  // Allocate space.
371
  // #ifndef _WIN32
372
6.20k
  delete[] this->program;
373
  // #endif
374
6.20k
  this->program = new char[comp.regsize];
375
6.20k
  this->progsize = static_cast<int>(comp.regsize);
376
6.20k
  this->regnpar = comp.regnpar;
377
378
6.20k
  if (!this->program) {
379
    // RAISE Error, SYM(RegularExpression), SYM(Out_Of_Memory),
380
0
    printf("RegularExpression::compile(): Out of memory.\n");
381
0
    return false;
382
0
  }
383
384
#ifdef __clang_analyzer__ /* Convince it that the program is initialized.  */
385
  memset(this->program, 0, comp.regsize);
386
#endif
387
388
  // Second pass: emit code.
389
6.20k
  comp.regparse = exp;
390
6.20k
  comp.regnpar = 1;
391
6.20k
  comp.regcode = this->program;
392
6.20k
  comp.regc(static_cast<char>(MAGIC));
393
6.20k
  comp.reg(0, &flags);
394
395
  // Dig out information for optimizations.
396
6.20k
  this->regstart = '\0'; // Worst-case defaults.
397
6.20k
  this->reganch = 0;
398
6.20k
  this->regmust = nullptr;
399
6.20k
  this->regmlen = 0;
400
6.20k
  scan = this->program + 1;       // First BRANCH.
401
6.20k
  if (OP(regnext(scan)) == END) { // Only one top-level choice.
402
3.63k
    scan = OPERAND(scan);
403
404
    // Starting-point info.
405
3.63k
    if (OP(scan) == EXACTLY)
406
479
      this->regstart = *OPERAND(scan);
407
3.15k
    else if (OP(scan) == BOL)
408
321
      this->reganch++;
409
410
    //
411
    // If there's something expensive in the r.e., find the longest
412
    // literal string that must appear and make it the regmust.  Resolve
413
    // ties in favor of later strings, since the regstart check works
414
    // with the beginning of the r.e. and avoiding duplication
415
    // strengthens checking.  Not a strong reason, but sufficient in the
416
    // absence of others.
417
    //
418
3.63k
    if (flags & SPSTART) {
419
1.33k
      longest = nullptr;
420
1.33k
      size_t len = 0;
421
82.4k
      for (; scan; scan = regnext(scan))
422
81.1k
        if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
423
2.39k
          longest = OPERAND(scan);
424
2.39k
          len = strlen(OPERAND(scan));
425
2.39k
        }
426
1.33k
      this->regmust = longest;
427
1.33k
      this->regmlen = len;
428
1.33k
    }
429
3.63k
  }
430
6.20k
  return true;
431
6.20k
}
432
433
/*
434
 - reg - regular expression, i.e. main body or parenthesized thing
435
 *
436
 * Caller must absorb opening parenthesis.
437
 *
438
 * Combining parenthesis handling with the base level of regular expression
439
 * is a trifle forced, but the need to tie the tails of the branches to what
440
 * follows makes it hard to avoid.
441
 */
442
char* RegExpCompile::reg(int paren, int* flagp)
443
67.0k
{
444
67.0k
  char* ret;
445
67.0k
  char* br;
446
67.0k
  char* ender;
447
67.0k
  int parno = 0;
448
67.0k
  int flags;
449
450
67.0k
  *flagp = HASWIDTH; // Tentatively.
451
452
  // Make an OPEN node, if parenthesized.
453
67.0k
  if (paren) {
454
54.1k
    if (regnpar >= RegularExpressionMatch::NSUBEXP) {
455
      // RAISE Error, SYM(RegularExpression), SYM(Too_Many_Parens),
456
10
      printf("RegularExpression::compile(): Too many parentheses.\n");
457
10
      return nullptr;
458
10
    }
459
54.1k
    parno = regnpar;
460
54.1k
    regnpar++;
461
54.1k
    ret = regnode(static_cast<char>(OPEN + parno));
462
54.1k
  } else
463
12.9k
    ret = nullptr;
464
465
  // Pick up the branches, linking them together.
466
67.0k
  br = regbranch(&flags);
467
67.0k
  if (!br)
468
975
    return (nullptr);
469
66.0k
  if (ret)
470
53.5k
    regtail(ret, br); // OPEN -> first.
471
12.5k
  else
472
12.5k
    ret = br;
473
66.0k
  if (!(flags & HASWIDTH))
474
13.5k
    *flagp &= ~HASWIDTH;
475
66.0k
  *flagp |= flags & SPSTART;
476
207k
  while (*regparse == '|') {
477
142k
    regparse++;
478
142k
    br = regbranch(&flags);
479
142k
    if (!br)
480
379
      return (nullptr);
481
141k
    regtail(ret, br); // BRANCH -> BRANCH.
482
141k
    if (!(flags & HASWIDTH))
483
105k
      *flagp &= ~HASWIDTH;
484
141k
    *flagp |= flags & SPSTART;
485
141k
  }
486
487
  // Make a closing node, and hook it on the end.
488
65.7k
  ender = regnode(static_cast<char>((paren) ? CLOSE + parno : END));
489
65.7k
  regtail(ret, ender);
490
491
  // Hook the tails of the branches to the closing node.
492
257k
  for (br = ret; br; br = regnext(br))
493
191k
    regoptail(br, ender);
494
495
  // Check for proper termination.
496
65.7k
  if (paren && *regparse++ != ')') {
497
    // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens),
498
169
    printf("RegularExpression::compile(): Unmatched parentheses.\n");
499
169
    return nullptr;
500
65.5k
  } else if (!paren && *regparse != '\0') {
501
51
    if (*regparse == ')') {
502
      // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens),
503
51
      printf("RegularExpression::compile(): Unmatched parentheses.\n");
504
51
      return nullptr;
505
51
    } else {
506
      // RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
507
0
      printf("RegularExpression::compile(): Internal error.\n");
508
0
      return nullptr;
509
0
    }
510
    // NOTREACHED
511
51
  }
512
65.4k
  return (ret);
513
65.7k
}
514
515
/*
516
 - regbranch - one alternative of an | operator
517
 *
518
 * Implements the concatenation operator.
519
 */
520
char* RegExpCompile::regbranch(int* flagp)
521
209k
{
522
209k
  char* ret;
523
209k
  char* chain;
524
209k
  char* latest;
525
209k
  int flags;
526
527
209k
  *flagp = WORST; // Tentatively.
528
529
209k
  ret = regnode(BRANCH);
530
209k
  chain = nullptr;
531
1.30M
  while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
532
1.09M
    latest = regpiece(&flags);
533
1.09M
    if (!latest)
534
1.35k
      return (nullptr);
535
1.09M
    *flagp |= flags & HASWIDTH;
536
1.09M
    if (!chain) // First piece.
537
93.6k
      *flagp |= flags & SPSTART;
538
1.00M
    else
539
1.00M
      regtail(chain, latest);
540
1.09M
    chain = latest;
541
1.09M
  }
542
207k
  if (!chain) // Loop ran zero times.
543
114k
    regnode(NOTHING);
544
545
207k
  return (ret);
546
209k
}
547
548
/*
549
 - regpiece - something followed by possible [*+?]
550
 *
551
 * Note that the branching code sequences used for ? and the general cases
552
 * of * and + are somewhat optimized:  they use the same NOTHING node as
553
 * both the endmarker for their branch list and the body of the last branch.
554
 * It might seem that this node could be dispensed with entirely, but the
555
 * endmarker role is not redundant.
556
 */
557
char* RegExpCompile::regpiece(int* flagp)
558
1.09M
{
559
1.09M
  char* ret;
560
1.09M
  char op;
561
1.09M
  char* next;
562
1.09M
  int flags;
563
564
1.09M
  ret = regatom(&flags);
565
1.09M
  if (!ret)
566
1.30k
    return (nullptr);
567
568
1.09M
  op = *regparse;
569
1.09M
  if (!ISMULT(op)) {
570
983k
    *flagp = flags;
571
983k
    return (ret);
572
983k
  }
573
574
110k
  if (!(flags & HASWIDTH) && op != '?') {
575
    // RAISE Error, SYM(RegularExpression), SYM(Empty_Operand),
576
11
    printf("RegularExpression::compile() : *+ operand could be empty.\n");
577
11
    return nullptr;
578
11
  }
579
110k
  *flagp = (op != '+') ? (WORST | SPSTART) : (WORST | HASWIDTH);
580
581
110k
  if (op == '*' && (flags & SIMPLE))
582
43.8k
    reginsert(STAR, ret);
583
67.0k
  else if (op == '*') {
584
    // Emit x* as (x&|), where & means "self".
585
2.76k
    reginsert(BRANCH, ret);         // Either x
586
2.76k
    regoptail(ret, regnode(BACK));  // and loop
587
2.76k
    regoptail(ret, ret);            // back
588
2.76k
    regtail(ret, regnode(BRANCH));  // or
589
2.76k
    regtail(ret, regnode(NOTHING)); // null.
590
64.2k
  } else if (op == '+' && (flags & SIMPLE))
591
41.3k
    reginsert(PLUS, ret);
592
22.8k
  else if (op == '+') {
593
    // Emit x+ as x(&|), where & means "self".
594
819
    next = regnode(BRANCH); // Either
595
819
    regtail(ret, next);
596
819
    regtail(regnode(BACK), ret);    // loop back
597
819
    regtail(next, regnode(BRANCH)); // or
598
819
    regtail(ret, regnode(NOTHING)); // null.
599
22.0k
  } else if (op == '?') {
600
    // Emit x? as (x|)
601
22.0k
    reginsert(BRANCH, ret);        // Either x
602
22.0k
    regtail(ret, regnode(BRANCH)); // or
603
22.0k
    next = regnode(NOTHING);       // null.
604
22.0k
    regtail(ret, next);
605
22.0k
    regoptail(ret, next);
606
22.0k
  }
607
110k
  regparse++;
608
110k
  if (ISMULT(*regparse)) {
609
    // RAISE Error, SYM(RegularExpression), SYM(Nested_Operand),
610
41
    printf("RegularExpression::compile(): Nested *?+.\n");
611
41
    return nullptr;
612
41
  }
613
110k
  return (ret);
614
110k
}
615
616
/*
617
 - regatom - the lowest level
618
 *
619
 * Optimization:  gobbles an entire sequence of ordinary characters so that
620
 * it can turn them into a single node, which is smaller to store and
621
 * faster to run.  Backslashed characters are exceptions, each becoming a
622
 * separate node; the code is simpler that way and it's not worth fixing.
623
 */
624
char* RegExpCompile::regatom(int* flagp)
625
1.09M
{
626
1.09M
  char* ret;
627
1.09M
  int flags;
628
629
1.09M
  *flagp = WORST; // Tentatively.
630
631
1.09M
  switch (*regparse++) {
632
26.2k
    case '^':
633
26.2k
      ret = regnode(BOL);
634
26.2k
      break;
635
94.2k
    case '$':
636
94.2k
      ret = regnode(EOL);
637
94.2k
      break;
638
334k
    case '.':
639
334k
      ret = regnode(ANY);
640
334k
      *flagp |= HASWIDTH | SIMPLE;
641
334k
      break;
642
18.9k
    case '[': {
643
18.9k
      int rxpclass;
644
18.9k
      int rxpclassend;
645
646
18.9k
      if (*regparse == '^') { // Complement of range.
647
1.97k
        ret = regnode(ANYBUT);
648
1.97k
        regparse++;
649
1.97k
      } else
650
16.9k
        ret = regnode(ANYOF);
651
18.9k
      if (*regparse == ']' || *regparse == '-')
652
2.55k
        regc(*regparse++);
653
3.27M
      while (*regparse != '\0' && *regparse != ']') {
654
3.25M
        if (*regparse == '-') {
655
52.0k
          regparse++;
656
52.0k
          if (*regparse == ']' || *regparse == '\0')
657
926
            regc('-');
658
51.1k
          else {
659
51.1k
            rxpclass = UCHARAT(regparse - 2) + 1;
660
51.1k
            rxpclassend = UCHARAT(regparse);
661
51.1k
            if (rxpclass > rxpclassend + 1) {
662
              // RAISE Error, SYM(RegularExpression), SYM(Invalid_Range),
663
45
              printf("RegularExpression::compile(): Invalid range in [].\n");
664
45
              return nullptr;
665
45
            }
666
6.53M
            for (; rxpclass <= rxpclassend; rxpclass++)
667
6.48M
              regc(static_cast<char>(rxpclass));
668
51.0k
            regparse++;
669
51.0k
          }
670
52.0k
        } else
671
3.20M
          regc(*regparse++);
672
3.25M
      }
673
18.8k
      regc('\0');
674
18.8k
      if (*regparse != ']') {
675
        // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Bracket),
676
153
        printf("RegularExpression::compile(): Unmatched [].\n");
677
153
        return nullptr;
678
153
      }
679
18.7k
      regparse++;
680
18.7k
      *flagp |= HASWIDTH | SIMPLE;
681
18.7k
    } break;
682
54.1k
    case '(':
683
54.1k
      ret = reg(1, &flags);
684
54.1k
      if (!ret)
685
1.07k
        return (nullptr);
686
53.0k
      *flagp |= flags & (HASWIDTH | SPSTART);
687
53.0k
      break;
688
0
    case '\0':
689
0
    case '|':
690
0
    case ')':
691
      // RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
692
0
      printf("RegularExpression::compile(): Internal error.\n"); // Never here
693
0
      return nullptr;
694
6
    case '?':
695
11
    case '+':
696
16
    case '*':
697
      // RAISE Error, SYM(RegularExpression), SYM(No_Operand),
698
16
      printf("RegularExpression::compile(): ?+* follows nothing.\n");
699
16
      return nullptr;
700
7.19k
    case '\\':
701
7.19k
      if (*regparse == '\0') {
702
        // RAISE Error, SYM(RegularExpression), SYM(Trailing_Backslash),
703
13
        printf("RegularExpression::compile(): Trailing backslash.\n");
704
13
        return nullptr;
705
13
      }
706
7.17k
      ret = regnode(EXACTLY);
707
7.17k
      regc(*regparse++);
708
7.17k
      regc('\0');
709
7.17k
      *flagp |= HASWIDTH | SIMPLE;
710
7.17k
      break;
711
560k
    default: {
712
560k
      int len;
713
560k
      char ender;
714
715
560k
      regparse--;
716
560k
      len = int(strcspn(regparse, META));
717
560k
      if (len <= 0) {
718
        // RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
719
0
        printf("RegularExpression::compile(): Internal error.\n");
720
0
        return nullptr;
721
0
      }
722
560k
      ender = *(regparse + len);
723
560k
      if (len > 1 && ISMULT(ender))
724
79.1k
        len--; // Back off clear of ?+* operand.
725
560k
      *flagp |= HASWIDTH;
726
560k
      if (len == 1)
727
216k
        *flagp |= SIMPLE;
728
560k
      ret = regnode(EXACTLY);
729
21.7M
      while (len > 0) {
730
21.2M
        regc(*regparse++);
731
21.2M
        len--;
732
21.2M
      }
733
560k
      regc('\0');
734
560k
    } break;
735
1.09M
  }
736
1.09M
  return (ret);
737
1.09M
}
738
739
/*
740
 - regnode - emit a node
741
   Location.
742
 */
743
char* RegExpCompile::regnode(char op)
744
1.54M
{
745
1.54M
  char* ret;
746
1.54M
  char* ptr;
747
748
1.54M
  ret = regcode;
749
1.54M
  if (ret == regdummyptr) {
750
805k
    regsize += 3;
751
805k
    return (ret);
752
805k
  }
753
754
734k
  ptr = ret;
755
734k
  *ptr++ = op;
756
734k
  *ptr++ = '\0'; // Null "next" pointer.
757
734k
  *ptr++ = '\0';
758
734k
  regcode = ptr;
759
760
734k
  return (ret);
761
1.54M
}
762
763
/*
764
 - regc - emit (if appropriate) a byte of code
765
 */
766
void RegExpCompile::regc(char b)
767
31.5M
{
768
31.5M
  if (regcode != regdummyptr)
769
14.9M
    *regcode++ = b;
770
16.5M
  else
771
16.5M
    regsize++;
772
31.5M
}
773
774
/*
775
 - reginsert - insert an operator in front of already-emitted operand
776
 *
777
 * Means relocating the operand.
778
 */
779
void RegExpCompile::reginsert(char op, char* opnd)
780
110k
{
781
110k
  char* src;
782
110k
  char* dst;
783
110k
  char* place;
784
785
110k
  if (regcode == regdummyptr) {
786
58.4k
    regsize += 3;
787
58.4k
    return;
788
58.4k
  }
789
790
51.5k
  src = regcode;
791
51.5k
  regcode += 3;
792
51.5k
  dst = regcode;
793
8.05M
  while (src > opnd)
794
7.99M
    *--dst = *--src;
795
796
51.5k
  place = opnd; // Op node, where operand used to be.
797
51.5k
  *place++ = op;
798
51.5k
  *place++ = '\0';
799
51.5k
  *place = '\0';
800
51.5k
}
801
802
/*
803
 - regtail - set the next-pointer at the end of a node chain
804
 */
805
void RegExpCompile::regtail(char* p, char const* val)
806
1.42M
{
807
1.42M
  char* scan;
808
1.42M
  char* temp;
809
1.42M
  int offset;
810
811
1.42M
  if (p == regdummyptr)
812
687k
    return;
813
814
  // Find last node.
815
740k
  scan = p;
816
2.89M
  for (;;) {
817
2.89M
    temp = regnext(scan);
818
2.89M
    if (!temp)
819
740k
      break;
820
2.15M
    scan = temp;
821
2.15M
  }
822
823
740k
  if (OP(scan) == BACK)
824
1.73k
    offset = int(scan - val);
825
738k
  else
826
738k
    offset = int(val - scan);
827
740k
  *(scan + 1) = static_cast<char>((offset >> 8) & 0377);
828
740k
  *(scan + 2) = static_cast<char>(offset & 0377);
829
740k
}
830
831
/*
832
 - regoptail - regtail on operand of first argument; nop if operandless
833
 */
834
void RegExpCompile::regoptail(char* p, char const* val)
835
219k
{
836
  // "Operandless" and "op != BRANCH" are synonymous in practice.
837
219k
  if (!p || p == regdummyptr || OP(p) != BRANCH)
838
106k
    return;
839
113k
  regtail(OPERAND(p), val);
840
113k
}
841
842
////////////////////////////////////////////////////////////////////////
843
//
844
//  find and friends
845
//
846
////////////////////////////////////////////////////////////////////////
847
848
/*
849
 * Utility class for RegularExpression::find().
850
 */
851
class RegExpFind
852
{
853
public:
854
  char const* reginput;   // String-input pointer.
855
  char const* regbol;     // Beginning of input, for ^ check.
856
  char const** regstartp; // Pointer to startp array.
857
  char const** regendp;   // Ditto for endp.
858
  char const* regreject; // Reject matches ending here, for NONEMPTY_AT_OFFSET.
859
860
  int regtry(char const*, char const**, char const**, char const*);
861
  int regmatch(char const*);
862
  int regrepeat(char const*);
863
};
864
865
// find -- Matches the regular expression to the given string.
866
// Returns true if found, and sets start and end indexes accordingly.
867
bool RegularExpression::find(char const* string,
868
                             RegularExpressionMatch& rmatch,
869
                             std::string::size_type offset,
870
                             unsigned options) const
871
12.2k
{
872
12.2k
  char const* s;
873
874
12.2k
  rmatch.clear();
875
12.2k
  rmatch.searchstring = string;
876
877
12.2k
  if (!this->program) {
878
0
    return false;
879
0
  }
880
881
  // Check validity of program.
882
12.2k
  if (UCHARAT(this->program) != MAGIC) {
883
    // RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
884
0
    printf(
885
0
      "RegularExpression::find(): Compiled regular expression corrupted.\n");
886
0
    return false;
887
0
  }
888
889
  // If there is a "must appear" string, look for it.
890
12.2k
  if (this->regmust) {
891
1.49k
    s = string + offset;
892
8.37k
    while ((s = strchr(s, this->regmust[0]))) {
893
7.41k
      if (strncmp(s, this->regmust, this->regmlen) == 0)
894
538
        break; // Found it.
895
6.87k
      s++;
896
6.87k
    }
897
1.49k
    if (!s) // Not present.
898
956
      return false;
899
1.49k
  }
900
901
11.2k
  RegExpFind regFind;
902
11.2k
  s = string + offset;
903
904
  // Mark beginning of line for ^ .
905
11.2k
  regFind.regbol = (options & BOL_AT_OFFSET) ? s : string;
906
11.2k
  regFind.regreject = (options & NONEMPTY_AT_OFFSET) ? s : nullptr;
907
908
  // Simplest case:  anchored match need be tried only once.
909
11.2k
  if (this->reganch)
910
2.82k
    return (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program) != 0);
911
912
  // Messy cases:  unanchored match.
913
8.44k
  if (this->regstart != '\0')
914
    // We know what char it must start with.
915
5.90k
    while ((s = strchr(s, this->regstart))) {
916
5.01k
      if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program))
917
196
        return true;
918
4.82k
      s++;
919
4.82k
    }
920
7.36k
  else
921
    // We don't -- general case.
922
1.13M
    do {
923
1.13M
      if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program))
924
4.09k
        return true;
925
1.13M
    } while (*s++ != '\0');
926
927
  // Failure.
928
4.16k
  return false;
929
8.44k
}
930
931
/*
932
 - regtry - try match at specific point
933
   0 failure, 1 success
934
 */
935
int RegExpFind::regtry(char const* string, char const** start,
936
                       char const** end, char const* prog)
937
1.14M
{
938
1.14M
  int i;
939
1.14M
  char const** sp1;
940
1.14M
  char const** ep;
941
942
1.14M
  reginput = string;
943
1.14M
  regstartp = start;
944
1.14M
  regendp = end;
945
946
1.14M
  sp1 = start;
947
1.14M
  ep = end;
948
37.7M
  for (i = RegularExpressionMatch::NSUBEXP; i > 0; i--) {
949
36.5M
    *sp1++ = nullptr;
950
36.5M
    *ep++ = nullptr;
951
36.5M
  }
952
1.14M
  if (regmatch(prog + 1)) {
953
4.38k
    start[0] = string;
954
4.38k
    end[0] = reginput;
955
4.38k
    return (1);
956
4.38k
  } else
957
1.13M
    return (0);
958
1.14M
}
959
960
/*
961
 - regmatch - main matching routine
962
 *
963
 * Conceptually the strategy is simple:  check to see whether the current
964
 * node matches, call self recursively to see whether the rest matches,
965
 * and then act accordingly.  In practice we make some effort to avoid
966
 * recursion, in particular by going through "ordinary" nodes (that don't
967
 * need to know whether the rest of the match failed) by a loop instead of
968
 * by recursion.
969
 * 0 failure, 1 success
970
 */
971
int RegExpFind::regmatch(char const* prog)
972
38.2M
{
973
38.2M
  char const* scan; // Current node.
974
38.2M
  char const* next; // Next node.
975
976
38.2M
  scan = prog;
977
978
48.0M
  while (scan) {
979
980
48.0M
    next = regnext(scan);
981
982
48.0M
    switch (OP(scan)) {
983
3.60M
      case BOL:
984
3.60M
        if (reginput != regbol)
985
3.59M
          return (0);
986
9.36k
        break;
987
2.19M
      case EOL:
988
2.19M
        if (*reginput != '\0')
989
1.04M
          return (0);
990
1.15M
        break;
991
1.47M
      case ANY:
992
1.47M
        if (*reginput == '\0')
993
990k
          return (0);
994
482k
        reginput++;
995
482k
        break;
996
9.31M
      case EXACTLY: {
997
9.31M
        size_t len;
998
9.31M
        char const* opnd;
999
1000
9.31M
        opnd = OPERAND(scan);
1001
        // Inline the first character, for speed.
1002
9.31M
        if (*opnd != *reginput)
1003
8.87M
          return (0);
1004
431k
        len = strlen(opnd);
1005
431k
        if (len > 1 && strncmp(opnd, reginput, len) != 0)
1006
154k
          return (0);
1007
277k
        reginput += len;
1008
277k
      } break;
1009
737k
      case ANYOF:
1010
737k
        if (*reginput == '\0' || !strchr(OPERAND(scan), *reginput))
1011
666k
          return (0);
1012
71.0k
        reginput++;
1013
71.0k
        break;
1014
17.0k
      case ANYBUT:
1015
17.0k
        if (*reginput == '\0' || strchr(OPERAND(scan), *reginput))
1016
6.73k
          return (0);
1017
10.3k
        reginput++;
1018
10.3k
        break;
1019
6.15M
      case NOTHING:
1020
6.15M
        break;
1021
74.1k
      case BACK:
1022
74.1k
        break;
1023
102k
      case OPEN + 1:
1024
161k
      case OPEN + 2:
1025
218k
      case OPEN + 3:
1026
276k
      case OPEN + 4:
1027
324k
      case OPEN + 5:
1028
383k
      case OPEN + 6:
1029
424k
      case OPEN + 7:
1030
601k
      case OPEN + 8:
1031
930k
      case OPEN + 9:
1032
1.25M
      case OPEN + 10:
1033
1.30M
      case OPEN + 11:
1034
1.34M
      case OPEN + 12:
1035
1.37M
      case OPEN + 13:
1036
1.41M
      case OPEN + 14:
1037
1.43M
      case OPEN + 15:
1038
1.47M
      case OPEN + 16:
1039
1.54M
      case OPEN + 17:
1040
1.58M
      case OPEN + 18:
1041
1.62M
      case OPEN + 19:
1042
1.66M
      case OPEN + 20:
1043
1.71M
      case OPEN + 21:
1044
1.77M
      case OPEN + 22:
1045
1.83M
      case OPEN + 23:
1046
1.92M
      case OPEN + 24:
1047
2.03M
      case OPEN + 25:
1048
2.19M
      case OPEN + 26:
1049
2.35M
      case OPEN + 27:
1050
2.63M
      case OPEN + 28:
1051
3.13M
      case OPEN + 29:
1052
3.14M
      case OPEN + 30:
1053
3.15M
      case OPEN + 31:
1054
3.15M
      case OPEN + 32: {
1055
3.15M
        int no;
1056
3.15M
        char const* save;
1057
1058
3.15M
        no = OP(scan) - OPEN;
1059
3.15M
        save = reginput;
1060
1061
3.15M
        if (regmatch(next)) {
1062
1063
          //
1064
          // Don't set startp if some later invocation of the
1065
          // same parentheses already has.
1066
          //
1067
288k
          if (!regstartp[no])
1068
9.27k
            regstartp[no] = save;
1069
288k
          return (1);
1070
288k
        } else
1071
2.87M
          return (0);
1072
3.15M
      }
1073
      //              break;
1074
139k
      case CLOSE + 1:
1075
255k
      case CLOSE + 2:
1076
283k
      case CLOSE + 3:
1077
308k
      case CLOSE + 4:
1078
361k
      case CLOSE + 5:
1079
390k
      case CLOSE + 6:
1080
481k
      case CLOSE + 7:
1081
724k
      case CLOSE + 8:
1082
740k
      case CLOSE + 9:
1083
1.05M
      case CLOSE + 10:
1084
1.07M
      case CLOSE + 11:
1085
1.09M
      case CLOSE + 12:
1086
1.10M
      case CLOSE + 13:
1087
1.12M
      case CLOSE + 14:
1088
1.14M
      case CLOSE + 15:
1089
1.16M
      case CLOSE + 16:
1090
1.18M
      case CLOSE + 17:
1091
1.21M
      case CLOSE + 18:
1092
1.23M
      case CLOSE + 19:
1093
1.27M
      case CLOSE + 20:
1094
1.32M
      case CLOSE + 21:
1095
1.37M
      case CLOSE + 22:
1096
1.45M
      case CLOSE + 23:
1097
1.55M
      case CLOSE + 24:
1098
1.71M
      case CLOSE + 25:
1099
1.84M
      case CLOSE + 26:
1100
2.09M
      case CLOSE + 27:
1101
2.61M
      case CLOSE + 28:
1102
3.11M
      case CLOSE + 29:
1103
3.12M
      case CLOSE + 30:
1104
3.12M
      case CLOSE + 31:
1105
3.12M
      case CLOSE + 32: {
1106
3.12M
        int no;
1107
3.12M
        char const* save;
1108
1109
3.12M
        no = OP(scan) - CLOSE;
1110
3.12M
        save = reginput;
1111
1112
3.12M
        if (regmatch(next)) {
1113
1114
          //
1115
          // Don't set endp if some later invocation of the
1116
          // same parentheses already has.
1117
          //
1118
288k
          if (!regendp[no])
1119
9.27k
            regendp[no] = save;
1120
288k
          return (1);
1121
288k
        } else
1122
2.84M
          return (0);
1123
3.12M
      }
1124
      //              break;
1125
7.55M
      case BRANCH: {
1126
1127
7.55M
        char const* save;
1128
1129
7.55M
        if (OP(next) != BRANCH) // No choice.
1130
1.57M
          next = OPERAND(scan); // Avoid recursion.
1131
5.98M
        else {
1132
19.8M
          do {
1133
19.8M
            save = reginput;
1134
19.8M
            if (regmatch(OPERAND(scan)))
1135
721k
              return (1);
1136
19.1M
            reginput = save;
1137
19.1M
            scan = regnext(scan);
1138
19.1M
          } while (scan && OP(scan) == BRANCH);
1139
5.25M
          return (0);
1140
          // NOTREACHED
1141
5.98M
        }
1142
7.55M
      } break;
1143
1.57M
      case STAR:
1144
10.6M
      case PLUS: {
1145
10.6M
        char nextch;
1146
10.6M
        int no;
1147
10.6M
        char const* save;
1148
10.6M
        int min_no;
1149
1150
        //
1151
        // Lookahead to avoid useless match attempts when we know
1152
        // what character comes next.
1153
        //
1154
10.6M
        nextch = '\0';
1155
10.6M
        if (OP(next) == EXACTLY)
1156
2.31M
          nextch = *OPERAND(next);
1157
10.6M
        min_no = (OP(scan) == STAR) ? 0 : 1;
1158
10.6M
        save = reginput;
1159
10.6M
        no = regrepeat(OPERAND(scan));
1160
40.5M
        while (no >= min_no) {
1161
          // If it could work, try it.
1162
29.9M
          if (nextch == '\0' || *reginput == nextch)
1163
10.9M
            if (regmatch(next))
1164
4.73k
              return (1);
1165
          // Couldn't or didn't -- back up.
1166
29.9M
          no--;
1167
29.9M
          reginput = save + no;
1168
29.9M
        }
1169
10.6M
        return (0);
1170
10.6M
      }
1171
      //              break;
1172
4.38k
      case END:
1173
4.38k
        if (reginput == regreject)
1174
0
          return (0); // Can't end a match here
1175
4.38k
        return (1);   // Success!
1176
1177
0
      default:
1178
        // RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
1179
0
        printf(
1180
0
          "RegularExpression::find(): Internal error -- memory corrupted.\n");
1181
0
        return 0;
1182
48.0M
    }
1183
9.80M
    scan = next;
1184
9.80M
  }
1185
1186
  //
1187
  //  We get here only if there's trouble -- normally "case END" is the
1188
  //  terminating point.
1189
  //
1190
  // RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
1191
0
  printf("RegularExpression::find(): Internal error -- corrupted pointers.\n");
1192
0
  return (0);
1193
38.2M
}
1194
1195
/*
1196
 - regrepeat - repeatedly match something simple, report how many
1197
 */
1198
int RegExpFind::regrepeat(char const* p)
1199
10.6M
{
1200
10.6M
  int count = 0;
1201
10.6M
  char const* scan;
1202
10.6M
  char const* opnd;
1203
1204
10.6M
  scan = reginput;
1205
10.6M
  opnd = OPERAND(p);
1206
10.6M
  switch (OP(p)) {
1207
98.6k
    case ANY:
1208
98.6k
      count = int(strlen(scan));
1209
98.6k
      scan += count;
1210
98.6k
      break;
1211
599k
    case EXACTLY:
1212
631k
      while (*opnd == *scan) {
1213
32.5k
        count++;
1214
32.5k
        scan++;
1215
32.5k
      }
1216
599k
      break;
1217
9.43M
    case ANYOF:
1218
16.6M
      while (*scan != '\0' && strchr(opnd, *scan)) {
1219
7.25M
        count++;
1220
7.25M
        scan++;
1221
7.25M
      }
1222
9.43M
      break;
1223
486k
    case ANYBUT:
1224
3.78M
      while (*scan != '\0' && !strchr(opnd, *scan)) {
1225
3.30M
        count++;
1226
3.30M
        scan++;
1227
3.30M
      }
1228
486k
      break;
1229
0
    default: // Oh dear.  Called inappropriately.
1230
      // RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
1231
0
      printf("cm RegularExpression::find(): Internal error.\n");
1232
0
      return 0;
1233
10.6M
  }
1234
10.6M
  reginput = scan;
1235
10.6M
  return (count);
1236
10.6M
}
1237
1238
/*
1239
 - regnext - dig the "next" pointer out of a node
1240
 */
1241
static char const* regnext(char const* p)
1242
67.2M
{
1243
67.2M
  int offset;
1244
1245
67.2M
  if (p == regdummyptr)
1246
0
    return (nullptr);
1247
1248
67.2M
  offset = NEXT(p);
1249
67.2M
  if (offset == 0)
1250
5.72k
    return (nullptr);
1251
1252
67.2M
  if (OP(p) == BACK)
1253
74.1k
    return (p - offset);
1254
67.2M
  else
1255
67.2M
    return (p + offset);
1256
67.2M
}
1257
1258
static char* regnext(char* p)
1259
3.08M
{
1260
3.08M
  int offset;
1261
1262
3.08M
  if (p == regdummyptr)
1263
33.3k
    return (nullptr);
1264
1265
3.05M
  offset = NEXT(p);
1266
3.05M
  if (offset == 0)
1267
772k
    return (nullptr);
1268
1269
2.27M
  if (OP(p) == BACK)
1270
0
    return (p - offset);
1271
2.27M
  else
1272
2.27M
    return (p + offset);
1273
2.27M
}
1274
1275
} // namespace KWSYS_NAMESPACE