Coverage Report

Created: 2026-02-09 06:05

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
23.6k
#define END 0   // no   End of program.
200
17.7k
#define BOL 1   // no   Match "" at beginning of line.
201
17.8M
#define EOL 2   // no   Match "" at end of line.
202
20.6M
#define ANY 3   // no   Match any one character.
203
3.50M
#define ANYOF 4 // str  Match any character in this string.
204
#define ANYBUT                                                                \
205
107k
  5 // str  Match any character not in this
206
    // string.
207
#define BRANCH                                                                \
208
260M
  6               // node Match this alternative, or the
209
                  // next...
210
425M
#define BACK 7    // no   Match "", "next" ptr points backward.
211
38.5M
#define EXACTLY 8 // str  Match this string.
212
49.3M
#define NOTHING 9 // no   Match empty string.
213
#define STAR                                                                  \
214
4.10M
  10 // node Match this (simple) thing 0 or more
215
     // times.
216
#define PLUS                                                                  \
217
2.20M
  11 // node Match this (simple) thing 1 or more
218
     // times.
219
#define OPEN                                                                  \
220
1.08G
  20 // no   Mark this point in input as start of
221
     // #n.
222
// OPEN+1 is number 1, etc.
223
962M
#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
1.03G
#define OP(p) (*(p))
259
418M
#define NEXT(p) (((*((p) + 1) & 0377) << 8) + (*((p) + 2) & 0377))
260
175M
#define OPERAND(p) ((p) + 3)
261
262
unsigned char const MAGIC = 0234;
263
/*
264
 * Utility definitions.
265
 */
266
267
57.1k
#define UCHARAT(p) (reinterpret_cast<const unsigned char*>(p))[0]
268
269
136k
#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
270
41.0k
#define META "^$.[()|?+*\\"
271
272
/*
273
 * Flags to be passed up and down.
274
 */
275
266k
#define HASWIDTH 01 // Known never to match null string.
276
69.9k
#define SIMPLE 02   // Simple enough to be STAR/PLUS operand.
277
80.1k
#define SPSTART 04  // Starts with * or +.
278
148k
#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
1.85k
{
340
1.85k
  char const* scan;
341
1.85k
  char const* longest;
342
1.85k
  int flags;
343
344
1.85k
  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
1.85k
  RegExpCompile comp;
352
1.85k
  comp.regparse = exp;
353
1.85k
  comp.regnpar = 1;
354
1.85k
  comp.regsize = 0L;
355
1.85k
  comp.regcode = regdummyptr;
356
1.85k
  comp.regc(static_cast<char>(MAGIC));
357
1.85k
  if (!comp.reg(0, &flags)) {
358
168
    printf("RegularExpression::compile(): Error in compile.\n");
359
168
    return false;
360
168
  }
361
1.68k
  this->regmatch.clear();
362
363
  // Small enough for pointer-storage convention?
364
1.68k
  if (comp.regsize >= 65535L) {
365
    // RAISE Error, SYM(RegularExpression), SYM(Expr_Too_Big),
366
1
    printf("RegularExpression::compile(): Expression too big.\n");
367
1
    return false;
368
1
  }
369
370
  // Allocate space.
371
  // #ifndef _WIN32
372
1.68k
  delete[] this->program;
373
  // #endif
374
1.68k
  this->program = new char[comp.regsize];
375
1.68k
  this->progsize = static_cast<int>(comp.regsize);
376
1.68k
  this->regnpar = comp.regnpar;
377
378
1.68k
  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
1.68k
  comp.regparse = exp;
390
1.68k
  comp.regnpar = 1;
391
1.68k
  comp.regcode = this->program;
392
1.68k
  comp.regc(static_cast<char>(MAGIC));
393
1.68k
  comp.reg(0, &flags);
394
395
  // Dig out information for optimizations.
396
1.68k
  this->regstart = '\0'; // Worst-case defaults.
397
1.68k
  this->reganch = 0;
398
1.68k
  this->regmust = nullptr;
399
1.68k
  this->regmlen = 0;
400
1.68k
  scan = this->program + 1;       // First BRANCH.
401
1.68k
  if (OP(regnext(scan)) == END) { // Only one top-level choice.
402
1.58k
    scan = OPERAND(scan);
403
404
    // Starting-point info.
405
1.58k
    if (OP(scan) == EXACTLY)
406
331
      this->regstart = *OPERAND(scan);
407
1.25k
    else if (OP(scan) == BOL)
408
46
      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
1.58k
    if (flags & SPSTART) {
419
741
      longest = nullptr;
420
741
      size_t len = 0;
421
11.4k
      for (; scan; scan = regnext(scan))
422
10.6k
        if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
423
1.19k
          longest = OPERAND(scan);
424
1.19k
          len = strlen(OPERAND(scan));
425
1.19k
        }
426
741
      this->regmust = longest;
427
741
      this->regmlen = len;
428
741
    }
429
1.58k
  }
430
1.68k
  return true;
431
1.68k
}
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
17.2k
{
444
17.2k
  char* ret;
445
17.2k
  char* br;
446
17.2k
  char* ender;
447
17.2k
  int parno = 0;
448
17.2k
  int flags;
449
450
17.2k
  *flagp = HASWIDTH; // Tentatively.
451
452
  // Make an OPEN node, if parenthesized.
453
17.2k
  if (paren) {
454
13.7k
    if (regnpar >= RegularExpressionMatch::NSUBEXP) {
455
      // RAISE Error, SYM(RegularExpression), SYM(Too_Many_Parens),
456
5
      printf("RegularExpression::compile(): Too many parentheses.\n");
457
5
      return nullptr;
458
5
    }
459
13.7k
    parno = regnpar;
460
13.7k
    regnpar++;
461
13.7k
    ret = regnode(static_cast<char>(OPEN + parno));
462
13.7k
  } else
463
3.53k
    ret = nullptr;
464
465
  // Pick up the branches, linking them together.
466
17.2k
  br = regbranch(&flags);
467
17.2k
  if (!br)
468
325
    return (nullptr);
469
16.9k
  if (ret)
470
13.5k
    regtail(ret, br); // OPEN -> first.
471
3.39k
  else
472
3.39k
    ret = br;
473
16.9k
  if (!(flags & HASWIDTH))
474
4.87k
    *flagp &= ~HASWIDTH;
475
16.9k
  *flagp |= flags & SPSTART;
476
28.7k
  while (*regparse == '|') {
477
11.9k
    regparse++;
478
11.9k
    br = regbranch(&flags);
479
11.9k
    if (!br)
480
133
      return (nullptr);
481
11.8k
    regtail(ret, br); // BRANCH -> BRANCH.
482
11.8k
    if (!(flags & HASWIDTH))
483
5.57k
      *flagp &= ~HASWIDTH;
484
11.8k
    *flagp |= flags & SPSTART;
485
11.8k
  }
486
487
  // Make a closing node, and hook it on the end.
488
16.8k
  ender = regnode(static_cast<char>((paren) ? CLOSE + parno : END));
489
16.8k
  regtail(ret, ender);
490
491
  // Hook the tails of the branches to the closing node.
492
54.3k
  for (br = ret; br; br = regnext(br))
493
37.4k
    regoptail(br, ender);
494
495
  // Check for proper termination.
496
16.8k
  if (paren && *regparse++ != ')') {
497
    // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens),
498
47
    printf("RegularExpression::compile(): Unmatched parentheses.\n");
499
47
    return nullptr;
500
16.7k
  } else if (!paren && *regparse != '\0') {
501
14
    if (*regparse == ')') {
502
      // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens),
503
14
      printf("RegularExpression::compile(): Unmatched parentheses.\n");
504
14
      return nullptr;
505
14
    } 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
14
  }
512
16.7k
  return (ret);
513
16.8k
}
514
515
/*
516
 - regbranch - one alternative of an | operator
517
 *
518
 * Implements the concatenation operator.
519
 */
520
char* RegExpCompile::regbranch(int* flagp)
521
29.2k
{
522
29.2k
  char* ret;
523
29.2k
  char* chain;
524
29.2k
  char* latest;
525
29.2k
  int flags;
526
527
29.2k
  *flagp = WORST; // Tentatively.
528
529
29.2k
  ret = regnode(BRANCH);
530
29.2k
  chain = nullptr;
531
124k
  while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
532
95.8k
    latest = regpiece(&flags);
533
95.8k
    if (!latest)
534
458
      return (nullptr);
535
95.3k
    *flagp |= flags & HASWIDTH;
536
95.3k
    if (!chain) // First piece.
537
20.0k
      *flagp |= flags & SPSTART;
538
75.3k
    else
539
75.3k
      regtail(chain, latest);
540
95.3k
    chain = latest;
541
95.3k
  }
542
28.7k
  if (!chain) // Loop ran zero times.
543
8.83k
    regnode(NOTHING);
544
545
28.7k
  return (ret);
546
29.2k
}
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
95.8k
{
559
95.8k
  char* ret;
560
95.8k
  char op;
561
95.8k
  char* next;
562
95.8k
  int flags;
563
564
95.8k
  ret = regatom(&flags);
565
95.8k
  if (!ret)
566
447
    return (nullptr);
567
568
95.3k
  op = *regparse;
569
95.3k
  if (!ISMULT(op)) {
570
71.5k
    *flagp = flags;
571
71.5k
    return (ret);
572
71.5k
  }
573
574
23.8k
  if (!(flags & HASWIDTH) && op != '?') {
575
    // RAISE Error, SYM(RegularExpression), SYM(Empty_Operand),
576
2
    printf("RegularExpression::compile() : *+ operand could be empty.\n");
577
2
    return nullptr;
578
2
  }
579
23.8k
  *flagp = (op != '+') ? (WORST | SPSTART) : (WORST | HASWIDTH);
580
581
23.8k
  if (op == '*' && (flags & SIMPLE))
582
6.69k
    reginsert(STAR, ret);
583
17.2k
  else if (op == '*') {
584
    // Emit x* as (x&|), where & means "self".
585
1.99k
    reginsert(BRANCH, ret);         // Either x
586
1.99k
    regoptail(ret, regnode(BACK));  // and loop
587
1.99k
    regoptail(ret, ret);            // back
588
1.99k
    regtail(ret, regnode(BRANCH));  // or
589
1.99k
    regtail(ret, regnode(NOTHING)); // null.
590
15.2k
  } else if (op == '+' && (flags & SIMPLE))
591
7.39k
    reginsert(PLUS, ret);
592
7.81k
  else if (op == '+') {
593
    // Emit x+ as x(&|), where & means "self".
594
217
    next = regnode(BRANCH); // Either
595
217
    regtail(ret, next);
596
217
    regtail(regnode(BACK), ret);    // loop back
597
217
    regtail(next, regnode(BRANCH)); // or
598
217
    regtail(ret, regnode(NOTHING)); // null.
599
7.59k
  } else if (op == '?') {
600
    // Emit x? as (x|)
601
7.59k
    reginsert(BRANCH, ret);        // Either x
602
7.59k
    regtail(ret, regnode(BRANCH)); // or
603
7.59k
    next = regnode(NOTHING);       // null.
604
7.59k
    regtail(ret, next);
605
7.59k
    regoptail(ret, next);
606
7.59k
  }
607
23.8k
  regparse++;
608
23.8k
  if (ISMULT(*regparse)) {
609
    // RAISE Error, SYM(RegularExpression), SYM(Nested_Operand),
610
9
    printf("RegularExpression::compile(): Nested *?+.\n");
611
9
    return nullptr;
612
9
  }
613
23.8k
  return (ret);
614
23.8k
}
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
95.8k
{
626
95.8k
  char* ret;
627
95.8k
  int flags;
628
629
95.8k
  *flagp = WORST; // Tentatively.
630
631
95.8k
  switch (*regparse++) {
632
2.91k
    case '^':
633
2.91k
      ret = regnode(BOL);
634
2.91k
      break;
635
9.50k
    case '$':
636
9.50k
      ret = regnode(EOL);
637
9.50k
      break;
638
12.4k
    case '.':
639
12.4k
      ret = regnode(ANY);
640
12.4k
      *flagp |= HASWIDTH | SIMPLE;
641
12.4k
      break;
642
12.4k
    case '[': {
643
12.4k
      int rxpclass;
644
12.4k
      int rxpclassend;
645
646
12.4k
      if (*regparse == '^') { // Complement of range.
647
2.47k
        ret = regnode(ANYBUT);
648
2.47k
        regparse++;
649
2.47k
      } else
650
10.0k
        ret = regnode(ANYOF);
651
12.4k
      if (*regparse == ']' || *regparse == '-')
652
2.30k
        regc(*regparse++);
653
135k
      while (*regparse != '\0' && *regparse != ']') {
654
122k
        if (*regparse == '-') {
655
25.7k
          regparse++;
656
25.7k
          if (*regparse == ']' || *regparse == '\0')
657
854
            regc('-');
658
24.9k
          else {
659
24.9k
            rxpclass = UCHARAT(regparse - 2) + 1;
660
24.9k
            rxpclassend = UCHARAT(regparse);
661
24.9k
            if (rxpclass > rxpclassend + 1) {
662
              // RAISE Error, SYM(RegularExpression), SYM(Invalid_Range),
663
13
              printf("RegularExpression::compile(): Invalid range in [].\n");
664
13
              return nullptr;
665
13
            }
666
3.00M
            for (; rxpclass <= rxpclassend; rxpclass++)
667
2.97M
              regc(static_cast<char>(rxpclass));
668
24.9k
            regparse++;
669
24.9k
          }
670
25.7k
        } else
671
97.1k
          regc(*regparse++);
672
122k
      }
673
12.4k
      regc('\0');
674
12.4k
      if (*regparse != ']') {
675
        // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Bracket),
676
56
        printf("RegularExpression::compile(): Unmatched [].\n");
677
56
        return nullptr;
678
56
      }
679
12.4k
      regparse++;
680
12.4k
      *flagp |= HASWIDTH | SIMPLE;
681
12.4k
    } break;
682
13.7k
    case '(':
683
13.7k
      ret = reg(1, &flags);
684
13.7k
      if (!ret)
685
356
        return (nullptr);
686
13.4k
      *flagp |= flags & (HASWIDTH | SPSTART);
687
13.4k
      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
3
    case '?':
695
4
    case '+':
696
15
    case '*':
697
      // RAISE Error, SYM(RegularExpression), SYM(No_Operand),
698
15
      printf("RegularExpression::compile(): ?+* follows nothing.\n");
699
15
      return nullptr;
700
3.67k
    case '\\':
701
3.67k
      if (*regparse == '\0') {
702
        // RAISE Error, SYM(RegularExpression), SYM(Trailing_Backslash),
703
7
        printf("RegularExpression::compile(): Trailing backslash.\n");
704
7
        return nullptr;
705
7
      }
706
3.66k
      ret = regnode(EXACTLY);
707
3.66k
      regc(*regparse++);
708
3.66k
      regc('\0');
709
3.66k
      *flagp |= HASWIDTH | SIMPLE;
710
3.66k
      break;
711
41.0k
    default: {
712
41.0k
      int len;
713
41.0k
      char ender;
714
715
41.0k
      regparse--;
716
41.0k
      len = int(strcspn(regparse, META));
717
41.0k
      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
41.0k
      ender = *(regparse + len);
723
41.0k
      if (len > 1 && ISMULT(ender))
724
4.62k
        len--; // Back off clear of ?+* operand.
725
41.0k
      *flagp |= HASWIDTH;
726
41.0k
      if (len == 1)
727
25.1k
        *flagp |= SIMPLE;
728
41.0k
      ret = regnode(EXACTLY);
729
247k
      while (len > 0) {
730
206k
        regc(*regparse++);
731
206k
        len--;
732
206k
      }
733
41.0k
      regc('\0');
734
41.0k
    } break;
735
95.8k
  }
736
95.3k
  return (ret);
737
95.8k
}
738
739
/*
740
 - regnode - emit a node
741
   Location.
742
 */
743
char* RegExpCompile::regnode(char op)
744
172k
{
745
172k
  char* ret;
746
172k
  char* ptr;
747
748
172k
  ret = regcode;
749
172k
  if (ret == regdummyptr) {
750
89.0k
    regsize += 3;
751
89.0k
    return (ret);
752
89.0k
  }
753
754
83.7k
  ptr = ret;
755
83.7k
  *ptr++ = op;
756
83.7k
  *ptr++ = '\0'; // Null "next" pointer.
757
83.7k
  *ptr++ = '\0';
758
83.7k
  regcode = ptr;
759
760
83.7k
  return (ret);
761
172k
}
762
763
/*
764
 - regc - emit (if appropriate) a byte of code
765
 */
766
void RegExpCompile::regc(char b)
767
3.35M
{
768
3.35M
  if (regcode != regdummyptr)
769
1.62M
    *regcode++ = b;
770
1.72M
  else
771
1.72M
    regsize++;
772
3.35M
}
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
23.6k
{
781
23.6k
  char* src;
782
23.6k
  char* dst;
783
23.6k
  char* place;
784
785
23.6k
  if (regcode == regdummyptr) {
786
12.4k
    regsize += 3;
787
12.4k
    return;
788
12.4k
  }
789
790
11.2k
  src = regcode;
791
11.2k
  regcode += 3;
792
11.2k
  dst = regcode;
793
1.83M
  while (src > opnd)
794
1.82M
    *--dst = *--src;
795
796
11.2k
  place = opnd; // Op node, where operand used to be.
797
11.2k
  *place++ = op;
798
11.2k
  *place++ = '\0';
799
11.2k
  *place = '\0';
800
11.2k
}
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
157k
{
807
157k
  char* scan;
808
157k
  char* temp;
809
157k
  int offset;
810
811
157k
  if (p == regdummyptr)
812
70.6k
    return;
813
814
  // Find last node.
815
86.7k
  scan = p;
816
564k
  for (;;) {
817
564k
    temp = regnext(scan);
818
564k
    if (!temp)
819
86.7k
      break;
820
477k
    scan = temp;
821
477k
  }
822
823
86.7k
  if (OP(scan) == BACK)
824
1.07k
    offset = int(scan - val);
825
85.6k
  else
826
85.6k
    offset = int(val - scan);
827
86.7k
  *(scan + 1) = static_cast<char>((offset >> 8) & 0377);
828
86.7k
  *(scan + 2) = static_cast<char>(offset & 0377);
829
86.7k
}
830
831
/*
832
 - regoptail - regtail on operand of first argument; nop if operandless
833
 */
834
void RegExpCompile::regoptail(char* p, char const* val)
835
49.0k
{
836
  // "Operandless" and "op != BRANCH" are synonymous in practice.
837
49.0k
  if (!p || p == regdummyptr || OP(p) != BRANCH)
838
29.3k
    return;
839
19.7k
  regtail(OPERAND(p), val);
840
19.7k
}
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
7.30k
{
872
7.30k
  char const* s;
873
874
7.30k
  rmatch.clear();
875
7.30k
  rmatch.searchstring = string;
876
877
7.30k
  if (!this->program) {
878
0
    return false;
879
0
  }
880
881
  // Check validity of program.
882
7.30k
  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
7.30k
  if (this->regmust) {
891
1.39k
    s = string + offset;
892
5.05k
    while ((s = strchr(s, this->regmust[0]))) {
893
4.12k
      if (strncmp(s, this->regmust, this->regmlen) == 0)
894
472
        break; // Found it.
895
3.65k
      s++;
896
3.65k
    }
897
1.39k
    if (!s) // Not present.
898
923
      return false;
899
1.39k
  }
900
901
6.38k
  RegExpFind regFind;
902
6.38k
  s = string + offset;
903
904
  // Mark beginning of line for ^ .
905
6.38k
  regFind.regbol = (options & BOL_AT_OFFSET) ? s : string;
906
6.38k
  regFind.regreject = (options & NONEMPTY_AT_OFFSET) ? s : nullptr;
907
908
  // Simplest case:  anchored match need be tried only once.
909
6.38k
  if (this->reganch)
910
2.44k
    return (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program) != 0);
911
912
  // Messy cases:  unanchored match.
913
3.93k
  if (this->regstart != '\0')
914
    // We know what char it must start with.
915
7.48k
    while ((s = strchr(s, this->regstart))) {
916
6.69k
      if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program))
917
162
        return true;
918
6.53k
      s++;
919
6.53k
    }
920
2.98k
  else
921
    // We don't -- general case.
922
87.3k
    do {
923
87.3k
      if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program))
924
1.54k
        return true;
925
87.3k
    } while (*s++ != '\0');
926
927
  // Failure.
928
2.22k
  return false;
929
3.93k
}
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
96.4k
{
938
96.4k
  int i;
939
96.4k
  char const** sp1;
940
96.4k
  char const** ep;
941
942
96.4k
  reginput = string;
943
96.4k
  regstartp = start;
944
96.4k
  regendp = end;
945
946
96.4k
  sp1 = start;
947
96.4k
  ep = end;
948
3.18M
  for (i = RegularExpressionMatch::NSUBEXP; i > 0; i--) {
949
3.08M
    *sp1++ = nullptr;
950
3.08M
    *ep++ = nullptr;
951
3.08M
  }
952
96.4k
  if (regmatch(prog + 1)) {
953
1.78k
    start[0] = string;
954
1.78k
    end[0] = reginput;
955
1.78k
    return (1);
956
1.78k
  } else
957
94.7k
    return (0);
958
96.4k
}
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
207M
{
973
207M
  char const* scan; // Current node.
974
207M
  char const* next; // Next node.
975
976
207M
  scan = prog;
977
978
324M
  while (scan) {
979
980
324M
    next = regnext(scan);
981
982
324M
    switch (OP(scan)) {
983
13.5k
      case BOL:
984
13.5k
        if (reginput != regbol)
985
10.4k
          return (0);
986
3.11k
        break;
987
17.7M
      case EOL:
988
17.7M
        if (*reginput != '\0')
989
12.9M
          return (0);
990
4.82M
        break;
991
19.3M
      case ANY:
992
19.3M
        if (*reginput == '\0')
993
4.47M
          return (0);
994
14.8M
        reginput++;
995
14.8M
        break;
996
35.5M
      case EXACTLY: {
997
35.5M
        size_t len;
998
35.5M
        char const* opnd;
999
1000
35.5M
        opnd = OPERAND(scan);
1001
        // Inline the first character, for speed.
1002
35.5M
        if (*opnd != *reginput)
1003
32.8M
          return (0);
1004
2.70M
        len = strlen(opnd);
1005
2.70M
        if (len > 1 && strncmp(opnd, reginput, len) != 0)
1006
536k
          return (0);
1007
2.17M
        reginput += len;
1008
2.17M
      } break;
1009
3.37M
      case ANYOF:
1010
3.37M
        if (*reginput == '\0' || !strchr(OPERAND(scan), *reginput))
1011
2.44M
          return (0);
1012
929k
        reginput++;
1013
929k
        break;
1014
65.0k
      case ANYBUT:
1015
65.0k
        if (*reginput == '\0' || strchr(OPERAND(scan), *reginput))
1016
4.59k
          return (0);
1017
60.5k
        reginput++;
1018
60.5k
        break;
1019
49.3M
      case NOTHING:
1020
49.3M
        break;
1021
7.58M
      case BACK:
1022
7.58M
        break;
1023
1.21M
      case OPEN + 1:
1024
2.40M
      case OPEN + 2:
1025
2.84M
      case OPEN + 3:
1026
4.32M
      case OPEN + 4:
1027
7.91M
      case OPEN + 5:
1028
11.5M
      case OPEN + 6:
1029
15.1M
      case OPEN + 7:
1030
17.0M
      case OPEN + 8:
1031
19.5M
      case OPEN + 9:
1032
21.5M
      case OPEN + 10:
1033
23.0M
      case OPEN + 11:
1034
24.1M
      case OPEN + 12:
1035
26.5M
      case OPEN + 13:
1036
28.4M
      case OPEN + 14:
1037
29.1M
      case OPEN + 15:
1038
30.6M
      case OPEN + 16:
1039
34.1M
      case OPEN + 17:
1040
36.7M
      case OPEN + 18:
1041
38.2M
      case OPEN + 19:
1042
38.7M
      case OPEN + 20:
1043
40.1M
      case OPEN + 21:
1044
41.5M
      case OPEN + 22:
1045
44.2M
      case OPEN + 23:
1046
47.9M
      case OPEN + 24:
1047
51.7M
      case OPEN + 25:
1048
54.6M
      case OPEN + 26:
1049
55.3M
      case OPEN + 27:
1050
55.9M
      case OPEN + 28:
1051
55.9M
      case OPEN + 29:
1052
56.4M
      case OPEN + 30:
1053
56.9M
      case OPEN + 31:
1054
56.9M
      case OPEN + 32: {
1055
56.9M
        int no;
1056
56.9M
        char const* save;
1057
1058
56.9M
        no = OP(scan) - OPEN;
1059
56.9M
        save = reginput;
1060
1061
56.9M
        if (regmatch(next)) {
1062
1063
          //
1064
          // Don't set startp if some later invocation of the
1065
          // same parentheses already has.
1066
          //
1067
374k
          if (!regstartp[no])
1068
3.39k
            regstartp[no] = save;
1069
374k
          return (1);
1070
374k
        } else
1071
56.5M
          return (0);
1072
56.9M
      }
1073
      //              break;
1074
1.19M
      case CLOSE + 1:
1075
2.63M
      case CLOSE + 2:
1076
3.10M
      case CLOSE + 3:
1077
5.76M
      case CLOSE + 4:
1078
9.37M
      case CLOSE + 5:
1079
11.9M
      case CLOSE + 6:
1080
14.5M
      case CLOSE + 7:
1081
15.8M
      case CLOSE + 8:
1082
17.8M
      case CLOSE + 9:
1083
19.1M
      case CLOSE + 10:
1084
20.4M
      case CLOSE + 11:
1085
21.5M
      case CLOSE + 12:
1086
23.9M
      case CLOSE + 13:
1087
25.5M
      case CLOSE + 14:
1088
26.0M
      case CLOSE + 15:
1089
27.2M
      case CLOSE + 16:
1090
30.3M
      case CLOSE + 17:
1091
32.8M
      case CLOSE + 18:
1092
34.3M
      case CLOSE + 19:
1093
34.8M
      case CLOSE + 20:
1094
35.8M
      case CLOSE + 21:
1095
39.5M
      case CLOSE + 22:
1096
39.7M
      case CLOSE + 23:
1097
40.6M
      case CLOSE + 24:
1098
44.2M
      case CLOSE + 25:
1099
46.8M
      case CLOSE + 26:
1100
47.2M
      case CLOSE + 27:
1101
47.7M
      case CLOSE + 28:
1102
47.7M
      case CLOSE + 29:
1103
48.2M
      case CLOSE + 30:
1104
48.6M
      case CLOSE + 31:
1105
48.6M
      case CLOSE + 32: {
1106
48.6M
        int no;
1107
48.6M
        char const* save;
1108
1109
48.6M
        no = OP(scan) - CLOSE;
1110
48.6M
        save = reginput;
1111
1112
48.6M
        if (regmatch(next)) {
1113
1114
          //
1115
          // Don't set endp if some later invocation of the
1116
          // same parentheses already has.
1117
          //
1118
374k
          if (!regendp[no])
1119
3.39k
            regendp[no] = save;
1120
374k
          return (1);
1121
374k
        } else
1122
48.2M
          return (0);
1123
48.6M
      }
1124
      //              break;
1125
83.4M
      case BRANCH: {
1126
1127
83.4M
        char const* save;
1128
1129
83.4M
        if (OP(next) != BRANCH) // No choice.
1130
37.3M
          next = OPERAND(scan); // Avoid recursion.
1131
46.0M
        else {
1132
93.6M
          do {
1133
93.6M
            save = reginput;
1134
93.6M
            if (regmatch(OPERAND(scan)))
1135
372k
              return (1);
1136
93.2M
            reginput = save;
1137
93.2M
            scan = regnext(scan);
1138
93.2M
          } while (scan && OP(scan) == BRANCH);
1139
45.7M
          return (0);
1140
          // NOTREACHED
1141
46.0M
        }
1142
83.4M
      } break;
1143
37.3M
      case STAR:
1144
2.19M
      case PLUS: {
1145
2.19M
        char nextch;
1146
2.19M
        int no;
1147
2.19M
        char const* save;
1148
2.19M
        int min_no;
1149
1150
        //
1151
        // Lookahead to avoid useless match attempts when we know
1152
        // what character comes next.
1153
        //
1154
2.19M
        nextch = '\0';
1155
2.19M
        if (OP(next) == EXACTLY)
1156
1.01M
          nextch = *OPERAND(next);
1157
2.19M
        min_no = (OP(scan) == STAR) ? 0 : 1;
1158
2.19M
        save = reginput;
1159
2.19M
        no = regrepeat(OPERAND(scan));
1160
25.6M
        while (no >= min_no) {
1161
          // If it could work, try it.
1162
23.4M
          if (nextch == '\0' || *reginput == nextch)
1163
7.86M
            if (regmatch(next))
1164
2.63k
              return (1);
1165
          // Couldn't or didn't -- back up.
1166
23.4M
          no--;
1167
23.4M
          reginput = save + no;
1168
23.4M
        }
1169
2.19M
        return (0);
1170
2.19M
      }
1171
      //              break;
1172
1.78k
      case END:
1173
1.78k
        if (reginput == regreject)
1174
0
          return (0); // Can't end a match here
1175
1.78k
        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
324M
    }
1183
117M
    scan = next;
1184
117M
  }
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
207M
}
1194
1195
/*
1196
 - regrepeat - repeatedly match something simple, report how many
1197
 */
1198
int RegExpFind::regrepeat(char const* p)
1199
2.19M
{
1200
2.19M
  int count = 0;
1201
2.19M
  char const* scan;
1202
2.19M
  char const* opnd;
1203
1204
2.19M
  scan = reginput;
1205
2.19M
  opnd = OPERAND(p);
1206
2.19M
  switch (OP(p)) {
1207
1.32M
    case ANY:
1208
1.32M
      count = int(strlen(scan));
1209
1.32M
      scan += count;
1210
1.32M
      break;
1211
711k
    case EXACTLY:
1212
912k
      while (*opnd == *scan) {
1213
200k
        count++;
1214
200k
        scan++;
1215
200k
      }
1216
711k
      break;
1217
122k
    case ANYOF:
1218
482k
      while (*scan != '\0' && strchr(opnd, *scan)) {
1219
360k
        count++;
1220
360k
        scan++;
1221
360k
      }
1222
122k
      break;
1223
39.5k
    case ANYBUT:
1224
93.0k
      while (*scan != '\0' && !strchr(opnd, *scan)) {
1225
53.5k
        count++;
1226
53.5k
        scan++;
1227
53.5k
      }
1228
39.5k
      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
2.19M
  }
1234
2.19M
  reginput = scan;
1235
2.19M
  return (count);
1236
2.19M
}
1237
1238
/*
1239
 - regnext - dig the "next" pointer out of a node
1240
 */
1241
static char const* regnext(char const* p)
1242
417M
{
1243
417M
  int offset;
1244
1245
417M
  if (p == regdummyptr)
1246
0
    return (nullptr);
1247
1248
417M
  offset = NEXT(p);
1249
417M
  if (offset == 0)
1250
2.52k
    return (nullptr);
1251
1252
417M
  if (OP(p) == BACK)
1253
7.58M
    return (p - offset);
1254
410M
  else
1255
410M
    return (p + offset);
1256
417M
}
1257
1258
static char* regnext(char* p)
1259
601k
{
1260
601k
  int offset;
1261
1262
601k
  if (p == regdummyptr)
1263
8.55k
    return (nullptr);
1264
1265
593k
  offset = NEXT(p);
1266
593k
  if (offset == 0)
1267
95.0k
    return (nullptr);
1268
1269
498k
  if (OP(p) == BACK)
1270
0
    return (p - offset);
1271
498k
  else
1272
498k
    return (p + offset);
1273
498k
}
1274
1275
} // namespace KWSYS_NAMESPACE