]> git.saurik.com Git - apple/icu.git/blob - icuSources/i18n/repattrn.cpp
ICU-3.13.tar.gz
[apple/icu.git] / icuSources / i18n / repattrn.cpp
1 //
2 // file: repattrn.cpp
3 //
4 /*
5 ***************************************************************************
6 * Copyright (C) 2002-2003 International Business Machines Corporation *
7 * and others. All rights reserved. *
8 ***************************************************************************
9 */
10
11 #include "unicode/utypes.h"
12
13 #if !UCONFIG_NO_REGULAR_EXPRESSIONS
14
15 #include "unicode/regex.h"
16 #include "uassert.h"
17 #include "uvector.h"
18 #include "uvectr32.h"
19 #include "regexcmp.h"
20 #include "regeximp.h"
21 #include "regexst.h"
22
23 U_NAMESPACE_BEGIN
24
25 //--------------------------------------------------------------------------
26 //
27 // RegexPattern Default Constructor
28 //
29 //--------------------------------------------------------------------------
30 RegexPattern::RegexPattern() {
31 // Init all of this instances data.
32 init();
33
34 // Lazy init of all shared global sets.
35 RegexStaticSets::initGlobals(&fDeferredStatus);
36 };
37
38
39 //--------------------------------------------------------------------------
40 //
41 // Copy Constructor Note: This is a rather inefficient implementation,
42 // but it probably doesn't matter.
43 //
44 //--------------------------------------------------------------------------
45 RegexPattern::RegexPattern(const RegexPattern &other) : UObject(other) {
46 init();
47 *this = other;
48 }
49
50
51
52 //--------------------------------------------------------------------------
53 //
54 // Assignmenet Operator
55 //
56 //--------------------------------------------------------------------------
57 RegexPattern &RegexPattern::operator = (const RegexPattern &other) {
58 if (this == &other) {
59 // Source and destination are the same. Don't do anything.
60 return *this;
61 }
62
63 // Clean out any previous contents of object being assigned to.
64 zap();
65
66 // Give target object a default initialization
67 init();
68
69 // Copy simple fields
70 fPattern = other.fPattern;
71 fFlags = other.fFlags;
72 fLiteralText = other.fLiteralText;
73 fDeferredStatus = other.fDeferredStatus;
74 fMinMatchLen = other.fMinMatchLen;
75 fMaxCaptureDigits = other.fMaxCaptureDigits;
76 fStaticSets = other.fStaticSets;
77
78 fStartType = other.fStartType;
79 fInitialStringIdx = other.fInitialStringIdx;
80 fInitialStringLen = other.fInitialStringLen;
81 *fInitialChars = *other.fInitialChars;
82 *fInitialChars8 = *other.fInitialChars8;
83 fInitialChar = other.fInitialChar;
84
85 // Copy the pattern. It's just values, nothing deep to copy.
86 fCompiledPat->assign(*other.fCompiledPat, fDeferredStatus);
87 fGroupMap->assign(*other.fGroupMap, fDeferredStatus);
88
89 // Copy the Unicode Sets.
90 // Could be made more efficient if the sets were reference counted and shared,
91 // but I doubt that pattern copying will be particularly common.
92 // Note: init() already added an empty element zero to fSets
93 int32_t i;
94 int32_t numSets = other.fSets->size();
95 fSets8 = new Regex8BitSet[numSets];
96 for (i=1; i<numSets; i++) {
97 if (U_FAILURE(fDeferredStatus)) {
98 return *this;
99 }
100 UnicodeSet *sourceSet = (UnicodeSet *)other.fSets->elementAt(i);
101 UnicodeSet *newSet = new UnicodeSet(*sourceSet);
102 if (newSet == NULL) {
103 fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
104 break;
105 }
106 fSets->addElement(newSet, fDeferredStatus);
107 fSets8[i] = other.fSets8[i];
108 }
109
110 return *this;
111 }
112
113
114 //--------------------------------------------------------------------------
115 //
116 // init Shared initialization for use by constructors.
117 // Bring an uninitialized RegexPattern up to a default state.
118 //
119 //--------------------------------------------------------------------------
120 void RegexPattern::init() {
121 fFlags = 0;
122 fDeferredStatus = U_ZERO_ERROR;
123 fMinMatchLen = 0;
124 fMaxCaptureDigits = 1;
125 fStaticSets = NULL;
126 fFrameSize = 0;
127 fDataSize = 0;
128 fStartType = START_NO_INFO;
129 fInitialStringIdx = 0;
130 fInitialStringLen = 0;
131 fInitialChars = NULL;
132 fInitialChars8 = NULL;
133 fInitialChar = 0;
134 fSets8 = NULL;
135
136 fCompiledPat = new UVector32(fDeferredStatus);
137 fGroupMap = new UVector32(fDeferredStatus);
138 fSets = new UVector(fDeferredStatus);
139 fInitialChars = new UnicodeSet;
140 fInitialChars8 = new Regex8BitSet;
141 if (U_FAILURE(fDeferredStatus)) {
142 return;
143 }
144 if (fCompiledPat == NULL || fGroupMap == NULL || fSets == NULL ||
145 fInitialChars == NULL || fInitialChars8 == NULL) {
146 fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
147 return;
148 }
149
150 // Slot zero of the vector of sets is reserved. Fill it here.
151 fSets->addElement((int32_t)0, fDeferredStatus);
152 }
153
154
155 //--------------------------------------------------------------------------
156 //
157 // zap Delete everything owned by this RegexPattern.
158 //
159 //--------------------------------------------------------------------------
160 void RegexPattern::zap() {
161 delete fCompiledPat;
162 fCompiledPat = NULL;
163 int i;
164 for (i=1; i<fSets->size(); i++) {
165 UnicodeSet *s;
166 s = (UnicodeSet *)fSets->elementAt(i);
167 if (s != NULL) {
168 delete s;
169 }
170 }
171 delete fSets;
172 fSets = NULL;
173 delete fGroupMap;
174 fGroupMap = NULL;
175 delete fInitialChars;
176 fInitialChars = NULL;
177 delete fInitialChars8;
178 fInitialChars8 = NULL;
179 delete[] fSets8;
180 fSets8 = NULL;
181 }
182
183
184 //--------------------------------------------------------------------------
185 //
186 // Destructor
187 //
188 //--------------------------------------------------------------------------
189 RegexPattern::~RegexPattern() {
190 zap();
191 };
192
193
194 //--------------------------------------------------------------------------
195 //
196 // Clone
197 //
198 //--------------------------------------------------------------------------
199 RegexPattern *RegexPattern::clone() const {
200 RegexPattern *copy = new RegexPattern(*this);
201 return copy;
202 };
203
204
205 //--------------------------------------------------------------------------
206 //
207 // operator == (comparison) Consider to patterns to be == if the
208 // pattern strings and the flags are the same.
209 //
210 //--------------------------------------------------------------------------
211 UBool RegexPattern::operator ==(const RegexPattern &other) const {
212 UBool r = this->fFlags == other.fFlags &&
213 this->fPattern == other.fPattern &&
214 this->fDeferredStatus == other.fDeferredStatus;
215 return r;
216 }
217
218 //---------------------------------------------------------------------
219 //
220 // compile
221 //
222 //---------------------------------------------------------------------
223 RegexPattern *RegexPattern::compile(
224 const UnicodeString &regex,
225 uint32_t flags,
226 UParseError &pe,
227 UErrorCode &status) {
228
229 if (U_FAILURE(status)) {
230 return NULL;
231 }
232
233 const uint32_t allFlags = UREGEX_CANON_EQ | UREGEX_CASE_INSENSITIVE | UREGEX_COMMENTS |
234 UREGEX_DOTALL | UREGEX_MULTILINE;
235
236 if ((flags & ~allFlags) != 0) {
237 status = U_REGEX_INVALID_FLAG;
238 return NULL;
239 }
240
241 if ((flags & UREGEX_CANON_EQ) != 0) {
242 status = U_REGEX_UNIMPLEMENTED;
243 return NULL;
244 }
245
246 RegexPattern *This = new RegexPattern;
247 if (This == NULL) {
248 status = U_MEMORY_ALLOCATION_ERROR;
249 return NULL;
250 }
251 if (U_FAILURE(This->fDeferredStatus)) {
252 status = This->fDeferredStatus;
253 return NULL;
254 }
255 This->fFlags = flags;
256
257 RegexCompile compiler(This, status);
258 compiler.compile(regex, pe, status);
259
260 return This;
261 };
262
263 //
264 // compile with default flags.
265 //
266 RegexPattern *RegexPattern::compile( const UnicodeString &regex,
267 UParseError &pe,
268 UErrorCode &err)
269 {
270 return compile(regex, 0, pe, err);
271 }
272
273
274
275 //
276 // compile with no UParseErr parameter.
277 //
278 RegexPattern *RegexPattern::compile( const UnicodeString &regex,
279 uint32_t flags,
280 UErrorCode &err)
281 {
282 UParseError pe;
283 return compile(regex, flags, pe, err);
284 }
285
286
287
288 //---------------------------------------------------------------------
289 //
290 // flags
291 //
292 //---------------------------------------------------------------------
293 uint32_t RegexPattern::flags() const {
294 return fFlags;
295 }
296
297
298 //---------------------------------------------------------------------
299 //
300 // matcher(UnicodeString, err)
301 //
302 //---------------------------------------------------------------------
303 RegexMatcher *RegexPattern::matcher(const UnicodeString &input,
304 UErrorCode &status) const {
305 RegexMatcher *retMatcher = matcher(status);
306 if (retMatcher != NULL) {
307 retMatcher->reset(input);
308 }
309 return retMatcher;
310 };
311
312
313
314 //---------------------------------------------------------------------
315 //
316 // matcher(status)
317 //
318 //---------------------------------------------------------------------
319 RegexMatcher *RegexPattern::matcher(UErrorCode &status) const {
320 RegexMatcher *retMatcher = NULL;
321
322 if (U_FAILURE(status)) {
323 return NULL;
324 }
325 if (U_FAILURE(fDeferredStatus)) {
326 status = fDeferredStatus;
327 return NULL;
328 }
329
330 retMatcher = new RegexMatcher(this);
331 if (retMatcher == NULL) {
332 status = U_MEMORY_ALLOCATION_ERROR;
333 return NULL;
334 }
335 return retMatcher;
336 };
337
338
339
340 //---------------------------------------------------------------------
341 //
342 // matches Convenience function to test for a match, starting
343 // with a pattern string and a data string.
344 //
345 //---------------------------------------------------------------------
346 UBool RegexPattern::matches(const UnicodeString &regex,
347 const UnicodeString &input,
348 UParseError &pe,
349 UErrorCode &status) {
350
351 if (U_FAILURE(status)) {return FALSE;}
352
353 UBool retVal;
354 RegexPattern *pat = NULL;
355 RegexMatcher *matcher = NULL;
356
357 pat = RegexPattern::compile(regex, 0, pe, status);
358 matcher = pat->matcher(input, status);
359 retVal = matcher->matches(status);
360
361 delete matcher;
362 delete pat;
363 return retVal;
364 }
365
366
367
368
369 //---------------------------------------------------------------------
370 //
371 // pattern
372 //
373 //---------------------------------------------------------------------
374 UnicodeString RegexPattern::pattern() const {
375 return fPattern;
376 }
377
378
379
380
381 //---------------------------------------------------------------------
382 //
383 // split
384 //
385 //---------------------------------------------------------------------
386 int32_t RegexPattern::split(const UnicodeString &input,
387 UnicodeString dest[],
388 int32_t destCapacity,
389 UErrorCode &status) const
390 {
391 if (U_FAILURE(status)) {
392 return 0;
393 };
394
395 RegexMatcher m(this);
396 int32_t r = m.split(input, dest, destCapacity, status);
397 return r;
398 }
399
400
401
402 //---------------------------------------------------------------------
403 //
404 // dump Output the compiled form of the pattern.
405 // Debugging function only.
406 //
407 //---------------------------------------------------------------------
408 void RegexPattern::dumpOp(int32_t index) const {
409 #if defined(REGEX_DEBUG)
410 static const char * const opNames[] = {URX_OPCODE_NAMES};
411 int32_t op = fCompiledPat->elementAti(index);
412 int32_t val = URX_VAL(op);
413 int32_t type = URX_TYPE(op);
414 int32_t pinnedType = type;
415 if (pinnedType >= sizeof(opNames)/sizeof(char *)) {
416 pinnedType = 0;
417 }
418
419 REGEX_DUMP_DEBUG_PRINTF("%4d %08x %-15s ", index, op, opNames[pinnedType]);
420 switch (type) {
421 case URX_NOP:
422 case URX_DOTANY:
423 case URX_DOTANY_ALL:
424 case URX_DOTANY_PL:
425 case URX_DOTANY_ALL_PL:
426 case URX_FAIL:
427 case URX_CARET:
428 case URX_DOLLAR:
429 case URX_BACKSLASH_G:
430 case URX_BACKSLASH_X:
431 case URX_END:
432 case URX_DOLLAR_M:
433 case URX_CARET_M:
434 // Types with no operand field of interest.
435 break;
436
437 case URX_RESERVED_OP:
438 case URX_START_CAPTURE:
439 case URX_END_CAPTURE:
440 case URX_STATE_SAVE:
441 case URX_JMP:
442 case URX_JMP_SAV:
443 case URX_JMP_SAV_X:
444 case URX_BACKSLASH_B:
445 case URX_BACKSLASH_D:
446 case URX_BACKSLASH_Z:
447 case URX_STRING_LEN:
448 case URX_CTR_INIT:
449 case URX_CTR_INIT_NG:
450 case URX_CTR_LOOP:
451 case URX_CTR_LOOP_NG:
452 case URX_RELOC_OPRND:
453 case URX_STO_SP:
454 case URX_LD_SP:
455 case URX_BACKREF:
456 case URX_STO_INP_LOC:
457 case URX_JMPX:
458 case URX_LA_START:
459 case URX_LA_END:
460 case URX_BACKREF_I:
461 case URX_LB_START:
462 case URX_LB_CONT:
463 case URX_LB_END:
464 case URX_LBN_CONT:
465 case URX_LBN_END:
466 case URX_LOOP_C:
467 case URX_LOOP_DOT_I:
468 // types with an integer operand field.
469 REGEX_DUMP_DEBUG_PRINTF("%d", val);
470 break;
471
472 case URX_ONECHAR:
473 case URX_ONECHAR_I:
474 REGEX_DUMP_DEBUG_PRINTF("%c", val<256?val:'?');
475 break;
476
477 case URX_STRING:
478 case URX_STRING_I:
479 {
480 int32_t lengthOp = fCompiledPat->elementAti(index+1);
481 U_ASSERT(URX_TYPE(lengthOp) == URX_STRING_LEN);
482 int32_t length = URX_VAL(lengthOp);
483 int32_t i;
484 for (i=val; i<val+length; i++) {
485 UChar c = fLiteralText[i];
486 if (c < 32 || c >= 256) {c = '.';}
487 REGEX_DUMP_DEBUG_PRINTF("%c", c);
488 }
489 }
490 break;
491
492 case URX_SETREF:
493 case URX_LOOP_SR_I:
494 {
495 UnicodeString s;
496 UnicodeSet *set = (UnicodeSet *)fSets->elementAt(val);
497 set->toPattern(s, TRUE);
498 for (int32_t i=0; i<s.length(); i++) {
499 REGEX_DUMP_DEBUG_PRINTF("%c", s.charAt(i));
500 }
501 }
502 break;
503
504 case URX_STATIC_SETREF:
505 case URX_STAT_SETREF_N:
506 {
507 UnicodeString s;
508 if (val & URX_NEG_SET) {
509 REGEX_DUMP_DEBUG_PRINTF("NOT ");
510 val &= ~URX_NEG_SET;
511 }
512 UnicodeSet *set = fStaticSets[val];
513 set->toPattern(s, TRUE);
514 for (int32_t i=0; i<s.length(); i++) {
515 REGEX_DUMP_DEBUG_PRINTF("%c", s.charAt(i));
516 }
517 }
518 break;
519
520
521 default:
522 REGEX_DUMP_DEBUG_PRINTF("??????");
523 break;
524 }
525 REGEX_DUMP_DEBUG_PRINTF("\n");
526 #endif
527 }
528
529
530
531 void RegexPattern::dump() const {
532 #if defined(REGEX_DEBUG)
533 int index;
534 int i;
535
536 REGEX_DUMP_DEBUG_PRINTF("Original Pattern: ");
537 for (i=0; i<fPattern.length(); i++) {
538 REGEX_DUMP_DEBUG_PRINTF("%c", fPattern.charAt(i));
539 }
540 REGEX_DUMP_DEBUG_PRINTF("\n");
541 REGEX_DUMP_DEBUG_PRINTF(" Min Match Length: %d\n", fMinMatchLen);
542 REGEX_DUMP_DEBUG_PRINTF(" Match Start Type: %s\n", START_OF_MATCH_STR(fStartType));
543 if (fStartType == START_STRING) {
544 REGEX_DUMP_DEBUG_PRINTF(" Initial match sting: \"");
545 for (i=fInitialStringIdx; i<fInitialStringIdx+fInitialStringLen; i++) {
546 REGEX_DUMP_DEBUG_PRINTF("%c", fLiteralText[i]); // TODO: non-printables, surrogates.
547 }
548
549 } else if (fStartType == START_SET) {
550 int32_t numSetChars = fInitialChars->size();
551 if (numSetChars > 20) {
552 numSetChars = 20;
553 }
554 REGEX_DUMP_DEBUG_PRINTF(" Match First Chars : ");
555 for (i=0; i<numSetChars; i++) {
556 UChar32 c = fInitialChars->charAt(i);
557 if (0x20<c && c <0x7e) {
558 REGEX_DUMP_DEBUG_PRINTF("%c ", c);
559 } else {
560 REGEX_DUMP_DEBUG_PRINTF("%#x ", c);
561 }
562 }
563 if (numSetChars < fInitialChars->size()) {
564 REGEX_DUMP_DEBUG_PRINTF(" ...");
565 }
566 REGEX_DUMP_DEBUG_PRINTF("\n");
567
568 } else if (fStartType == START_CHAR) {
569 REGEX_DUMP_DEBUG_PRINTF(" First char of Match : ");
570 if (0x20 < fInitialChar && fInitialChar<0x7e) {
571 REGEX_DUMP_DEBUG_PRINTF("%c\n", fInitialChar);
572 } else {
573 REGEX_DUMP_DEBUG_PRINTF("%#x\n", fInitialChar);
574 }
575 }
576
577 REGEX_DUMP_DEBUG_PRINTF("\nIndex Binary Type Operand\n"
578 "-------------------------------------------\n");
579 for (index = 0; index<fCompiledPat->size(); index++) {
580 dumpOp(index);
581 }
582 REGEX_DUMP_DEBUG_PRINTF("\n\n");
583 #endif
584 };
585
586
587
588 const char RegexPattern::fgClassID = 0;
589
590 //----------------------------------------------------------------------------------
591 //
592 // regex_cleanup Memory cleanup function, free/delete all
593 // cached memory. Called by ICU's u_cleanup() function.
594 //
595 //----------------------------------------------------------------------------------
596 U_CFUNC UBool
597 regex_cleanup(void) {
598 RegexCompile::cleanup();
599 return TRUE;
600 };
601
602 U_NAMESPACE_END
603 #endif // !UCONFIG_NO_REGULAR_EXPRESSIONS