Coverage Report

Created: 2026-07-14 07:09

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
26.9k
#define END 0   // no   End of program.
200
4.17M
#define BOL 1   // no   Match "" at beginning of line.
201
48.8M
#define EOL 2   // no   Match "" at end of line.
202
25.9M
#define ANY 3   // no   Match any one character.
203
3.32M
#define ANYOF 4 // str  Match any character in this string.
204
#define ANYBUT                                                                \
205
29.2k
  5 // str  Match any character not in this
206
    // string.
207
#define BRANCH                                                                \
208
428M
  6               // node Match this alternative, or the
209
                  // next...
210
718M
#define BACK 7    // no   Match "", "next" ptr points backward.
211
83.7M
#define EXACTLY 8 // str  Match this string.
212
109M
#define NOTHING 9 // no   Match empty string.
213
#define STAR                                                                  \
214
3.74M
  10 // node Match this (simple) thing 0 or more
215
     // times.
216
#define PLUS                                                                  \
217
3.38M
  11 // node Match this (simple) thing 1 or more
218
     // times.
219
#define OPEN                                                                  \
220
823M
  20 // no   Mark this point in input as start of
221
     // #n.
222
// OPEN+1 is number 1, etc.
223
1.07G
#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.67G
#define OP(p) (*(p))
259
716M
#define NEXT(p) (((*((p) + 1) & 0377) << 8) + (*((p) + 2) & 0377))
260
308M
#define OPERAND(p) ((p) + 3)
261
262
unsigned char const MAGIC = 0234;
263
/*
264
 * Utility definitions.
265
 */
266
267
86.0k
#define UCHARAT(p) (reinterpret_cast<const unsigned char*>(p))[0]
268
269
103k
#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
270
26.2k
#define META "^$.[()|?+*\\"
271
272
/*
273
 * Flags to be passed up and down.
274
 */
275
229k
#define HASWIDTH 01 // Known never to match null string.
276
53.4k
#define SIMPLE 02   // Simple enough to be STAR/PLUS operand.
277
78.4k
#define SPSTART 04  // Starts with * or +.
278
124k
#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
2.05k
{
340
2.05k
  char const* scan;
341
2.05k
  char const* longest;
342
2.05k
  int flags;
343
344
2.05k
  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
2.05k
  RegExpCompile comp;
352
2.05k
  comp.regparse = exp;
353
2.05k
  comp.regnpar = 1;
354
2.05k
  comp.regsize = 0L;
355
2.05k
  comp.regcode = regdummyptr;
356
2.05k
  comp.regc(static_cast<char>(MAGIC));
357
2.05k
  if (!comp.reg(0, &flags)) {
358
176
    printf("RegularExpression::compile(): Error in compile.\n");
359
176
    return false;
360
176
  }
361
1.87k
  this->regmatch.clear();
362
363
  // Small enough for pointer-storage convention?
364
1.87k
  if (comp.regsize >= 65535L) {
365
    // RAISE Error, SYM(RegularExpression), SYM(Expr_Too_Big),
366
4
    printf("RegularExpression::compile(): Expression too big.\n");
367
4
    return false;
368
4
  }
369
370
  // Allocate space.
371
  // #ifndef _WIN32
372
1.87k
  delete[] this->program;
373
  // #endif
374
1.87k
  this->program = new char[comp.regsize];
375
1.87k
  this->progsize = static_cast<int>(comp.regsize);
376
1.87k
  this->regnpar = comp.regnpar;
377
378
1.87k
  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.87k
  comp.regparse = exp;
390
1.87k
  comp.regnpar = 1;
391
1.87k
  comp.regcode = this->program;
392
1.87k
  comp.regc(static_cast<char>(MAGIC));
393
1.87k
  comp.reg(0, &flags);
394
395
  // Dig out information for optimizations.
396
1.87k
  this->regstart = '\0'; // Worst-case defaults.
397
1.87k
  this->reganch = 0;
398
1.87k
  this->regmust = nullptr;
399
1.87k
  this->regmlen = 0;
400
1.87k
  scan = this->program + 1;       // First BRANCH.
401
1.87k
  if (OP(regnext(scan)) == END) { // Only one top-level choice.
402
1.76k
    scan = OPERAND(scan);
403
404
    // Starting-point info.
405
1.76k
    if (OP(scan) == EXACTLY)
406
335
      this->regstart = *OPERAND(scan);
407
1.42k
    else if (OP(scan) == BOL)
408
38
      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.76k
    if (flags & SPSTART) {
419
702
      longest = nullptr;
420
702
      size_t len = 0;
421
11.1k
      for (; scan; scan = regnext(scan))
422
10.4k
        if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
423
927
          longest = OPERAND(scan);
424
927
          len = strlen(OPERAND(scan));
425
927
        }
426
702
      this->regmust = longest;
427
702
      this->regmlen = len;
428
702
    }
429
1.76k
  }
430
1.87k
  return true;
431
1.87k
}
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
19.0k
{
444
19.0k
  char* ret;
445
19.0k
  char* br;
446
19.0k
  char* ender;
447
19.0k
  int parno = 0;
448
19.0k
  int flags;
449
450
19.0k
  *flagp = HASWIDTH; // Tentatively.
451
452
  // Make an OPEN node, if parenthesized.
453
19.0k
  if (paren) {
454
15.1k
    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
15.1k
    parno = regnpar;
460
15.1k
    regnpar++;
461
15.1k
    ret = regnode(static_cast<char>(OPEN + parno));
462
15.1k
  } else
463
3.92k
    ret = nullptr;
464
465
  // Pick up the branches, linking them together.
466
19.0k
  br = regbranch(&flags);
467
19.0k
  if (!br)
468
381
    return (nullptr);
469
18.6k
  if (ret)
470
14.8k
    regtail(ret, br); // OPEN -> first.
471
3.78k
  else
472
3.78k
    ret = br;
473
18.6k
  if (!(flags & HASWIDTH))
474
12.1k
    *flagp &= ~HASWIDTH;
475
18.6k
  *flagp |= flags & SPSTART;
476
29.5k
  while (*regparse == '|') {
477
11.0k
    regparse++;
478
11.0k
    br = regbranch(&flags);
479
11.0k
    if (!br)
480
98
      return (nullptr);
481
10.9k
    regtail(ret, br); // BRANCH -> BRANCH.
482
10.9k
    if (!(flags & HASWIDTH))
483
5.34k
      *flagp &= ~HASWIDTH;
484
10.9k
    *flagp |= flags & SPSTART;
485
10.9k
  }
486
487
  // Make a closing node, and hook it on the end.
488
18.5k
  ender = regnode(static_cast<char>((paren) ? CLOSE + parno : END));
489
18.5k
  regtail(ret, ender);
490
491
  // Hook the tails of the branches to the closing node.
492
58.9k
  for (br = ret; br; br = regnext(br))
493
40.3k
    regoptail(br, ender);
494
495
  // Check for proper termination.
496
18.5k
  if (paren && *regparse++ != ')') {
497
    // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens),
498
44
    printf("RegularExpression::compile(): Unmatched parentheses.\n");
499
44
    return nullptr;
500
18.5k
  } else if (!paren && *regparse != '\0') {
501
16
    if (*regparse == ')') {
502
      // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens),
503
16
      printf("RegularExpression::compile(): Unmatched parentheses.\n");
504
16
      return nullptr;
505
16
    } 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
16
  }
512
18.4k
  return (ret);
513
18.5k
}
514
515
/*
516
 - regbranch - one alternative of an | operator
517
 *
518
 * Implements the concatenation operator.
519
 */
520
char* RegExpCompile::regbranch(int* flagp)
521
30.0k
{
522
30.0k
  char* ret;
523
30.0k
  char* chain;
524
30.0k
  char* latest;
525
30.0k
  int flags;
526
527
30.0k
  *flagp = WORST; // Tentatively.
528
529
30.0k
  ret = regnode(BRANCH);
530
30.0k
  chain = nullptr;
531
102k
  while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
532
72.8k
    latest = regpiece(&flags);
533
72.8k
    if (!latest)
534
479
      return (nullptr);
535
72.3k
    *flagp |= flags & HASWIDTH;
536
72.3k
    if (!chain) // First piece.
537
17.0k
      *flagp |= flags & SPSTART;
538
55.3k
    else
539
55.3k
      regtail(chain, latest);
540
72.3k
    chain = latest;
541
72.3k
  }
542
29.5k
  if (!chain) // Loop ran zero times.
543
12.6k
    regnode(NOTHING);
544
545
29.5k
  return (ret);
546
30.0k
}
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
72.8k
{
559
72.8k
  char* ret;
560
72.8k
  char op;
561
72.8k
  char* next;
562
72.8k
  int flags;
563
564
72.8k
  ret = regatom(&flags);
565
72.8k
  if (!ret)
566
468
    return (nullptr);
567
568
72.3k
  op = *regparse;
569
72.3k
  if (!ISMULT(op)) {
570
50.8k
    *flagp = flags;
571
50.8k
    return (ret);
572
50.8k
  }
573
574
21.5k
  if (!(flags & HASWIDTH) && op != '?') {
575
    // RAISE Error, SYM(RegularExpression), SYM(Empty_Operand),
576
3
    printf("RegularExpression::compile() : *+ operand could be empty.\n");
577
3
    return nullptr;
578
3
  }
579
21.5k
  *flagp = (op != '+') ? (WORST | SPSTART) : (WORST | HASWIDTH);
580
581
21.5k
  if (op == '*' && (flags & SIMPLE))
582
6.00k
    reginsert(STAR, ret);
583
15.5k
  else if (op == '*') {
584
    // Emit x* as (x&|), where & means "self".
585
1.02k
    reginsert(BRANCH, ret);         // Either x
586
1.02k
    regoptail(ret, regnode(BACK));  // and loop
587
1.02k
    regoptail(ret, ret);            // back
588
1.02k
    regtail(ret, regnode(BRANCH));  // or
589
1.02k
    regtail(ret, regnode(NOTHING)); // null.
590
14.5k
  } else if (op == '+' && (flags & SIMPLE))
591
5.46k
    reginsert(PLUS, ret);
592
9.03k
  else if (op == '+') {
593
    // Emit x+ as x(&|), where & means "self".
594
663
    next = regnode(BRANCH); // Either
595
663
    regtail(ret, next);
596
663
    regtail(regnode(BACK), ret);    // loop back
597
663
    regtail(next, regnode(BRANCH)); // or
598
663
    regtail(ret, regnode(NOTHING)); // null.
599
8.37k
  } else if (op == '?') {
600
    // Emit x? as (x|)
601
8.37k
    reginsert(BRANCH, ret);        // Either x
602
8.37k
    regtail(ret, regnode(BRANCH)); // or
603
8.37k
    next = regnode(NOTHING);       // null.
604
8.37k
    regtail(ret, next);
605
8.37k
    regoptail(ret, next);
606
8.37k
  }
607
21.5k
  regparse++;
608
21.5k
  if (ISMULT(*regparse)) {
609
    // RAISE Error, SYM(RegularExpression), SYM(Nested_Operand),
610
8
    printf("RegularExpression::compile(): Nested *?+.\n");
611
8
    return nullptr;
612
8
  }
613
21.5k
  return (ret);
614
21.5k
}
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
72.8k
{
626
72.8k
  char* ret;
627
72.8k
  int flags;
628
629
72.8k
  *flagp = WORST; // Tentatively.
630
631
72.8k
  switch (*regparse++) {
632
5.34k
    case '^':
633
5.34k
      ret = regnode(BOL);
634
5.34k
      break;
635
3.63k
    case '$':
636
3.63k
      ret = regnode(EOL);
637
3.63k
      break;
638
7.16k
    case '.':
639
7.16k
      ret = regnode(ANY);
640
7.16k
      *flagp |= HASWIDTH | SIMPLE;
641
7.16k
      break;
642
13.6k
    case '[': {
643
13.6k
      int rxpclass;
644
13.6k
      int rxpclassend;
645
646
13.6k
      if (*regparse == '^') { // Complement of range.
647
1.64k
        ret = regnode(ANYBUT);
648
1.64k
        regparse++;
649
1.64k
      } else
650
12.0k
        ret = regnode(ANYOF);
651
13.6k
      if (*regparse == ']' || *regparse == '-')
652
2.42k
        regc(*regparse++);
653
162k
      while (*regparse != '\0' && *regparse != ']') {
654
148k
        if (*regparse == '-') {
655
39.7k
          regparse++;
656
39.7k
          if (*regparse == ']' || *regparse == '\0')
657
788
            regc('-');
658
39.0k
          else {
659
39.0k
            rxpclass = UCHARAT(regparse - 2) + 1;
660
39.0k
            rxpclassend = UCHARAT(regparse);
661
39.0k
            if (rxpclass > rxpclassend + 1) {
662
              // RAISE Error, SYM(RegularExpression), SYM(Invalid_Range),
663
10
              printf("RegularExpression::compile(): Invalid range in [].\n");
664
10
              return nullptr;
665
10
            }
666
6.45M
            for (; rxpclass <= rxpclassend; rxpclass++)
667
6.41M
              regc(static_cast<char>(rxpclass));
668
38.9k
            regparse++;
669
38.9k
          }
670
39.7k
        } else
671
108k
          regc(*regparse++);
672
148k
      }
673
13.6k
      regc('\0');
674
13.6k
      if (*regparse != ']') {
675
        // RAISE Error, SYM(RegularExpression), SYM(Unmatched_Bracket),
676
71
        printf("RegularExpression::compile(): Unmatched [].\n");
677
71
        return nullptr;
678
71
      }
679
13.5k
      regparse++;
680
13.5k
      *flagp |= HASWIDTH | SIMPLE;
681
13.5k
    } break;
682
15.1k
    case '(':
683
15.1k
      ret = reg(1, &flags);
684
15.1k
      if (!ret)
685
368
        return (nullptr);
686
14.7k
      *flagp |= flags & (HASWIDTH | SPSTART);
687
14.7k
      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
4
    case '?':
695
7
    case '+':
696
11
    case '*':
697
      // RAISE Error, SYM(RegularExpression), SYM(No_Operand),
698
11
      printf("RegularExpression::compile(): ?+* follows nothing.\n");
699
11
      return nullptr;
700
1.62k
    case '\\':
701
1.62k
      if (*regparse == '\0') {
702
        // RAISE Error, SYM(RegularExpression), SYM(Trailing_Backslash),
703
8
        printf("RegularExpression::compile(): Trailing backslash.\n");
704
8
        return nullptr;
705
8
      }
706
1.61k
      ret = regnode(EXACTLY);
707
1.61k
      regc(*regparse++);
708
1.61k
      regc('\0');
709
1.61k
      *flagp |= HASWIDTH | SIMPLE;
710
1.61k
      break;
711
26.2k
    default: {
712
26.2k
      int len;
713
26.2k
      char ender;
714
715
26.2k
      regparse--;
716
26.2k
      len = int(strcspn(regparse, META));
717
26.2k
      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
26.2k
      ender = *(regparse + len);
723
26.2k
      if (len > 1 && ISMULT(ender))
724
2.56k
        len--; // Back off clear of ?+* operand.
725
26.2k
      *flagp |= HASWIDTH;
726
26.2k
      if (len == 1)
727
17.9k
        *flagp |= SIMPLE;
728
26.2k
      ret = regnode(EXACTLY);
729
194k
      while (len > 0) {
730
167k
        regc(*regparse++);
731
167k
        len--;
732
167k
      }
733
26.2k
      regc('\0');
734
26.2k
    } break;
735
72.8k
  }
736
72.3k
  return (ret);
737
72.8k
}
738
739
/*
740
 - regnode - emit a node
741
   Location.
742
 */
743
char* RegExpCompile::regnode(char op)
744
156k
{
745
156k
  char* ret;
746
156k
  char* ptr;
747
748
156k
  ret = regcode;
749
156k
  if (ret == regdummyptr) {
750
80.4k
    regsize += 3;
751
80.4k
    return (ret);
752
80.4k
  }
753
754
76.0k
  ptr = ret;
755
76.0k
  *ptr++ = op;
756
76.0k
  *ptr++ = '\0'; // Null "next" pointer.
757
76.0k
  *ptr++ = '\0';
758
76.0k
  regcode = ptr;
759
760
76.0k
  return (ret);
761
156k
}
762
763
/*
764
 - regc - emit (if appropriate) a byte of code
765
 */
766
void RegExpCompile::regc(char b)
767
6.74M
{
768
6.74M
  if (regcode != regdummyptr)
769
3.21M
    *regcode++ = b;
770
3.52M
  else
771
3.52M
    regsize++;
772
6.74M
}
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
20.8k
{
781
20.8k
  char* src;
782
20.8k
  char* dst;
783
20.8k
  char* place;
784
785
20.8k
  if (regcode == regdummyptr) {
786
10.7k
    regsize += 3;
787
10.7k
    return;
788
10.7k
  }
789
790
10.1k
  src = regcode;
791
10.1k
  regcode += 3;
792
10.1k
  dst = regcode;
793
4.11M
  while (src > opnd)
794
4.10M
    *--dst = *--src;
795
796
10.1k
  place = opnd; // Op node, where operand used to be.
797
10.1k
  *place++ = op;
798
10.1k
  *place++ = '\0';
799
10.1k
  *place = '\0';
800
10.1k
}
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
140k
{
807
140k
  char* scan;
808
140k
  char* temp;
809
140k
  int offset;
810
811
140k
  if (p == regdummyptr)
812
62.0k
    return;
813
814
  // Find last node.
815
78.8k
  scan = p;
816
519k
  for (;;) {
817
519k
    temp = regnext(scan);
818
519k
    if (!temp)
819
78.8k
      break;
820
440k
    scan = temp;
821
440k
  }
822
823
78.8k
  if (OP(scan) == BACK)
824
823
    offset = int(scan - val);
825
77.9k
  else
826
77.9k
    offset = int(val - scan);
827
78.8k
  *(scan + 1) = static_cast<char>((offset >> 8) & 0377);
828
78.8k
  *(scan + 2) = static_cast<char>(offset & 0377);
829
78.8k
}
830
831
/*
832
 - regoptail - regtail on operand of first argument; nop if operandless
833
 */
834
void RegExpCompile::regoptail(char* p, char const* val)
835
50.7k
{
836
  // "Operandless" and "op != BRANCH" are synonymous in practice.
837
50.7k
  if (!p || p == regdummyptr || OP(p) != BRANCH)
838
31.0k
    return;
839
19.6k
  regtail(OPERAND(p), val);
840
19.6k
}
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
8.00k
{
872
8.00k
  char const* s;
873
874
8.00k
  rmatch.clear();
875
8.00k
  rmatch.searchstring = string;
876
877
8.00k
  if (!this->program) {
878
0
    return false;
879
0
  }
880
881
  // Check validity of program.
882
8.00k
  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
8.00k
  if (this->regmust) {
891
957
    s = string + offset;
892
2.74k
    while ((s = strchr(s, this->regmust[0]))) {
893
2.13k
      if (strncmp(s, this->regmust, this->regmlen) == 0)
894
344
        break; // Found it.
895
1.78k
      s++;
896
1.78k
    }
897
957
    if (!s) // Not present.
898
613
      return false;
899
957
  }
900
901
7.39k
  RegExpFind regFind;
902
7.39k
  s = string + offset;
903
904
  // Mark beginning of line for ^ .
905
7.39k
  regFind.regbol = (options & BOL_AT_OFFSET) ? s : string;
906
7.39k
  regFind.regreject = (options & NONEMPTY_AT_OFFSET) ? s : nullptr;
907
908
  // Simplest case:  anchored match need be tried only once.
909
7.39k
  if (this->reganch)
910
2.55k
    return (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program) != 0);
911
912
  // Messy cases:  unanchored match.
913
4.84k
  if (this->regstart != '\0')
914
    // We know what char it must start with.
915
3.01k
    while ((s = strchr(s, this->regstart))) {
916
2.23k
      if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program))
917
177
        return true;
918
2.05k
      s++;
919
2.05k
    }
920
3.88k
  else
921
    // We don't -- general case.
922
75.3k
    do {
923
75.3k
      if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program))
924
2.47k
        return true;
925
75.3k
    } while (*s++ != '\0');
926
927
  // Failure.
928
2.19k
  return false;
929
4.84k
}
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
80.1k
{
938
80.1k
  int i;
939
80.1k
  char const** sp1;
940
80.1k
  char const** ep;
941
942
80.1k
  reginput = string;
943
80.1k
  regstartp = start;
944
80.1k
  regendp = end;
945
946
80.1k
  sp1 = start;
947
80.1k
  ep = end;
948
2.64M
  for (i = RegularExpressionMatch::NSUBEXP; i > 0; i--) {
949
2.56M
    *sp1++ = nullptr;
950
2.56M
    *ep++ = nullptr;
951
2.56M
  }
952
80.1k
  if (regmatch(prog + 1)) {
953
2.72k
    start[0] = string;
954
2.72k
    end[0] = reginput;
955
2.72k
    return (1);
956
2.72k
  } else
957
77.4k
    return (0);
958
80.1k
}
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
334M
{
973
334M
  char const* scan; // Current node.
974
334M
  char const* next; // Next node.
975
976
334M
  scan = prog;
977
978
510M
  while (scan) {
979
980
510M
    next = regnext(scan);
981
982
510M
    switch (OP(scan)) {
983
4.16M
      case BOL:
984
4.16M
        if (reginput != regbol)
985
4.15M
          return (0);
986
6.99k
        break;
987
48.8M
      case EOL:
988
48.8M
        if (*reginput != '\0')
989
230k
          return (0);
990
48.5M
        break;
991
48.5M
      case ANY:
992
25.8M
        if (*reginput == '\0')
993
23.2M
          return (0);
994
2.56M
        reginput++;
995
2.56M
        break;
996
80.2M
      case EXACTLY: {
997
80.2M
        size_t len;
998
80.2M
        char const* opnd;
999
1000
80.2M
        opnd = OPERAND(scan);
1001
        // Inline the first character, for speed.
1002
80.2M
        if (*opnd != *reginput)
1003
79.8M
          return (0);
1004
367k
        len = strlen(opnd);
1005
367k
        if (len > 1 && strncmp(opnd, reginput, len) != 0)
1006
89.9k
          return (0);
1007
277k
        reginput += len;
1008
277k
      } break;
1009
169k
      case ANYOF:
1010
169k
        if (*reginput == '\0' || !strchr(OPERAND(scan), *reginput))
1011
117k
          return (0);
1012
51.7k
        reginput++;
1013
51.7k
        break;
1014
4.33k
      case ANYBUT:
1015
4.33k
        if (*reginput == '\0' || strchr(OPERAND(scan), *reginput))
1016
1.48k
          return (0);
1017
2.85k
        reginput++;
1018
2.85k
        break;
1019
109M
      case NOTHING:
1020
109M
        break;
1021
2.18M
      case BACK:
1022
2.18M
        break;
1023
2.20M
      case OPEN + 1:
1024
4.37M
      case OPEN + 2:
1025
6.54M
      case OPEN + 3:
1026
8.71M
      case OPEN + 4:
1027
10.9M
      case OPEN + 5:
1028
13.1M
      case OPEN + 6:
1029
15.2M
      case OPEN + 7:
1030
15.3M
      case OPEN + 8:
1031
15.4M
      case OPEN + 9:
1032
15.5M
      case OPEN + 10:
1033
15.7M
      case OPEN + 11:
1034
15.9M
      case OPEN + 12:
1035
16.3M
      case OPEN + 13:
1036
17.0M
      case OPEN + 14:
1037
17.7M
      case OPEN + 15:
1038
18.7M
      case OPEN + 16:
1039
19.7M
      case OPEN + 17:
1040
20.8M
      case OPEN + 18:
1041
22.2M
      case OPEN + 19:
1042
23.6M
      case OPEN + 20:
1043
25.8M
      case OPEN + 21:
1044
28.6M
      case OPEN + 22:
1045
31.5M
      case OPEN + 23:
1046
37.0M
      case OPEN + 24:
1047
37.5M
      case OPEN + 25:
1048
38.2M
      case OPEN + 26:
1049
39.2M
      case OPEN + 27:
1050
40.8M
      case OPEN + 28:
1051
43.7M
      case OPEN + 29:
1052
48.2M
      case OPEN + 30:
1053
52.4M
      case OPEN + 31:
1054
52.4M
      case OPEN + 32: {
1055
52.4M
        int no;
1056
52.4M
        char const* save;
1057
1058
52.4M
        no = OP(scan) - OPEN;
1059
52.4M
        save = reginput;
1060
1061
52.4M
        if (regmatch(next)) {
1062
1063
          //
1064
          // Don't set startp if some later invocation of the
1065
          // same parentheses already has.
1066
          //
1067
323k
          if (!regstartp[no])
1068
8.86k
            regstartp[no] = save;
1069
323k
          return (1);
1070
323k
        } else
1071
52.1M
          return (0);
1072
52.4M
      }
1073
      //              break;
1074
2.24M
      case CLOSE + 1:
1075
4.44M
      case CLOSE + 2:
1076
6.59M
      case CLOSE + 3:
1077
8.76M
      case CLOSE + 4:
1078
10.9M
      case CLOSE + 5:
1079
15.2M
      case CLOSE + 6:
1080
17.4M
      case CLOSE + 7:
1081
17.4M
      case CLOSE + 8:
1082
17.5M
      case CLOSE + 9:
1083
17.7M
      case CLOSE + 10:
1084
18.0M
      case CLOSE + 11:
1085
18.3M
      case CLOSE + 12:
1086
19.0M
      case CLOSE + 13:
1087
19.7M
      case CLOSE + 14:
1088
20.7M
      case CLOSE + 15:
1089
21.8M
      case CLOSE + 16:
1090
22.8M
      case CLOSE + 17:
1091
24.2M
      case CLOSE + 18:
1092
25.6M
      case CLOSE + 19:
1093
27.8M
      case CLOSE + 20:
1094
30.6M
      case CLOSE + 21:
1095
36.1M
      case CLOSE + 22:
1096
41.7M
      case CLOSE + 23:
1097
52.6M
      case CLOSE + 24:
1098
53.3M
      case CLOSE + 25:
1099
54.3M
      case CLOSE + 26:
1100
56.0M
      case CLOSE + 27:
1101
58.9M
      case CLOSE + 28:
1102
63.9M
      case CLOSE + 29:
1103
68.5M
      case CLOSE + 30:
1104
72.6M
      case CLOSE + 31:
1105
72.6M
      case CLOSE + 32: {
1106
72.6M
        int no;
1107
72.6M
        char const* save;
1108
1109
72.6M
        no = OP(scan) - CLOSE;
1110
72.6M
        save = reginput;
1111
1112
72.6M
        if (regmatch(next)) {
1113
1114
          //
1115
          // Don't set endp if some later invocation of the
1116
          // same parentheses already has.
1117
          //
1118
323k
          if (!regendp[no])
1119
8.86k
            regendp[no] = save;
1120
323k
          return (1);
1121
323k
        } else
1122
72.3M
          return (0);
1123
72.6M
      }
1124
      //              break;
1125
111M
      case BRANCH: {
1126
1127
111M
        char const* save;
1128
1129
111M
        if (OP(next) != BRANCH) // No choice.
1130
13.1M
          next = OPERAND(scan); // Avoid recursion.
1131
98.4M
        else {
1132
205M
          do {
1133
205M
            save = reginput;
1134
205M
            if (regmatch(OPERAND(scan)))
1135
561k
              return (1);
1136
205M
            reginput = save;
1137
205M
            scan = regnext(scan);
1138
205M
          } while (scan && OP(scan) == BRANCH);
1139
97.8M
          return (0);
1140
          // NOTREACHED
1141
98.4M
        }
1142
111M
      } break;
1143
13.1M
      case STAR:
1144
3.38M
      case PLUS: {
1145
3.38M
        char nextch;
1146
3.38M
        int no;
1147
3.38M
        char const* save;
1148
3.38M
        int min_no;
1149
1150
        //
1151
        // Lookahead to avoid useless match attempts when we know
1152
        // what character comes next.
1153
        //
1154
3.38M
        nextch = '\0';
1155
3.38M
        if (OP(next) == EXACTLY)
1156
2.23M
          nextch = *OPERAND(next);
1157
3.38M
        min_no = (OP(scan) == STAR) ? 0 : 1;
1158
3.38M
        save = reginput;
1159
3.38M
        no = regrepeat(OPERAND(scan));
1160
25.3M
        while (no >= min_no) {
1161
          // If it could work, try it.
1162
21.9M
          if (nextch == '\0' || *reginput == nextch)
1163
3.60M
            if (regmatch(next))
1164
4.22k
              return (1);
1165
          // Couldn't or didn't -- back up.
1166
21.9M
          no--;
1167
21.9M
          reginput = save + no;
1168
21.9M
        }
1169
3.37M
        return (0);
1170
3.38M
      }
1171
      //              break;
1172
2.72k
      case END:
1173
2.72k
        if (reginput == regreject)
1174
0
          return (0); // Can't end a match here
1175
2.72k
        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
510M
    }
1183
175M
    scan = next;
1184
175M
  }
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
334M
}
1194
1195
/*
1196
 - regrepeat - repeatedly match something simple, report how many
1197
 */
1198
int RegExpFind::regrepeat(char const* p)
1199
3.38M
{
1200
3.38M
  int count = 0;
1201
3.38M
  char const* scan;
1202
3.38M
  char const* opnd;
1203
1204
3.38M
  scan = reginput;
1205
3.38M
  opnd = OPERAND(p);
1206
3.38M
  switch (OP(p)) {
1207
102k
    case ANY:
1208
102k
      count = int(strlen(scan));
1209
102k
      scan += count;
1210
102k
      break;
1211
117k
    case EXACTLY:
1212
130k
      while (*opnd == *scan) {
1213
13.3k
        count++;
1214
13.3k
        scan++;
1215
13.3k
      }
1216
117k
      break;
1217
3.13M
    case ANYOF:
1218
6.75M
      while (*scan != '\0' && strchr(opnd, *scan)) {
1219
3.62M
        count++;
1220
3.62M
        scan++;
1221
3.62M
      }
1222
3.13M
      break;
1223
23.3k
    case ANYBUT:
1224
26.2k
      while (*scan != '\0' && !strchr(opnd, *scan)) {
1225
2.93k
        count++;
1226
2.93k
        scan++;
1227
2.93k
      }
1228
23.3k
      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
3.38M
  }
1234
3.38M
  reginput = scan;
1235
3.38M
  return (count);
1236
3.38M
}
1237
1238
/*
1239
 - regnext - dig the "next" pointer out of a node
1240
 */
1241
static char const* regnext(char const* p)
1242
715M
{
1243
715M
  int offset;
1244
1245
715M
  if (p == regdummyptr)
1246
0
    return (nullptr);
1247
1248
715M
  offset = NEXT(p);
1249
715M
  if (offset == 0)
1250
3.42k
    return (nullptr);
1251
1252
715M
  if (OP(p) == BACK)
1253
2.18M
    return (p - offset);
1254
713M
  else
1255
713M
    return (p + offset);
1256
715M
}
1257
1258
static char* regnext(char* p)
1259
560k
{
1260
560k
  int offset;
1261
1262
560k
  if (p == regdummyptr)
1263
9.39k
    return (nullptr);
1264
1265
550k
  offset = NEXT(p);
1266
550k
  if (offset == 0)
1267
87.9k
    return (nullptr);
1268
1269
462k
  if (OP(p) == BACK)
1270
0
    return (p - offset);
1271
462k
  else
1272
462k
    return (p + offset);
1273
462k
}
1274
1275
} // namespace KWSYS_NAMESPACE