tools/pcre/pcre_scanner.cc
author David Anderson <dvander@alliedmods.net>
Tue Jul 28 17:51:34 2009 -0400 (2009-07-28)
changeset 2762 d2d467bf1b5a
child 3831 babd0eee3c5e
permissions -rw-r--r--
Check-in of pcre-7.9 source code and win32 static lib (bug 3923).
dvander@2762
     1
// Copyright (c) 2005, Google Inc.
dvander@2762
     2
// All rights reserved.
dvander@2762
     3
//
dvander@2762
     4
// Redistribution and use in source and binary forms, with or without
dvander@2762
     5
// modification, are permitted provided that the following conditions are
dvander@2762
     6
// met:
dvander@2762
     7
//
dvander@2762
     8
//     * Redistributions of source code must retain the above copyright
dvander@2762
     9
// notice, this list of conditions and the following disclaimer.
dvander@2762
    10
//     * Redistributions in binary form must reproduce the above
dvander@2762
    11
// copyright notice, this list of conditions and the following disclaimer
dvander@2762
    12
// in the documentation and/or other materials provided with the
dvander@2762
    13
// distribution.
dvander@2762
    14
//     * Neither the name of Google Inc. nor the names of its
dvander@2762
    15
// contributors may be used to endorse or promote products derived from
dvander@2762
    16
// this software without specific prior written permission.
dvander@2762
    17
//
dvander@2762
    18
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
dvander@2762
    19
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
dvander@2762
    20
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
dvander@2762
    21
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
dvander@2762
    22
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
dvander@2762
    23
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
dvander@2762
    24
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
dvander@2762
    25
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
dvander@2762
    26
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
dvander@2762
    27
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
dvander@2762
    28
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
dvander@2762
    29
//
dvander@2762
    30
// Author: Sanjay Ghemawat
dvander@2762
    31
dvander@2762
    32
#ifdef HAVE_CONFIG_H
dvander@2762
    33
#include "config.h"
dvander@2762
    34
#endif
dvander@2762
    35
dvander@2762
    36
#include <vector>
dvander@2762
    37
#include <assert.h>
dvander@2762
    38
dvander@2762
    39
#include "pcrecpp_internal.h"
dvander@2762
    40
#include "pcre_scanner.h"
dvander@2762
    41
dvander@2762
    42
using std::vector;
dvander@2762
    43
dvander@2762
    44
namespace pcrecpp {
dvander@2762
    45
dvander@2762
    46
Scanner::Scanner()
dvander@2762
    47
  : data_(),
dvander@2762
    48
    input_(data_),
dvander@2762
    49
    skip_(NULL),
dvander@2762
    50
    should_skip_(false),
dvander@2762
    51
    skip_repeat_(false),
dvander@2762
    52
    save_comments_(false),
dvander@2762
    53
    comments_(NULL),
dvander@2762
    54
    comments_offset_(0) {
dvander@2762
    55
}
dvander@2762
    56
dvander@2762
    57
Scanner::Scanner(const string& in)
dvander@2762
    58
  : data_(in),
dvander@2762
    59
    input_(data_),
dvander@2762
    60
    skip_(NULL),
dvander@2762
    61
    should_skip_(false),
dvander@2762
    62
    skip_repeat_(false),
dvander@2762
    63
    save_comments_(false),
dvander@2762
    64
    comments_(NULL),
dvander@2762
    65
    comments_offset_(0) {
dvander@2762
    66
}
dvander@2762
    67
dvander@2762
    68
Scanner::~Scanner() {
dvander@2762
    69
  delete skip_;
dvander@2762
    70
  delete comments_;
dvander@2762
    71
}
dvander@2762
    72
dvander@2762
    73
void Scanner::SetSkipExpression(const char* re) {
dvander@2762
    74
  delete skip_;
dvander@2762
    75
  if (re != NULL) {
dvander@2762
    76
    skip_ = new RE(re);
dvander@2762
    77
    should_skip_ = true;
dvander@2762
    78
    skip_repeat_ = true;
dvander@2762
    79
    ConsumeSkip();
dvander@2762
    80
  } else {
dvander@2762
    81
    skip_ = NULL;
dvander@2762
    82
    should_skip_ = false;
dvander@2762
    83
    skip_repeat_ = false;
dvander@2762
    84
  }
dvander@2762
    85
}
dvander@2762
    86
dvander@2762
    87
void Scanner::Skip(const char* re) {
dvander@2762
    88
  delete skip_;
dvander@2762
    89
  if (re != NULL) {
dvander@2762
    90
    skip_ = new RE(re);
dvander@2762
    91
    should_skip_ = true;
dvander@2762
    92
    skip_repeat_ = false;
dvander@2762
    93
    ConsumeSkip();
dvander@2762
    94
  } else {
dvander@2762
    95
    skip_ = NULL;
dvander@2762
    96
    should_skip_ = false;
dvander@2762
    97
    skip_repeat_ = false;
dvander@2762
    98
  }
dvander@2762
    99
}
dvander@2762
   100
dvander@2762
   101
void Scanner::DisableSkip() {
dvander@2762
   102
  assert(skip_ != NULL);
dvander@2762
   103
  should_skip_ = false;
dvander@2762
   104
}
dvander@2762
   105
dvander@2762
   106
void Scanner::EnableSkip() {
dvander@2762
   107
  assert(skip_ != NULL);
dvander@2762
   108
  should_skip_ = true;
dvander@2762
   109
  ConsumeSkip();
dvander@2762
   110
}
dvander@2762
   111
dvander@2762
   112
int Scanner::LineNumber() const {
dvander@2762
   113
  // TODO: Make it more efficient by keeping track of the last point
dvander@2762
   114
  // where we computed line numbers and counting newlines since then.
dvander@2762
   115
  // We could use std:count, but not all systems have it. :-(
dvander@2762
   116
  int count = 1;
dvander@2762
   117
  for (const char* p = data_.data(); p < input_.data(); ++p)
dvander@2762
   118
    if (*p == '\n')
dvander@2762
   119
      ++count;
dvander@2762
   120
  return count;
dvander@2762
   121
}
dvander@2762
   122
dvander@2762
   123
int Scanner::Offset() const {
dvander@2762
   124
  return input_.data() - data_.c_str();
dvander@2762
   125
}
dvander@2762
   126
dvander@2762
   127
bool Scanner::LookingAt(const RE& re) const {
dvander@2762
   128
  int consumed;
dvander@2762
   129
  return re.DoMatch(input_, RE::ANCHOR_START, &consumed, 0, 0);
dvander@2762
   130
}
dvander@2762
   131
dvander@2762
   132
dvander@2762
   133
bool Scanner::Consume(const RE& re,
dvander@2762
   134
                      const Arg& arg0,
dvander@2762
   135
                      const Arg& arg1,
dvander@2762
   136
                      const Arg& arg2) {
dvander@2762
   137
  const bool result = re.Consume(&input_, arg0, arg1, arg2);
dvander@2762
   138
  if (result && should_skip_) ConsumeSkip();
dvander@2762
   139
  return result;
dvander@2762
   140
}
dvander@2762
   141
dvander@2762
   142
// helper function to consume *skip_ and honour save_comments_
dvander@2762
   143
void Scanner::ConsumeSkip() {
dvander@2762
   144
  const char* start_data = input_.data();
dvander@2762
   145
  while (skip_->Consume(&input_)) {
dvander@2762
   146
    if (!skip_repeat_) {
dvander@2762
   147
      // Only one skip allowed.
dvander@2762
   148
      break;
dvander@2762
   149
    }
dvander@2762
   150
  }
dvander@2762
   151
  if (save_comments_) {
dvander@2762
   152
    if (comments_ == NULL) {
dvander@2762
   153
      comments_ = new vector<StringPiece>;
dvander@2762
   154
    }
dvander@2762
   155
    // already pointing one past end, so no need to +1
dvander@2762
   156
    int length = input_.data() - start_data;
dvander@2762
   157
    if (length > 0) {
dvander@2762
   158
      comments_->push_back(StringPiece(start_data, length));
dvander@2762
   159
    }
dvander@2762
   160
  }
dvander@2762
   161
}
dvander@2762
   162
dvander@2762
   163
dvander@2762
   164
void Scanner::GetComments(int start, int end, vector<StringPiece> *ranges) {
dvander@2762
   165
  // short circuit out if we've not yet initialized comments_
dvander@2762
   166
  // (e.g., when save_comments is false)
dvander@2762
   167
  if (!comments_) {
dvander@2762
   168
    return;
dvander@2762
   169
  }
dvander@2762
   170
  // TODO: if we guarantee that comments_ will contain StringPieces
dvander@2762
   171
  // that are ordered by their start, then we can do a binary search
dvander@2762
   172
  // for the first StringPiece at or past start and then scan for the
dvander@2762
   173
  // ones contained in the range, quit early (use equal_range or
dvander@2762
   174
  // lower_bound)
dvander@2762
   175
  for (vector<StringPiece>::const_iterator it = comments_->begin();
dvander@2762
   176
       it != comments_->end(); ++it) {
dvander@2762
   177
    if ((it->data() >= data_.c_str() + start &&
dvander@2762
   178
         it->data() + it->size() <= data_.c_str() + end)) {
dvander@2762
   179
      ranges->push_back(*it);
dvander@2762
   180
    }
dvander@2762
   181
  }
dvander@2762
   182
}
dvander@2762
   183
dvander@2762
   184
dvander@2762
   185
void Scanner::GetNextComments(vector<StringPiece> *ranges) {
dvander@2762
   186
  // short circuit out if we've not yet initialized comments_
dvander@2762
   187
  // (e.g., when save_comments is false)
dvander@2762
   188
  if (!comments_) {
dvander@2762
   189
    return;
dvander@2762
   190
  }
dvander@2762
   191
  for (vector<StringPiece>::const_iterator it =
dvander@2762
   192
         comments_->begin() + comments_offset_;
dvander@2762
   193
       it != comments_->end(); ++it) {
dvander@2762
   194
    ranges->push_back(*it);
dvander@2762
   195
    ++comments_offset_;
dvander@2762
   196
  }
dvander@2762
   197
}
dvander@2762
   198
dvander@2762
   199
}   // namespace pcrecpp