Regexp.cpp
上传用户:dzyhzl
上传日期:2019-04-29
资源大小:56270k
文件大小:45k
源码类别:

模拟服务器

开发平台:

C/C++

  1. // Win32 porting notes.
  2. #if defined( _MBCS )
  3. //#pragma message( __FILEINFO__ "This code is broken under _MBCS, " 
  4. //  "see the comments at the top of this file." )
  5. #endif //_MBCS
  6. //
  7. //
  8. // In case this isn't obvious from the later comments this is an ALTERED
  9. // version of the software. If you like my changes then cool, but nearly
  10. // all of the functionality here is derived from Henry Spencer's original
  11. // work.
  12. //
  13. // This code should work correctly under both _SBCS and _UNICODE, I did
  14. // start working on making it work with _MBCS but gave up after a while
  15. // since I don't need this particular port and it's not going to be as
  16. // straight forward as the other two.
  17. //
  18. // The problem stems from the compiled program being stored as TCHARS,
  19. // the individual items need to be wide enough to hold whatever character
  20. // is thrown at them, but currently they are accessed as an array of
  21. // whatever size integral type is appropriate.  _MBCS would cause this
  22. // to be char, but at times it would need to be larger.  This would
  23. // require making the program be an array of short with the appropriate
  24. // conversions used everywhere.  Certainly it's doable, but it's a pain.
  25. // What's worse is that the current code will compile and run under _MBCS,
  26. // only breaking when it gets wide characters thrown against it.
  27. //
  28. // I've marked at least one bit of code with #pragma messages, I may not
  29. // get all of them, but they should be a start
  30. //
  31. // Guy Gascoigne - Piggford (ggp@bigfoot.com) Friday, February 27, 1998
  32. // regcomp and regexec -- regsub and regerror are elsewhere
  33. // @(#)regexp.c 1.3 of 18 April 87
  34. //
  35. // Copyright (c) 1986 by University of Toronto.
  36. // Written by Henry Spencer.  Not derived from licensed software.
  37. //
  38. // Permission is granted to anyone to use this software for any
  39. // purpose on any computer system, and to redistribute it freely,
  40. // subject to the following restrictions:
  41. //
  42. // 1. The author is not responsible for the consequences of use of
  43. // this software, no matter how awful, even if they arise
  44. // from defects in it.
  45. //
  46. // 2. The origin of this software must not be misrepresented, either
  47. // by explicit claim or by omission.
  48. //
  49. // 3. Altered versions must be plainly marked as such, and must not
  50. // be misrepresented as being the original software.
  51. // *** THIS IS AN ALTERED VERSION.  It was altered by John Gilmore,
  52. // *** hoptoad!gnu, on 27 Dec 1986, to add < and > for word-matching
  53. // *** as in BSD grep and ex.
  54. // *** THIS IS AN ALTERED VERSION.  It was altered by John Gilmore,
  55. // *** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with .
  56. // *** THIS IS AN ALTERED VERSION.  It was altered by James A. Woods,
  57. // *** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy.
  58. // *** THIS IS AN ALTERED VERSION.  It was altered by Geoffrey Noer,
  59. // *** THIS IS AN ALTERED VERSION.  It was altered by Guy Gascoigne - Piggford
  60. // *** guy@wyrdrune.com, on 15 March 1998, porting it to C++ and converting
  61. // *** it to be the engine for the Regexp class
  62. //
  63. // Beware that some of this code is subtly aware of the way operator
  64. // precedence is structured in regular expressions.  Serious changes in
  65. // regular-expression syntax might require a total rethink.
  66. #include "stdafx.h"
  67. #include "regexp.h"
  68. #include "malloc.h"
  69. // The first byte of the regexp internal "program" is actually this magic
  70. // number; the start node begins in the second byte.
  71. const TCHAR MAGIC = ((TCHAR)'234');
  72. //#define new DEBUG_NEW
  73. #pragma warning( disable : 4711 ) // automatic inline selected
  74. // The "internal use only" fields in regexp.h are present to pass info from
  75. // compile to execute that permits the execute phase to run lots faster on
  76. // simple cases.  They are:
  77. //
  78. // regstart char that must begin a match; '' if none obvious
  79. // reganch is the match anchored (at beginning-of-line only)?
  80. // regmust string (pointer into program) that match must include, or NULL
  81. // regmlen length of regmust string
  82. //
  83. // Regstart and reganch permit very fast decisions on suitable starting
  84. // points for a match, cutting down the work a lot.  Regmust permits fast
  85. // rejection of lines that cannot possibly match.  The regmust tests are
  86. // costly enough that regcomp() supplies a regmust only if the
  87. // r.e. contains something potentially expensive (at present, the only
  88. // such thing detected is * or + at the start of the r.e., which can
  89. // involve a lot of backup).  Regmlen is supplied because the test in
  90. // regexec() needs it and regcomp() is computing it anyway.
  91. // Structure for regexp "program".  This is essentially a linear encoding
  92. // of a nondeterministic finite-state machine (aka syntax charts or
  93. // "railroad normal form" in parsing technology).  Each node is an opcode
  94. // plus a "next" pointer, possibly plus an operand.  "Next" pointers of
  95. // all nodes except BRANCH implement concatenation; a "next" pointer with
  96. // a BRANCH on both ends of it is connecting two alternatives.  (Here we
  97. // have one of the subtle syntax dependencies: an individual BRANCH (as
  98. // opposed to a collection of them) is never concatenated with anything
  99. // because of operator precedence.)  The operand of some types of node is
  100. // a literal string; for others, it is a node leading into a sub-FSM.  In
  101. // particular, the operand of a BRANCH node is the first node of the
  102. // branch.  (NB this is *not* a tree structure: the tail of the branch
  103. // connects to the thing following the set of BRANCHes.)  The opcodes
  104. // are:
  105. enum {
  106. //  definition number opnd? meaning
  107. END = 0, // no End of program.
  108. BOL = 1, // no Match beginning of line.
  109. EOL = 2, // no Match end of line.
  110. ANY = 3, // no Match any character.
  111. ANYOF = 4, // str Match any of these.
  112. ANYBUT = 5, // str Match any but one of these.
  113. BRANCH = 6, // node Match this, or the next..&.
  114. BACK = 7, // no "next" ptr points backward.
  115. EXACTLY = 8, // str Match this string.
  116. NOTHING = 9, // no Match empty string.
  117. STAR = 10, // node Match this 0 or more times.
  118. PLUS = 11, // node Match this 1 or more times.
  119. WORDA = 12, // no Match "" at wordchar, where prev is nonword
  120. WORDZ = 13, // no Match "" at nonwordchar, where prev is word
  121. OPEN = 20, // no Sub-RE starts here.
  122. // OPEN+1 is number 1, etc.
  123. CLOSE = 30 // no Analogous to OPEN.
  124. };
  125. // Opcode notes:
  126. //
  127. // BRANCH The set of branches constituting a single choice are hooked
  128. // together with their "next" pointers, since precedence prevents
  129. // anything being concatenated to any individual branch.  The
  130. // "next" pointer of the last BRANCH in a choice points to the
  131. // thing following the whole choice.  This is also where the
  132. // final "next" pointer of each individual branch points; each
  133. // branch starts with the operand node of a BRANCH node.
  134. //
  135. // BACK Normal "next" pointers all implicitly point forward; BACK
  136. // exists to make loop structures possible.
  137. //
  138. // STAR,PLUS '?', and complex '*' and '+', are implemented as circular
  139. // BRANCH structures using BACK.  Simple cases (one character
  140. // per match) are implemented with STAR and PLUS for speed
  141. // and to minimize recursive plunges.
  142. //
  143. // OPEN,CLOSE ...are numbered at compile time.
  144. // A node is one char of opcode followed by two chars of "next" pointer.
  145. // "Next" pointers are stored as two 8-bit pieces, high order first.  The
  146. // value is a positive offset from the opcode of the node containing it.
  147. // An operand, if any, simply follows the node.  (Note that much of the
  148. // code generation knows about this implicit relationship.)
  149. //
  150. // Using two bytes for the "next" pointer is vast overkill for most things,
  151. // but allows patterns to get big without disasters.
  152. enum
  153. {
  154. REGERR_SENTINEL_VALUE = 0,
  155. REGERR_NULLARG = 1, REGERR_CORRUPTED, REGERR_CORRUPTION, REGERR_CORRUPTED_POINTERS,
  156. REGERR_BAD_REGREPEAT, REGERR_CORRUPTED_OPCODE, REGERR_NULL_TO_REGSUB,
  157. REGERR_DAMAGED_REGEXP_REGSUB, REGERR_DAMAGED_MATCH_STRING, REGERR_NULL_TO_REGCOMP,
  158. REGERR_TO_BIG, REGERR_TO_MANY_PAREN, REGERR_UNTERMINATED_PAREN, REGERR_UNMATCHED_PAREN,
  159. REGERR_INTERNAL_ERROR_JUNK, REGERR_OP_COULD_BE_EMPTY, REGERR_NESTED_OP, REGERR_INVALID_RANGE,
  160. REGERR_UNMATCHED_BRACE, REGERR_INTERNAL_UNEXPECTED_CHAR, REGERR_OP_FOLLOWS_NOTHING,
  161. REGERR_TRAILING_ESC, REGERR_INTERNAL_STRSCSPN, REGERR_NO_REGEXP
  162. };
  163. struct regErr
  164. {
  165. int m_id;
  166. LPCTSTR m_err;
  167. } errors[] = {
  168. { REGERR_NULLARG, _T( "NULL argument to regexec" ) },
  169. { REGERR_CORRUPTED, _T( "corrupted regexp" ) },
  170. { REGERR_CORRUPTION, _T( "regexp corruption" ) },
  171. { REGERR_CORRUPTED_POINTERS, _T( "corrupted pointers" ) },
  172. { REGERR_BAD_REGREPEAT, _T( "internal error: bad call of regrepeat" ) },
  173. { REGERR_CORRUPTED_OPCODE, _T( "corrupted opcode" ) },
  174. { REGERR_NULL_TO_REGSUB, _T( "NULL parm to regsub" ) },
  175. { REGERR_DAMAGED_REGEXP_REGSUB, _T( "damaged regexp fed to regsub" ) },
  176. { REGERR_DAMAGED_MATCH_STRING, _T( "damaged match string" ) },
  177. { REGERR_NULL_TO_REGCOMP, _T( "NULL argument to regcomp" ) },
  178. { REGERR_TO_BIG, _T( "regexp too big" ) },
  179. { REGERR_TO_MANY_PAREN, _T( "too many ()" ) },
  180. { REGERR_UNTERMINATED_PAREN, _T( "unterminated ()" ) },
  181. { REGERR_UNMATCHED_PAREN, _T( "unmatched ()" ) },
  182. { REGERR_INTERNAL_ERROR_JUNK, _T( "internal error: junk on end" ) },
  183. { REGERR_OP_COULD_BE_EMPTY, _T( "*+ operand could be empty" ) },
  184. { REGERR_NESTED_OP, _T( "nested *?+" ) },
  185. { REGERR_INVALID_RANGE, _T( "invalid [] range" ) },
  186. { REGERR_UNMATCHED_BRACE, _T( "unmatched []" ) },
  187. { REGERR_INTERNAL_UNEXPECTED_CHAR, _T( "internal error: \0|) unexpected" ) },
  188. { REGERR_OP_FOLLOWS_NOTHING, _T( "?+* follows nothing" ) },
  189. { REGERR_TRAILING_ESC, _T( "trailing \" ) },
  190. { REGERR_INTERNAL_STRSCSPN, _T( "internal error: strcspn 0" ) },
  191. { REGERR_NO_REGEXP, _T( "NULL regexp" ) },
  192. { REGERR_SENTINEL_VALUE, _T( "Unknown error") } // must be last value
  193. };
  194. // Flags to be passed up and down.
  195. enum {
  196. HASWIDTH = 01, // Known never to match null string.
  197. SIMPLE = 02, // Simple enough to be STAR/PLUS operand.
  198. SPSTART = 04, // Starts with * or +.
  199. WORST = 0 // Worst case.
  200. };
  201. ///////////////////////////////////////////////////////////////////////////////
  202. class CRegErrorHandler
  203. {
  204. friend Regexp;
  205. mutable CString m_szError;
  206. static LPCTSTR FindErr( int id );
  207. protected:
  208. void ClearErrorString() const;
  209. void regerror( LPCTSTR s ) const;
  210. void regerror( int id ) const;
  211. public:
  212. CRegErrorHandler() { }
  213. CRegErrorHandler( const CRegErrorHandler & reh ) : m_szError( reh.m_szError ) {}
  214. const CString & GetErrorString() const;
  215. };
  216. void CRegErrorHandler::regerror( LPCTSTR s ) const
  217. {
  218. //TRACE1( "regerror: %sn", s );
  219. m_szError = s;
  220. }
  221. void CRegErrorHandler::regerror( int id ) const
  222. {
  223. regerror( FindErr( id ) );
  224. }
  225. const CString & CRegErrorHandler::GetErrorString() const
  226. {
  227. return m_szError;
  228. }
  229. void CRegErrorHandler::ClearErrorString() const
  230. {
  231. m_szError.resize(0);
  232. }
  233. LPCTSTR CRegErrorHandler::FindErr( int id )
  234. {
  235. for ( struct regErr * perr = errors; perr->m_id != REGERR_SENTINEL_VALUE; perr++ )
  236. if ( perr->m_id == id )
  237. return perr->m_err;
  238. return perr->m_err; // since we've fallen off the array, perr->m_id == 0
  239. }
  240. ///////////////////////////////////////////////////////////////////////////////
  241. // All of the functions required to directly access the 'program'
  242. class CRegProgramAccessor : public CRegErrorHandler
  243. {
  244. public:
  245. static inline TCHAR OP( LPTSTR p )
  246. {
  247. return (*(p));
  248. }
  249. static inline LPTSTR OPERAND( LPTSTR p )
  250. {
  251. return p + 3;
  252. }
  253. static inline LPTSTR regnext( LPTSTR p )
  254. {
  255. const short &offset = *((short*)(p+1));
  256. if (offset == 0)
  257. return(NULL);
  258. return((OP(p) == BACK) ? p-offset : p+offset);
  259. }
  260. #ifdef _RE_DEBUG
  261. LPTSTR CRegProgramAccessor::regprop( LPTSTR op );
  262. #endif
  263. };
  264. ///////////////////////////////////////////////////////////////////////////////
  265. // The internal interface to the regexp, wrapping the compilation as well as the
  266. // execution of the regexp (matching)
  267. class regexp : public CRegProgramAccessor
  268. {
  269. friend class CRegExecutor;
  270. friend class Regexp;
  271. int m_programSize;
  272. LPTSTR startp[Regexp::NSUBEXP];
  273. LPTSTR endp[Regexp::NSUBEXP];
  274. TCHAR regstart; // Internal use only.
  275. TCHAR reganch; // Internal use only.
  276. LPTSTR regmust; // Internal use only.
  277. int regmlen; // Internal use only.
  278. LPTSTR program;
  279. bool status;
  280. int count; // used by Regexp to manage the reference counting of regexps
  281. int numSubs;
  282. public:
  283. regexp( LPCTSTR exp, BOOL iCase );
  284. regexp( const regexp & r );
  285. ~regexp();
  286. void ignoreCase( const TCHAR * in, TCHAR * out );
  287. bool regcomp( LPCTSTR exp );
  288. bool regexec( LPCTSTR string );
  289. bool Status() const { return status; }
  290. CString GetReplaceString( const TCHAR* sReplaceExp ) const;
  291. regexp * getCopy();
  292. #ifdef _RE_DEBUG
  293. void  regdump();
  294. #endif
  295. #ifdef _DEBUG
  296. CString m_originalPattern;
  297. CString m_modifiedPattern;
  298. #endif
  299. };
  300. ///////////////////////////////////////////////////////////////////////////////
  301. // Compile / Validate the regular expression - ADT
  302. class CRegCompilerBase : public CRegProgramAccessor
  303. {
  304. public:
  305. CRegCompilerBase( LPCTSTR parse );
  306. LPTSTR reg(int paren, int *flagp);
  307. protected:
  308. LPTSTR regparse; // Input-scan pointer. 
  309. int regnpar; // () count. 
  310. LPTSTR regbranch(int *flagp);
  311. LPTSTR regpiece(int *flagp);
  312. LPTSTR regatom(int *flagp);
  313. inline bool ISREPN( TCHAR c ) { return ((c) == '*' || (c) == '+' || (c) == '?'); }
  314. virtual void regc(int c) = 0;
  315. virtual LPTSTR regnode(int op) = 0;
  316. virtual void reginsert(TCHAR op, LPTSTR opnd) = 0;
  317. virtual void regtail(LPTSTR p, LPTSTR val) = 0;
  318. virtual void regoptail(LPTSTR p, LPTSTR val) = 0;
  319. };
  320. ///////////////////////////////////////////////////////////////////////////////
  321. // First pass over the expression, testing for validity and returning the 
  322. // program size
  323. class CRegValidator : public CRegCompilerBase
  324. {
  325. public:
  326. CRegValidator( LPCTSTR parse );
  327. inline long Size() const { return regsize; }
  328. private:
  329. long regsize; // Code size. 
  330. TCHAR regdummy[3]; // NOTHING, 0 next ptr 
  331. protected:
  332. LPTSTR regnode(int) { regsize += 3; return regdummy; }
  333. void regc(int) { regsize++; }
  334. void reginsert(TCHAR, LPTSTR) { regsize += 3; }
  335. void regtail(LPTSTR, LPTSTR) { return; }
  336. void regoptail(LPTSTR, LPTSTR) { return; }
  337. };
  338. ///////////////////////////////////////////////////////////////////////////////
  339. // Second pass, actually generating the program
  340. class CRegCompiler : public CRegCompilerBase
  341. {
  342. public:
  343. CRegCompiler( LPCTSTR parse, LPTSTR prog );
  344. private:
  345. LPTSTR regcode;
  346. protected:
  347. // regc - emit (if appropriate) a byte of code
  348. void regc(int b)
  349. {
  350. *regcode++ = (TCHAR)b;
  351. }
  352. LPTSTR regnode(int op);
  353. void reginsert(TCHAR op, LPTSTR opnd);
  354. void regtail(LPTSTR p, LPTSTR val);
  355. void regoptail(LPTSTR p, LPTSTR val);
  356. };
  357. // regnode - emit a node
  358. LPTSTR CRegCompiler::regnode(int op)
  359. {
  360. LPTSTR const ret = regcode;
  361. LPTSTR ptr = ret;
  362. *ptr++ = (TCHAR)op;
  363. *ptr++ = ''; // Null next pointer. 
  364. *ptr++ = '';
  365. regcode = ptr;
  366. return(ret);
  367. }
  368. // reginsert - insert an operator in front of already-emitted operand
  369. //
  370. // Means relocating the operand.
  371. void CRegCompiler::reginsert(TCHAR op, LPTSTR opnd)
  372. {
  373. LPTSTR place;
  374. (void) memmove(opnd+3, opnd, (size_t)((regcode - opnd)*sizeof(TCHAR)));
  375. regcode += 3;
  376. place = opnd; // Op node, where operand used to be.
  377. *place++ = op;
  378. *place++ = '';
  379. *place++ = '';
  380. }
  381. // regtail - set the next-pointer at the end of a node chain
  382. void CRegCompiler::regtail(LPTSTR p, LPTSTR val)
  383. {
  384. LPTSTR scan;
  385. LPTSTR temp;
  386. // Find last node. 
  387. for (scan = p; (temp = regnext(scan)) != NULL; scan = temp)
  388. continue;
  389. *((short *)(scan+1)) = (short)((OP(scan) == BACK) ? scan - val : val - scan);
  390. }
  391. // regoptail - regtail on operand of first argument; nop if operandless
  392. void CRegCompiler::regoptail(LPTSTR p, LPTSTR val)
  393. {
  394. // "Operandless" and "op != BRANCH" are synonymous in practice. 
  395. if (OP(p) == BRANCH)
  396. regtail(OPERAND(p), val);
  397. }
  398. ///////////////////////////////////////////////////////////////////////////////
  399. CRegCompilerBase::CRegCompilerBase( LPCTSTR parse )
  400. : regparse( (LPTSTR)parse ),
  401. regnpar(1)
  402. {
  403. }
  404. CRegValidator::CRegValidator( LPCTSTR parse )
  405. : CRegCompilerBase( parse ),
  406. regsize(0)
  407. {
  408. regc(MAGIC);
  409. regdummy[0] = NOTHING;
  410. regdummy[1] = regdummy[2] = 0;
  411. }
  412. CRegCompiler::CRegCompiler( LPCTSTR parse, LPTSTR prog )
  413. : CRegCompilerBase( parse ),
  414. regcode(prog)
  415. {
  416. regc(MAGIC);
  417. }
  418. ///////////////////////////////////////////////////////////////////////////////
  419. regexp::regexp( LPCTSTR exp, BOOL iCase )
  420. : regstart(0),
  421. reganch(0),
  422. regmust(0),
  423. regmlen(0),
  424. program(0),
  425. m_programSize(0)
  426. {
  427. #if _DEBUG
  428. m_originalPattern = exp; // keep a version of the pattern for debugging
  429. #endif
  430. if ( iCase )
  431. {
  432. TCHAR * out = new TCHAR[(_tcslen( exp ) * 4) + 1];
  433. ignoreCase( exp, out );
  434. #if _DEBUG
  435. m_modifiedPattern = out; // and the modified version if there is one
  436. #endif
  437. status = regcomp( out );
  438. delete [] out;
  439. }
  440. else
  441. status = regcomp( exp );
  442. count = numSubs = 0;
  443. }
  444. regexp::regexp( const regexp & orig )
  445. : regstart(orig.regstart),
  446. reganch(orig.reganch),
  447. regmlen(orig.regmlen),
  448. m_programSize(orig.m_programSize),
  449. numSubs(orig.numSubs),
  450. regmust(0)
  451. {
  452. #if _DEBUG
  453. m_originalPattern = orig.m_originalPattern;
  454. m_modifiedPattern = orig.m_modifiedPattern;
  455. #endif
  456. status = orig.status;
  457. count = 0;
  458. program = new TCHAR[m_programSize];
  459. memcpy( program, orig.program, m_programSize * sizeof( TCHAR ) );
  460. if ( orig.regmust )
  461. regmust = program + ( orig.regmust - orig.program );
  462. for ( int i = Regexp::NSUBEXP; i > 0; i--)
  463. {
  464. startp[i] = orig.startp[i];
  465. endp[i] = orig.endp[i];
  466. }
  467. }
  468. regexp::~regexp()
  469. {
  470. delete [] program;
  471. }
  472. // regcomp - compile a regular expression into internal code
  473. //
  474. // We can't allocate space until we know how big the compiled form will
  475. // be, but we can't compile it (and thus know how big it is) until we've
  476. // got a place to put the code.  So we cheat: we compile it twice, once
  477. // with code generation turned off and size counting turned on, and once
  478. // "for real".  This also means that we don't allocate space until we are
  479. // sure that the thing really will compile successfully, and we never
  480. // have to move the code and thus invalidate pointers into it.  (Note
  481. // that it has to be in one piece because free() must be able to free it
  482. // all.)
  483. //
  484. // Beware that the optimization-preparation code in here knows about some
  485. // of the structure of the compiled regexp.
  486. bool regexp::regcomp(LPCTSTR exp)
  487. {
  488. LPTSTR scan;
  489. int flags;
  490. if (exp == NULL)
  491. {
  492. regerror( REGERR_NULL_TO_REGCOMP );
  493. return NULL;
  494. }
  495. // First pass: determine size, legality.
  496. CRegValidator tester( exp );
  497. if (tester.reg(0, &flags) == NULL)
  498. return false;
  499. // Small enough for pointer-storage convention? 
  500. if (tester.Size() >= 0x7fffL) // Probably could be 0xffffL. 
  501. {
  502. regerror(REGERR_TO_BIG);
  503. return NULL;
  504. }
  505. m_programSize = tester.Size();
  506. // Allocate space. 
  507. program = new TCHAR[m_programSize];
  508. CRegCompiler comp( exp, program );
  509. // Second pass: emit code. 
  510. if (comp.reg(0, &flags) == NULL)
  511. return false;
  512. scan = program + 1; // First BRANCH. 
  513. if (OP(regnext(scan)) == END)
  514. { // Only one top-level choice. 
  515. scan = OPERAND(scan);
  516. // Starting-point info. 
  517. if (OP(scan) == EXACTLY)
  518. regstart = *OPERAND(scan);
  519. else if (OP(scan) == BOL)
  520. reganch = 1;
  521. // If there's something expensive in the r.e., find the
  522. // longest literal string that must appear and make it the
  523. // regmust.  Resolve ties in favor of later strings, since
  524. // the regstart check works with the beginning of the r.e.
  525. // and avoiding duplication strengthens checking.  Not a
  526. // strong reason, but sufficient in the absence of others.
  527.  
  528. if (flags&SPSTART) 
  529. {
  530. LPTSTR longest = NULL;
  531. size_t len = 0;
  532. for (; scan != NULL; scan = regnext(scan))
  533. if (OP(scan) == EXACTLY && _tcslen(OPERAND(scan)) >= len)
  534. {
  535. longest = OPERAND(scan);
  536. len = _tcslen(OPERAND(scan));
  537. }
  538. regmust = longest;
  539. regmlen = (int)len;
  540. }
  541. }
  542. return true;
  543. }
  544. regexp * regexp::getCopy()
  545. {
  546. return new regexp( *this );
  547. }
  548. // reg - regular expression, i.e. main body or parenthesized thing
  549. //
  550. // Caller must absorb opening parenthesis.
  551. //
  552. // Combining parenthesis handling with the base level of regular expression
  553. // is a trifle forced, but the need to tie the tails of the branches to what
  554. // follows makes it hard to avoid.
  555. LPTSTR CRegCompilerBase::reg( int paren, int *flagp )
  556. {
  557. LPTSTR ret;
  558. LPTSTR br;
  559. LPTSTR ender;
  560. int parno = 0;
  561. int flags;
  562. *flagp = HASWIDTH; // Tentatively. 
  563. if (paren)
  564. {
  565. // Make an OPEN node. 
  566. if (regnpar >= Regexp::NSUBEXP)
  567. {
  568. regerror(REGERR_TO_MANY_PAREN);
  569. return NULL;
  570. }
  571. parno = regnpar;
  572. regnpar++;
  573. ret = regnode(OPEN+parno);
  574. }
  575. // Pick up the branches, linking them together. 
  576. br = regbranch(&flags);
  577. if (br == NULL)
  578. return(NULL);
  579. if (paren)
  580. regtail(ret, br); // OPEN -> first. 
  581. else
  582. ret = br;
  583. *flagp &= ~(~flags&HASWIDTH); // Clear bit if bit 0. 
  584. *flagp |= flags&SPSTART;
  585. while (*regparse == '|')
  586. {
  587. regparse++;
  588. br = regbranch(&flags);
  589. if (br == NULL)
  590. return(NULL);
  591. regtail(ret, br); // BRANCH -> BRANCH. 
  592. *flagp &= ~(~flags&HASWIDTH);
  593. *flagp |= flags&SPSTART;
  594. }
  595. // Make a closing node, and hook it on the end. 
  596. ender = regnode((paren) ? CLOSE+parno : END);
  597. regtail(ret, ender);
  598. // Hook the tails of the branches to the closing node. 
  599. for (br = ret; br != NULL; br = regnext(br))
  600. regoptail(br, ender);
  601. // Check for proper termination. 
  602. if (paren && *regparse++ != ')')
  603. {
  604. regerror( REGERR_UNTERMINATED_PAREN );
  605. return NULL;
  606. }
  607. else if (!paren && *regparse != '')
  608. {
  609. if (*regparse == ')')
  610. {
  611. regerror( REGERR_UNMATCHED_PAREN );
  612. return NULL;
  613. }
  614. else
  615. {
  616. regerror( REGERR_INTERNAL_ERROR_JUNK );
  617. return NULL;
  618. }
  619. // NOTREACHED 
  620. }
  621. return(ret);
  622. }
  623. // regbranch - one alternative of an | operator
  624. //
  625. // Implements the concatenation operator.
  626. LPTSTR CRegCompilerBase::regbranch(int *flagp)
  627. {
  628. LPTSTR ret;
  629. LPTSTR chain;
  630. LPTSTR latest;
  631. int flags;
  632. int c;
  633. *flagp = WORST; // Tentatively. 
  634. ret = regnode(BRANCH);
  635. chain = NULL;
  636. while ((c = *regparse) != '' && c != '|' && c != ')')
  637. {
  638. latest = regpiece(&flags);
  639. if (latest == NULL)
  640. return(NULL);
  641. *flagp |= flags&HASWIDTH;
  642. if (chain == NULL) // First piece. 
  643. *flagp |= flags&SPSTART;
  644. else
  645. regtail(chain, latest);
  646. chain = latest;
  647. }
  648. if (chain == NULL) // Loop ran zero times. 
  649. (void) regnode(NOTHING);
  650. return(ret);
  651. }
  652. // regpiece - something followed by possible [*+?]
  653. //
  654. // Note that the branching code sequences used for ? and the general cases
  655. // of * and + are somewhat optimized:  they use the same NOTHING node as
  656. // both the endmarker for their branch list and the body of the last branch.
  657. // It might seem that this node could be dispensed with entirely, but the
  658. // endmarker role is not redundant.
  659. LPTSTR CRegCompilerBase::regpiece(int *flagp)
  660. {
  661. LPTSTR ret;
  662. TCHAR op;
  663. LPTSTR next;
  664. int flags;
  665. ret = regatom(&flags);
  666. if (ret == NULL)
  667. return(NULL);
  668. op = *regparse;
  669. if (!ISREPN(op))
  670. {
  671. *flagp = flags;
  672. return(ret);
  673. }
  674. if (!(flags&HASWIDTH) && op != _T( '?' ))
  675. {
  676. regerror( REGERR_OP_COULD_BE_EMPTY );
  677. return NULL;
  678. }
  679. switch (op)
  680. {
  681. case _T( '*' ): *flagp = WORST|SPSTART; break;
  682. case _T( '+' ): *flagp = WORST|SPSTART|HASWIDTH; break;
  683. case _T( '?' ): *flagp = WORST; break;
  684. }
  685. if (op == _T( '*' ) && (flags&SIMPLE))
  686. reginsert(STAR, ret);
  687. else if (op == _T( '*' ))
  688. {
  689. // Emit x* as (x&|), where & means "self". 
  690. reginsert(BRANCH, ret); // Either x 
  691. regoptail(ret, regnode(BACK)); // and loop 
  692. regoptail(ret, ret); // back 
  693. regtail(ret, regnode(BRANCH)); // or 
  694. regtail(ret, regnode(NOTHING)); // null. 
  695. }
  696. else if (op == _T( '+' ) && (flags&SIMPLE))
  697. reginsert(PLUS, ret);
  698. else if (op == _T( '+' ))
  699. {
  700. // Emit x+ as x(&|), where & means "self". 
  701. next = regnode(BRANCH); // Either 
  702. regtail(ret, next);
  703. regtail(regnode(BACK), ret); // loop back 
  704. regtail(next, regnode(BRANCH)); // or 
  705. regtail(ret, regnode(NOTHING)); // null. 
  706. }
  707. else if (op == _T( '?' ))
  708. {
  709. // Emit x? as (x|) 
  710. reginsert(BRANCH, ret); // Either x 
  711. regtail(ret, regnode(BRANCH)); // or 
  712. next = regnode(NOTHING); // null. 
  713. regtail(ret, next);
  714. regoptail(ret, next);
  715. }
  716. regparse++;
  717. if (ISREPN(*regparse))
  718. {
  719. regerror( REGERR_NESTED_OP );
  720. return NULL;
  721. }
  722. return(ret);
  723. }
  724. // regatom - the lowest level
  725. //
  726. // Optimization:  gobbles an entire sequence of ordinary characters so that
  727. // it can turn them into a single node, which is smaller to store and
  728. // faster to run.  Backslashed characters are exceptions, each becoming a
  729. // separate node; the code is simpler that way and it's not worth fixing.
  730. LPTSTR CRegCompilerBase::regatom(int * flagp)
  731. {
  732. LPTSTR ret;
  733. int flags;
  734. *flagp = WORST; // Tentatively. 
  735. switch ( *regparse++ )
  736. {
  737. // FIXME: these chars only have meaning at beg/end of pat?
  738. case '^':
  739. ret = regnode(BOL);
  740. break;
  741. case '$':
  742. ret = regnode(EOL);
  743. break;
  744. case '.':
  745. ret = regnode(ANY);
  746. *flagp |= HASWIDTH|SIMPLE;
  747. break;
  748. case '[':
  749. {
  750. int range;
  751. int rangeend;
  752. int c;
  753. if (*regparse == '^')
  754. { // Complement of range. 
  755. ret = regnode(ANYBUT);
  756. regparse++;
  757. }
  758. else
  759. ret = regnode(ANYOF);
  760. if ((c = *regparse) == ']' || c == '-')
  761. {
  762. regc(c);
  763. regparse++;
  764. }
  765. while ((c = *regparse++ ) != '' && c != ']')
  766. {
  767. if (c != '-')
  768. regc(c);
  769. else if ((c = *regparse) == ']' || c == '')
  770. regc('-');
  771. else
  772. {
  773. range = (TCHAR)*(regparse-2);
  774. rangeend = (TCHAR)c;
  775. if (range > rangeend)
  776. {
  777. regerror( REGERR_INVALID_RANGE );
  778. return NULL;
  779. }
  780. for (range++; range <= rangeend; range++)
  781. regc(range);
  782. regparse++;
  783. }
  784. }
  785. regc('');
  786. if (c != ']')
  787. {
  788. regerror( REGERR_UNMATCHED_BRACE );
  789. return NULL;
  790. }
  791. *flagp |= HASWIDTH|SIMPLE;
  792. break;
  793. }
  794. case '(':
  795. ret = reg(1, &flags);
  796. if (ret == NULL)
  797. return(NULL);
  798. *flagp |= flags&(HASWIDTH|SPSTART);
  799. break;
  800. case '':
  801. case '|':
  802. case ')':
  803. // supposed to be caught earlier 
  804. regerror( REGERR_INTERNAL_UNEXPECTED_CHAR );
  805. return NULL;
  806. case '?':
  807. case '+':
  808. case '*':
  809. {
  810. regerror( REGERR_OP_FOLLOWS_NOTHING );
  811. return NULL;
  812. }
  813. case '\':
  814. switch (*regparse++)
  815. {
  816. case '':
  817. {
  818. regerror( REGERR_TRAILING_ESC );
  819. return NULL;
  820. }
  821. case '<':
  822. ret = regnode(WORDA);
  823. break;
  824. case '>':
  825. ret = regnode(WORDZ);
  826. break;
  827. /* FIXME: Someday handle 1, 2, ... */
  828. default:
  829. /* Handle general quoted chars in exact-match routine */
  830. goto de_fault;
  831. }
  832. break;
  833. de_fault:
  834. default:
  835. // Encode a string of characters to be matched exactly.
  836. //
  837. // This is a bit tricky due to quoted chars and due to
  838. // '*', '+', and '?' taking the SINGLE char previous
  839. // as their operand.
  840. //
  841. // On entry, the char at regparse[-1] is going to go
  842. // into the string, no matter what it is.  (It could be
  843. // following a  if we are entered from the '' case.)
  844. // 
  845. // Basic idea is to pick up a good char in  ch  and
  846. // examine the next char.  If it's *+? then we twiddle.
  847. // If it's  then we frozzle.  If it's other magic char
  848. // we push  ch  and terminate the string.  If none of the
  849. // above, we push  ch  on the string and go around again.
  850. //
  851. //  regprev  is used to remember where "the current char"
  852. // starts in the string, if due to a *+? we need to back
  853. // up and put the current char in a separate, 1-char, string.
  854. // When  regprev  is NULL,  ch  is the only char in the
  855. // string; this is used in *+? handling, and in setting
  856. // flags |= SIMPLE at the end.
  857. {
  858. TCHAR *regprev;
  859. register TCHAR ch;
  860. regparse--; /* Look at cur char */
  861. ret = regnode(EXACTLY);
  862. for ( regprev = 0 ; ; ) {
  863. ch = *regparse++; /* Get current char */
  864. switch (*regparse) { /* look at next one */
  865. default:
  866. regc(ch); /* Add cur to string */
  867. break;
  868. case '.': case '[': case '(':
  869. case ')': case '|': case 'n':
  870. case '$': case '^':
  871. case '':
  872. /* FIXME, $ and ^ should not always be magic */
  873. magic:
  874. regc(ch); /* dump cur char */
  875. goto done; /* and we are done */
  876. case '?': case '+': case '*':
  877. if (!regprev)  /* If just ch in str, */
  878. goto magic; /* use it */
  879. /* End mult-char string one early */
  880. regparse = regprev; /* Back up parse */
  881. goto done;
  882. case '\':
  883. regc(ch); /* Cur char OK */
  884. switch (regparse[1]){ /* Look after  */
  885. case '':
  886. case '<':
  887. case '>':
  888. /* FIXME: Someday handle 1, 2, ... */
  889. goto done; /* Not quoted */
  890. default:
  891. /* Backup point is , scan  * point is after it. */
  892. regprev = regparse;
  893. regparse++; 
  894. continue; /* NOT break; */
  895. }
  896. }
  897. regprev = regparse; /* Set backup point */
  898. }
  899. done:
  900. regc('');
  901. *flagp |= HASWIDTH;
  902. if (!regprev) /* One char? */
  903. *flagp |= SIMPLE;
  904. }
  905. break;
  906. }
  907. return(ret);
  908. }
  909. ////////////////////////////////////////////////////////////////////////////////
  910. // regexec and friends
  911. // Work-variable struct for regexec().
  912. class CRegExecutor : public CRegProgramAccessor
  913. {
  914. friend bool regexp::regexec( LPCTSTR str );
  915. LPTSTR reginput; // String-input pointer. 
  916. LPTSTR regbol; // Beginning of input, for ^ check. 
  917. LPTSTR * regstartp; // Pointer to startp array. 
  918. LPTSTR * regendp; // Ditto for endp.
  919. regexp * prog;
  920. public:
  921. CRegExecutor( regexp * prog, LPTSTR string );
  922. protected:
  923. bool regtry( LPTSTR string );
  924. bool regmatch( LPTSTR prog );
  925. size_t regrepeat( LPTSTR node );
  926. };
  927. CRegExecutor::CRegExecutor( regexp * p, LPTSTR string )
  928. : regbol( string ),
  929. regstartp( p->startp ),
  930. regendp( p->endp ),
  931. prog(p)
  932. {
  933. }
  934. #ifdef _RE_DEBUG
  935. int regnarrate = 0;
  936. #endif
  937. // regexec - match a regexp against a string
  938. bool regexp::regexec( LPCTSTR str )
  939. {
  940. LPTSTR string = (LPTSTR)str; // avert const poisoning 
  941. // Be paranoid. 
  942. if ( string == NULL )
  943. {
  944. regerror( REGERR_NULLARG );
  945. return false;
  946. }
  947. // Check validity of program. 
  948. if (*program != MAGIC)
  949. {
  950. regerror( REGERR_CORRUPTED );
  951. return false;
  952. }
  953. // If there is a "must appear" string, look for it. 
  954. if ( regmust != NULL && _tcsstr( string, regmust ) == NULL )
  955. return false;
  956. CRegExecutor executor( this, string );
  957. // Simplest case:  anchored match need be tried only once. 
  958. if ( reganch )
  959. return( executor.regtry( string ) );
  960. // Messy cases:  unanchored match. 
  961. if ( regstart != '' )
  962. {
  963. // We know what TCHAR it must start with. 
  964. for ( LPTSTR s = string; s != NULL; s = _tcschr( s+1 , regstart ) )
  965. if ( executor.regtry( s) )
  966. return true;
  967. return false;
  968. }
  969. else
  970. {
  971. // We don't -- general case. 
  972. for ( LPTSTR s = string; ! executor.regtry( s ); s++ )
  973. if (*s == '')
  974. return false;
  975. }
  976. return true;
  977. }
  978. // regtry - try match at specific point
  979. bool CRegExecutor::regtry( LPTSTR string )
  980. {
  981. int i;
  982. LPTSTR * stp;
  983. LPTSTR * enp;
  984. reginput = string;
  985. stp = prog->startp;
  986. enp = prog->endp;
  987. for (i = Regexp::NSUBEXP; i > 0; i--)
  988. {
  989. *stp++ = NULL;
  990. *enp++ = NULL;
  991. }
  992. if ( regmatch( prog->program + 1 ) )
  993. {
  994. prog->startp[0] = string;
  995. prog->endp[0] = reginput;
  996. return true;
  997. }
  998. else
  999. return false;
  1000. }
  1001. // regmatch - main matching routine
  1002. //
  1003. // Conceptually the strategy is simple:  check to see whether the current
  1004. // node matches, call self recursively to see whether the rest matches,
  1005. // and then act accordingly.  In practice we make some effort to avoid
  1006. // recursion, in particular by going through "ordinary" nodes (that don't
  1007. // need to know whether the rest of the match failed) by a loop instead of
  1008. // by recursion.
  1009. bool CRegExecutor::regmatch( LPTSTR prog )
  1010. {
  1011. LPTSTR scan; // Current node. 
  1012. LPTSTR next; // Next node. 
  1013. #ifdef _RE_DEBUG
  1014. if (prog != NULL && regnarrate)
  1015. _ftprintf(stderr, _T( "%s(n" ), regprop(prog));
  1016. #endif
  1017. for (scan = prog; scan != NULL; scan = next)
  1018. {
  1019. #ifdef _RE_DEBUG
  1020. if (regnarrate)
  1021. _ftprintf(stderr, _T( "%s...n" ), regprop(scan));
  1022. #endif
  1023. next = regnext(scan);
  1024. switch (OP(scan))
  1025. {
  1026. case BOL:
  1027. if (reginput != regbol)
  1028. return false;
  1029. break;
  1030. case EOL:
  1031. if (*reginput != '')
  1032. return false;
  1033. break;
  1034. case WORDA:
  1035. /* Must be looking at a letter, digit, or _ */
  1036. if ((!isalnum(*reginput)) && *reginput != '_')
  1037. return(0);
  1038. /* Prev must be BOL or nonword */
  1039. if (reginput > regbol &&
  1040. (isalnum(reginput[-1]) || reginput[-1] == '_'))
  1041. return(0);
  1042. break;
  1043. case WORDZ:
  1044. /* Must be looking at non letter, digit, or _ */
  1045. if (isalnum(*reginput) || *reginput == '_')
  1046. return(0);
  1047. /* We don't care what the previous char was */
  1048. break;
  1049. case ANY:
  1050. if (*reginput == '')
  1051. return false;
  1052. reginput++;
  1053. break;
  1054. case EXACTLY:
  1055. {
  1056. size_t len;
  1057. LPTSTR const opnd = OPERAND(scan);
  1058. // Inline the first character, for speed. 
  1059. if (*opnd != *reginput)
  1060. return false;
  1061. len = _tcslen(opnd);
  1062. if (len > 1 && _tcsncmp(opnd, reginput, len) != 0)
  1063. return false;
  1064. reginput += len;
  1065. break;
  1066. }
  1067. case ANYOF:
  1068. if (*reginput == '' ||
  1069. _tcschr(OPERAND(scan), *reginput) == NULL)
  1070. return false;
  1071. reginput++;
  1072. break;
  1073. case ANYBUT:
  1074. if (*reginput == '' ||
  1075. _tcschr(OPERAND(scan), *reginput) != NULL)
  1076. return false;
  1077. reginput++;
  1078. break;
  1079. case NOTHING:
  1080. break;
  1081. case BACK:
  1082. break;
  1083. case OPEN+1: case OPEN+2: case OPEN+3:
  1084. case OPEN+4: case OPEN+5: case OPEN+6:
  1085. case OPEN+7: case OPEN+8: case OPEN+9:
  1086. {
  1087. const int no = OP(scan) - OPEN;
  1088. LPTSTR const input = reginput;
  1089. if (regmatch(next))
  1090. {
  1091. // Don't set startp if some later
  1092. // invocation of the same parentheses
  1093. // already has.
  1094.  
  1095. if (regstartp[no] == NULL)
  1096. regstartp[no] = input;
  1097. return true;
  1098. }
  1099. else
  1100. return false;
  1101. break;
  1102. }
  1103. case CLOSE+1: case CLOSE+2: case CLOSE+3:
  1104. case CLOSE+4: case CLOSE+5: case CLOSE+6:
  1105. case CLOSE+7: case CLOSE+8: case CLOSE+9:
  1106. {
  1107. const int no = OP(scan) - CLOSE;
  1108. LPTSTR const input = reginput;
  1109. if (regmatch(next))
  1110. {
  1111. // Don't set endp if some later
  1112. // invocation of the same parentheses
  1113. // already has.
  1114.  
  1115. if (regendp[no] == NULL)
  1116. regendp[no] = input;
  1117. return true;
  1118. }
  1119. else
  1120. return false;
  1121. break;
  1122. }
  1123. case BRANCH:
  1124. {
  1125. LPTSTR const save = reginput;
  1126. if (OP(next) != BRANCH) // No choice. 
  1127. next = OPERAND(scan); // Avoid recursion. 
  1128. else
  1129. {
  1130. while (OP(scan) == BRANCH)
  1131. {
  1132. if (regmatch(OPERAND(scan)))
  1133. return true;
  1134. reginput = save;
  1135. scan = regnext(scan);
  1136. }
  1137. return false;
  1138. // NOTREACHED 
  1139. }
  1140. break;
  1141. }
  1142. case STAR: case PLUS:
  1143. {
  1144. const TCHAR nextch = (OP(next) == EXACTLY) ? *OPERAND(next) : '';
  1145. size_t no;
  1146. LPTSTR const save = reginput;
  1147. const size_t min = (OP(scan) == STAR) ? 0 : 1;
  1148. for (no = regrepeat(OPERAND(scan)) + 1; no > min; no--)
  1149. {
  1150. reginput = save + no - 1;
  1151. // If it could work, try it. 
  1152. if (nextch == '' || *reginput == nextch)
  1153. if (regmatch(next))
  1154. return true;
  1155. }
  1156. return false;
  1157. break;
  1158. }
  1159. case END:
  1160. return true; // Success! 
  1161. break;
  1162. default:
  1163. regerror( REGERR_CORRUPTION );
  1164. return false;
  1165. break;
  1166. }
  1167. }
  1168. // We get here only if there's trouble -- normally "case END" is
  1169. // the terminating point.
  1170. regerror( REGERR_CORRUPTED_POINTERS );
  1171. return false;
  1172. }
  1173. // regrepeat - report how many times something simple would match
  1174. size_t CRegExecutor::regrepeat( LPTSTR node )
  1175. {
  1176. size_t count;
  1177. LPTSTR scan;
  1178. TCHAR ch;
  1179. switch (OP(node))
  1180. {
  1181. case ANY:
  1182. return(_tcslen(reginput));
  1183. break;
  1184. case EXACTLY:
  1185. ch = *OPERAND(node);
  1186. count = 0;
  1187. for (scan = reginput; *scan == ch; scan++)
  1188. count++;
  1189. return(count);
  1190. break;
  1191. case ANYOF:
  1192. return(_tcsspn(reginput, OPERAND(node)));
  1193. break;
  1194. case ANYBUT:
  1195. return(_tcscspn(reginput, OPERAND(node)));
  1196. break;
  1197. default: // Oh dear.  Called inappropriately. 
  1198. regerror( REGERR_BAD_REGREPEAT );
  1199. return(0); // Best compromise. 
  1200. break;
  1201. }
  1202. // NOTREACHED 
  1203. }
  1204. #ifdef _RE_DEBUG
  1205. // regdump - dump a regexp onto stdout in vaguely comprehensible form
  1206. void regexp::regdump()
  1207. {
  1208. LPTSTR s;
  1209. TCHAR op = EXACTLY; // Arbitrary non-END op. 
  1210. LPTSTR next;
  1211. s = _tcsinc(program);
  1212. while (op != END)
  1213. { // While that wasn't END last time... 
  1214. op = OP(s);
  1215. _tprintf(_T( "%2d%s" ), s-program, regprop(s)); // Where, what. 
  1216. next = regnext(s);
  1217. if (next == NULL) // Next ptr. 
  1218. _tprintf(_T( "(0)" ));
  1219. else 
  1220. _tprintf(_T( "(%d)" ), (s-program)+(next-s));
  1221. s += 3;
  1222. if (op == ANYOF || op == ANYBUT || op == EXACTLY)
  1223. {
  1224. // Literal string, where present. 
  1225. while (*s != '')
  1226. {
  1227. _puttchar(*s);
  1228. s = _tcsinc(s);
  1229. }
  1230. s = _tcsinc(s);
  1231. }
  1232. _puttchar('n');
  1233. }
  1234. // Header fields of interest. 
  1235. if (regstart != '')
  1236. _tprintf(_T( "start `%c' " ), regstart);
  1237. if (reganch)
  1238. _tprintf(_T( "anchored " ));
  1239. if (regmust != NULL)
  1240. _tprintf(_T( "must have "%s"" ), regmust);
  1241. _tprintf(_T( "n" ));
  1242. }
  1243. // regprop - printable representation of opcode
  1244. #define OUTPUT(s) case s: p = _T( #s ); break
  1245. LPTSTR CRegProgramAccessor::regprop( LPTSTR op )
  1246. {
  1247. LPTSTR p;
  1248. static TCHAR buf[50];
  1249. (void) _tcscpy(buf, _T( ":" ));
  1250. switch (OP(op))
  1251. {
  1252. OUTPUT( BOL );
  1253. OUTPUT( EOL );
  1254. OUTPUT( ANY );
  1255. OUTPUT( ANYOF );
  1256. OUTPUT( ANYBUT );
  1257. OUTPUT( BRANCH );
  1258. OUTPUT( EXACTLY );
  1259. OUTPUT( NOTHING );
  1260. OUTPUT( BACK );
  1261. OUTPUT( END );
  1262. OUTPUT( STAR );
  1263. OUTPUT( PLUS );
  1264. OUTPUT( WORDA );
  1265. OUTPUT( WORDZ );
  1266. case OPEN+1: case OPEN+2: case OPEN+3:
  1267. case OPEN+4: case OPEN+5: case OPEN+6:
  1268. case OPEN+7: case OPEN+8: case OPEN+9:
  1269. _stprintf(buf+_tcslen(buf), _T( "OPEN%d" ), OP(op)-OPEN);
  1270. p = NULL;
  1271. break;
  1272. case CLOSE+1: case CLOSE+2: case CLOSE+3:
  1273. case CLOSE+4: case CLOSE+5: case CLOSE+6:
  1274. case CLOSE+7: case CLOSE+8: case CLOSE+9:
  1275. _stprintf(buf+_tcslen(buf), _T( "CLOSE%d" ), OP(op)-CLOSE);
  1276. p = NULL;
  1277. break;
  1278. default:
  1279. regerror( REGERR_CORRUPTED_OPCODE );
  1280. break;
  1281. }
  1282. if (p != NULL)
  1283. (void) _tcscat(buf, p);
  1284. return(buf);
  1285. }
  1286. #endif
  1287. ///////////////////////////////////////////////////////////////////////////////
  1288. Regexp::Regexp()
  1289. : rc(0),
  1290. string(0)
  1291. {
  1292. }
  1293. Regexp::Regexp( LPCTSTR exp, BOOL iCase )
  1294. : rc( new regexp( exp, iCase ) ),
  1295. string( 0 )
  1296. {
  1297. }
  1298. Regexp::Regexp( const Regexp &r )
  1299. : rc( r.rc ),
  1300. m_szError(r.m_szError),
  1301. string(r.string)
  1302. {
  1303. if ( rc )
  1304. rc->count++;
  1305. }
  1306. const Regexp & Regexp::operator=( const Regexp & r )
  1307. {
  1308. if ( this != &r )
  1309. {
  1310. if ( rc && rc->count-- == 0 )
  1311. delete rc;
  1312. rc = r.rc;
  1313. if ( rc )
  1314. rc->count++;
  1315. string = r.string;
  1316. m_szError = r.m_szError;
  1317. }
  1318. return *this;
  1319. }
  1320. Regexp::~Regexp()
  1321. {
  1322. if ( rc && rc->count-- == 0 )
  1323. delete rc;
  1324. }
  1325. bool Regexp::Match( const TCHAR * s )
  1326. {
  1327. ClearErrorString();
  1328. string = s;
  1329. bool ret = false;
  1330. if ( rc )
  1331. {
  1332. // copy on write !
  1333. if ( rc->count )
  1334. {
  1335. rc->count--;
  1336. rc = rc->getCopy();
  1337. }
  1338. ret = rc->regexec( s );
  1339. int i = 0;
  1340. if ( ret )
  1341. for ( i = 0; i < Regexp::NSUBEXP && rc->startp[i] ; i++ )
  1342. ;
  1343. rc->numSubs = i - 1;
  1344. }
  1345. else
  1346. m_szError = CRegErrorHandler::FindErr( REGERR_NO_REGEXP );
  1347. return ret;
  1348. }
  1349. CString Regexp::GetReplaceString( LPCTSTR source ) const
  1350. {
  1351. ClearErrorString();
  1352. if ( rc )
  1353. return rc->GetReplaceString( source );
  1354. else
  1355. m_szError = CRegErrorHandler::FindErr( REGERR_NO_REGEXP );
  1356. return _T( "" );
  1357. }
  1358. int Regexp::SubStrings() const
  1359. {
  1360. ClearErrorString();
  1361. int ret = -1;
  1362. if ( rc )
  1363. ret = rc->numSubs;
  1364. else
  1365. m_szError = CRegErrorHandler::FindErr( REGERR_NO_REGEXP );
  1366. return ret;
  1367. }
  1368. int Regexp::SubStart( unsigned int i ) const
  1369. {
  1370. ClearErrorString();
  1371. int ret = -1;
  1372. if ( rc )
  1373. ret = rc->startp[safeIndex(i)] - string;
  1374. else
  1375. m_szError = CRegErrorHandler::FindErr( REGERR_NO_REGEXP );
  1376. return ret;
  1377. }
  1378. int Regexp::SubLength( unsigned int i ) const
  1379. {
  1380. ClearErrorString();
  1381. int ret = -1;
  1382. if ( rc )
  1383. {
  1384. i = safeIndex(i);
  1385. ret = rc->endp[i] - rc->startp[i];
  1386. }
  1387. else
  1388. m_szError = CRegErrorHandler::FindErr( REGERR_NO_REGEXP );
  1389. return ret;
  1390. }
  1391. bool Regexp::CompiledOK() const
  1392. {
  1393. return rc ? rc->Status() : false;
  1394. }
  1395. #ifdef _RE_DEBUG
  1396. void Regexp::Dump()
  1397. {
  1398. if ( rc )
  1399. rc->regdump();
  1400. #if defined( _DEBUG )
  1401. else
  1402. TRACE0( "No regexp to dump outn" );
  1403. #endif
  1404. }
  1405. #endif
  1406. int Regexp::safeIndex( unsigned int i ) const
  1407. {
  1408. return i < Regexp::NSUBEXP ? i : Regexp::NSUBEXP;
  1409. }
  1410. const CString Regexp::operator[]( unsigned int i ) const
  1411. {
  1412. ClearErrorString();
  1413. ASSERT( rc );
  1414. if ( rc )
  1415. {
  1416. //CString buffer;
  1417. int len = SubLength(i);
  1418. //TCHAR * szbuf = buffer.GetBufferSetLength( len );
  1419. size_t buflen = (len + 1) * sizeof(TCHAR);
  1420. TCHAR* szbuf = (TCHAR*)_alloca(buflen);
  1421. memcpy( szbuf, rc->startp[i], len * sizeof(TCHAR) );
  1422. szbuf[len] = 0;
  1423. //buffer.ReleaseBuffer();
  1424. ///buffer.resize(_tcslen(szbuf));
  1425. //return buffer;
  1426. return CString(szbuf);
  1427. }
  1428. else
  1429. {
  1430. m_szError = CRegErrorHandler::FindErr( REGERR_NO_REGEXP );
  1431. return "";
  1432. }
  1433. }
  1434. void regexp::ignoreCase( const TCHAR * in, TCHAR * out )
  1435. {
  1436. // copy in to out making every top level character a [Aa] set
  1437. BOOL inRange = FALSE;
  1438. while( *in )
  1439. {
  1440. if ( *in == '[' )
  1441. inRange = TRUE;
  1442. if ( *in == ']' )
  1443. inRange = FALSE;
  1444. if ( ! inRange && isalpha( *in ) )
  1445. {
  1446. *out++ = '[';
  1447. *out++ = (TCHAR)toupper( *in );
  1448. *out++ = (TCHAR)tolower( *in );
  1449. *out++ = ']';
  1450. }
  1451. else
  1452. *out++ = *in;
  1453. in++;
  1454. }
  1455. *out = 0;
  1456. }
  1457. // GetReplaceString - Converts a replace expression to a string
  1458. // - perform substitutions after a regexp match
  1459. // Returns - The resultant string
  1460. CString regexp::GetReplaceString( const TCHAR* sReplaceExp ) const
  1461. {
  1462. CString szEmpty( _T( "" ) );
  1463. TCHAR *src = (TCHAR *)sReplaceExp;
  1464. TCHAR *buf;
  1465. TCHAR c;
  1466. int no;
  1467. size_t len;
  1468. if( sReplaceExp == NULL )
  1469. {
  1470. regerror( REGERR_NULL_TO_REGSUB  );
  1471. return szEmpty;
  1472. }
  1473. if ( *program != MAGIC)
  1474. {
  1475. regerror( REGERR_DAMAGED_REGEXP_REGSUB );
  1476. return szEmpty;
  1477. }
  1478. // First compute the length of the string
  1479. int replacelen = 0;
  1480. while ((c = *src++) != _T('')) 
  1481. {
  1482. if (c == _T('&'))
  1483. no = 0;
  1484. else if (c == _T('\') && isdigit(*src))
  1485. no = *src++ - _T('0');
  1486. else
  1487. no = -1;
  1488. if (no < 0) 
  1489. {
  1490. // Ordinary character. 
  1491. if (c == _T('\') && (*src == _T('\') || *src == _T('&')))
  1492. c = *src++;
  1493. replacelen++;
  1494. else if (startp[no] != NULL && endp[no] != NULL &&
  1495. endp[no] > startp[no]) 
  1496. {
  1497. // Get tagged expression
  1498. len = endp[no] - startp[no];
  1499. replacelen += len;
  1500. }
  1501. }
  1502. CString szReplace;
  1503. //buf = szReplace.GetBufferSetLength( replacelen );
  1504. size_t buflen = (replacelen + 1) * sizeof(TCHAR);
  1505. buf = (TCHAR*)_alloca(buflen);
  1506. size_t repsize = szReplace.size();
  1507. size_t reservesize = min(repsize, replacelen);
  1508. size_t reservelen = reservesize * sizeof(TCHAR);
  1509. memcpy(buf, szReplace.data(), reservelen);
  1510. memset(buf + reservesize, 0, buflen - reservelen);
  1511. // Now we can create the string
  1512. src = (TCHAR *)sReplaceExp;
  1513. while ((c = *src++) != _T('')) 
  1514. {
  1515. if (c == _T('&'))
  1516. no = 0;
  1517. else if (c == _T('\') && isdigit(*src))
  1518. no = *src++ - _T('0');
  1519. else
  1520. no = -1;
  1521. if (no < 0) 
  1522. {
  1523. // Ordinary character. 
  1524. if (c == _T('\') && (*src == _T('\') || *src == _T('&')))
  1525. c = *src++;
  1526. *buf++ = c;
  1527. else if (startp[no] != NULL && endp[no] != NULL &&
  1528. endp[no] > startp[no]) 
  1529. {
  1530. // Get tagged expression
  1531. len = endp[no] - startp[no];
  1532. _tcsncpy(buf, startp[no], len);
  1533. buf += len;
  1534. if (len != 0 && *(buf-1) == _T( '' ))
  1535. { /* strncpy hit NUL. */
  1536. regerror( REGERR_DAMAGED_MATCH_STRING );
  1537. return szEmpty;
  1538. }
  1539. }
  1540. }
  1541. //szReplace.ReleaseBuffer( replacelen );
  1542. //return szReplace;
  1543. return CString(buf, replacelen);
  1544. }
  1545. CString Regexp::GetErrorString() const
  1546. {
  1547. // make sure that if status == 0 that we have an error string
  1548. //ASSERT( ( ! CompiledOK() ) ? ( rc ? rc->GetErrorString() : m_szError).GetLength() != 0 : 1 );
  1549. ASSERT( ( ! CompiledOK() ) ? ( rc ? rc->GetErrorString() : m_szError).size() != 0 : 1 );
  1550. return rc ? rc->GetErrorString() : m_szError ;
  1551. }
  1552. void Regexp::ClearErrorString() const
  1553. {
  1554. if ( rc )
  1555. rc->ClearErrorString();
  1556. m_szError.resize(0);
  1557. }