sedAddress.cxx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Filename: sedAddress.cxx
  2. // Created by: drose (24Oct00)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. #include "sedAddress.h"
  6. #include "sedContext.h"
  7. #include <stdlib.h>
  8. #include <ctype.h>
  9. #include <assert.h>
  10. ////////////////////////////////////////////////////////////////////
  11. // Function: SedAddress::Constructor
  12. // Access: Public
  13. // Description:
  14. ////////////////////////////////////////////////////////////////////
  15. SedAddress::
  16. SedAddress() {
  17. _address_type = AT_invalid;
  18. }
  19. ////////////////////////////////////////////////////////////////////
  20. // Function: SedAddress::Destructor
  21. // Access: Public
  22. // Description:
  23. ////////////////////////////////////////////////////////////////////
  24. SedAddress::
  25. ~SedAddress() {
  26. if (_address_type == AT_re) {
  27. regfree(&_re);
  28. }
  29. }
  30. ////////////////////////////////////////////////////////////////////
  31. // Function: SedAddress::parse_address
  32. // Access: Public
  33. // Description: Scans the indicated string beginning at the indicated
  34. // character position for an address specification,
  35. // e.g. a number, $, or a regular expression. If a
  36. // correct address is found, increments p to the first
  37. // non-whitespace character past it and returns true;
  38. // otherwise, returns false.
  39. ////////////////////////////////////////////////////////////////////
  40. bool SedAddress::
  41. parse_address(const string &line, size_t &p) {
  42. assert(p < line.length());
  43. if (line[p] == '$') {
  44. p++;
  45. _address_type = AT_last;
  46. } else if (isdigit(line[p])) {
  47. const char *str = line.c_str() + p;
  48. char *end;
  49. _number = strtol(str, &end, 10);
  50. _address_type = AT_numeric;
  51. p += (end - str);
  52. } else {
  53. // It must be a regular expression.
  54. size_t p0 = p;
  55. char delimiter = line[p];
  56. p++;
  57. if (p < line.length() && delimiter == '\\') {
  58. // A backslash might escape the opening character.
  59. delimiter = line[p];
  60. p++;
  61. }
  62. size_t begin = p;
  63. while (p < line.length() && line[p] != delimiter) {
  64. if (line[p] == '\\') {
  65. p++;
  66. // A backslash could escape the closing character.
  67. }
  68. p++;
  69. }
  70. if (p >= line.length()) {
  71. cerr << "Could not find terminating character '" << delimiter
  72. << "' in regular expression: " << line.substr(p0) << "\n";
  73. return false;
  74. }
  75. string re = line.substr(begin, p - begin);
  76. p++;
  77. int error = regcomp(&_re, re.c_str(), REG_NOSUB);
  78. if (error != 0) {
  79. static const int errbuf_size = 512;
  80. char errbuf[errbuf_size];
  81. regerror(error, &_re, errbuf, errbuf_size);
  82. cerr << "Invalid regular expression: " << re << "\n"
  83. << errbuf << "\n";
  84. return false;
  85. }
  86. _address_type = AT_re;
  87. }
  88. // Skip whitespace following the address.
  89. while (p < line.length() && isspace(line[p])) {
  90. p++;
  91. }
  92. return true;
  93. }
  94. ////////////////////////////////////////////////////////////////////
  95. // Function: SedAddress::matches
  96. // Access: Public
  97. // Description: Returns true if this address exactly matches the
  98. // current pattern space.
  99. ////////////////////////////////////////////////////////////////////
  100. bool SedAddress::
  101. matches(const SedContext &context) const {
  102. switch (_address_type) {
  103. case AT_invalid:
  104. cerr << "Internal error!\n";
  105. assert(false);
  106. return false;
  107. case AT_numeric:
  108. return (_number == context._line_number);
  109. case AT_last:
  110. return context._is_last_line;
  111. case AT_re:
  112. return (regexec(&_re, context._pattern_space.c_str(), 0, (regmatch_t *)NULL, 0) == 0);
  113. }
  114. return false;
  115. }
  116. ////////////////////////////////////////////////////////////////////
  117. // Function: SedAddress::precedes
  118. // Access: Public
  119. // Description: Returns true if this address exactly matches the
  120. // current line or refers to a previous line. This
  121. // never returns true if the address is a regular
  122. // expression type.
  123. ////////////////////////////////////////////////////////////////////
  124. bool SedAddress::
  125. precedes(const SedContext &context) const {
  126. if (_address_type == AT_numeric) {
  127. return (_number <= context._line_number);
  128. }
  129. return false;
  130. }