regex.c (121240B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: bregex.c 8 * Purpose: Regex compiler 9 */ 10 11 #if 0 12 #define STANDALONE_MODE 1 13 #endif 14 15 #ifdef STANDALONE_MODE 16 #define INCLUDE_REGEX 17 #else 18 #define BROADCOM_SDK 19 #endif 20 21 #define START_ANCHOR_CHAR '^' 22 23 #define BITMASK_IS_SET(mask, bit) (mask[bit / WORDS2BITS(1)] & (1 << (bit % WORDS2BITS(1)))) 24 #define BITMASK_SET(mask, bit) mask[bit / WORDS2BITS(1)] |= (1 << (bit % WORDS2BITS(1))) 25 #define BITMASK_UNSET(mask, bit) mask[bit / WORDS2BITS(1)] &= ~(1 << (bit % WORDS2BITS(1))) 26 27 #define OPTIMIZE_PATTERN 1 28 #define DFA_STATE_BLOCK_SIZE 1024 29 #define NFA_BLOCK_SIZE 16300 30 #define NFA_STATE_BLOCK_SIZE 1000 31 #define REGEX_MAX_DFA_STATES 100000 32 #define REGEX_MAX_MEM_USAGE 100000000 /* 100MB */ 33 #define REGEX_MAX_TIMEOUT 1800 * 1000000 /* 30 Mins */ 34 #define NFA_STACK_SIZE 4096 35 36 /* 37 * Enable DFA minimization after computation of DFA from NFA. This is 38 * highly recommeneded as it leads to compressing/optimizing the DFA 39 * to in most cases to 2-4% of the orginal DFA. 40 */ 41 #define DFA_MINIMIZE 1 42 43 /* 44 * Disable nextline character to not be matched when '.' Dot character 45 * is encountered in the regex pattern. 46 */ 47 #define OPT_DONT_MATCH_NL_ON_DOT 0 48 49 #ifdef BROADCOM_SDK 50 /* Enabling the dump of final DFA. */ 51 #define ENABLE_FINAL_DFA_DUMP 0 52 53 /* Enable the dump of inverted DFA before minimization step. */ 54 #define ENABLE_INVERTED_DFA_DUMP 0 55 56 /* Enable the dump of DFA before minimization step. */ 57 #define ENABLE_DFA_DUMP_BEFORE_MINIMIZATION 0 58 59 /* enable the dump of DFA states as the list of NFA state list. */ 60 #define DUMP_DFA_STATE 0 61 62 /* dump the symbol classes that represent the pattern. */ 63 #define DUMP_SYMBOL_CLASSES 0 64 65 #define ENABLE_NFA_DUMP 0 66 67 /* dump regular expression in postfix format */ 68 #define ENABLE_POST_DUMP 0 69 70 #else 71 72 /* Enabling the dump of final DFA. */ 73 #define ENABLE_FINAL_DFA_DUMP 0 74 75 /* Enable the dump of inverted DFA before minimization step. */ 76 #define ENABLE_INVERTED_DFA_DUMP 0 77 78 /* Enable the dump of DFA before minimization step. */ 79 #define ENABLE_DFA_DUMP_BEFORE_MINIMIZATION 0 80 81 /* enable the dump of DFA states as the list of NFA state list. */ 82 #define DUMP_DFA_STATE 0 83 84 /* dump the symbol classes that represent the pattern. */ 85 #define DUMP_SYMBOL_CLASSES 0 86 87 #define ENABLE_NFA_DUMP 0 88 89 /* dump regular expression in postfix format */ 90 #define ENABLE_POST_DUMP 0 91 92 #endif 93 94 #if defined(INCLUDE_REGEX) 95 96 #include <shared/bsl.h> 97 98 #include <assert.h> 99 100 #ifdef BROADCOM_SDK 101 #include <soc/defs.h> 102 #include <soc/util.h> 103 #include <shared/alloc.h> 104 #include <shared/util.h> 105 #include <sal/core/libc.h> 106 #include <sal/core/sync.h> 107 #include <sal/appl/io.h> 108 #include <bcm/error.h> 109 #include <bcm_int/regex_api.h> 110 #define RE_SAL_TOI(s1,base) sal_ctoi((s1),NULL) 111 #define RE_SAL_ITOA(s1,u,base) sal_itoa((s1),u,base,0,0) 112 #define RE_SAL_DPRINT(args) LOG_INFO(BSL_LS_BCM_REGEX, args) 113 114 #else 115 116 #include <stdlib.h> 117 #include <string.h> 118 #include <stdio.h> 119 120 #include "regex_api.h" 121 122 #define MEM_PROFILE 0 123 124 #if MEM_PROFILE==1 125 #define sal_alloc(s,t) re_alloc_wrap((s),(t)) 126 #define sal_free(p) re_free_wrap((p)) 127 #else 128 #define sal_alloc(s,t) malloc((s)) 129 #define sal_free(p) free((p)) 130 #endif 131 132 #define sal_strcpy(s1,s2) strcpy((s1),(s2)) 133 #define RE_SAL_TOI(s1,base) strtol((s1),NULL, (base)) 134 #define RE_SAL_ITOA(s1,u,base) itoa(u,(s1),(base)) 135 #define RE_SAL_DPRINT(p) printf p 136 #define _shr_sort(a,b,s,n) qsort((void*)(a),(b),(s),(n)) 137 #define sal_strlen strlen 138 #define sal_memset memset 139 #define sal_memcpy memcpy 140 #define sal_strdup strdup 141 #define sal_memcmp memcmp 142 143 #if MEM_PROFILE==1 144 145 static int peak_alloc = 0; 146 static int total_alloc = 0; 147 148 typedef struct _mem_profile_s { 149 struct _mem_profile_s *next; 150 void *buf; 151 char loc[32]; 152 int size; 153 } _mem_profile_t; 154 155 static _mem_profile_t *alloc_list = NULL; 156 157 static void *re_alloc_wrap(int size, char *tag) 158 { 159 void *b; 160 _mem_profile_t *mp; 161 162 b = malloc(size+sizeof(_mem_profile_t)); 163 if (b) { 164 mp = (_mem_profile_t*)b; 165 mp->size = size; 166 mp->next = alloc_list; 167 alloc_list = mp; 168 sal_strcpy(mp->loc, tag); 169 mp->buf = b + sizeof(_mem_profile_t); 170 b += sizeof(_mem_profile_t); 171 total_alloc += size; 172 if (total_alloc > peak_alloc) { 173 peak_alloc = total_alloc; 174 } 175 } 176 return b; 177 } 178 179 static void re_free_wrap(void *b) 180 { 181 _mem_profile_t **p = &alloc_list, *tmp; 182 183 while(*p) { 184 if (b == (*p)->buf) { 185 tmp = *p; 186 *p = tmp->next; 187 total_alloc -= tmp->size; 188 free(tmp); 189 break; 190 } else { 191 p = &(*p)->next; 192 } 193 } 194 return; 195 } 196 197 static void re_dump_mem_leak(void) 198 { 199 int total = 0; 200 _mem_profile_t *mp = alloc_list; 201 202 while(mp) { 203 total += mp->size; 204 RE_SAL_DPRINT(("leak at :%s\n", mp->loc)); 205 mp = mp->next; 206 } 207 208 RE_SAL_DPRINT(("Total memory leak : %d bytes\n", total)); 209 if (peak_alloc > 0x100000) { 210 RE_SAL_DPRINT(("Total Peak alloc : %d MB \n", peak_alloc/0x100000)); 211 } else { 212 RE_SAL_DPRINT(("Total Peak alloc : %d KB\n", peak_alloc/1024)); 213 } 214 return; 215 } 216 217 #endif /* MEM_PROFILE */ 218 219 #endif 220 221 typedef struct re_wc { 222 /* 223 If ctrl indicates a meta-character, then c is an actual 224 character. However, if ctrl indicates data, then c is 225 actually a character class, not a character 226 */ 227 unsigned char ctrl; 228 unsigned char c; 229 } re_wc; 230 231 #define POST_EN_DATA 0x01 232 #define POST_EN_META 0x02 233 234 #define POST_ENTRY(p) *(p) 235 236 #define POST_EN_IS_META(p) ((p)->ctrl == POST_EN_META) 237 238 #define WSTR_DATA_VALID(pws) \ 239 (((pws)->ctrl == POST_EN_META) && ((pws)->c == '\0') ? 0 : 1) 240 241 #define WSTR_GET_DATA(pws) (pws)->c 242 243 #define WSTR_GET_DATA_AT_OFF(pws, off) WSTR_GET_DATA((pws)+(off)) 244 245 #define WSTR_PTR_INC(pws,i) (pws) += (i) 246 247 static int wstrlen(re_wc *wstring) 248 { 249 int i = 0; 250 251 while(WSTR_DATA_VALID(wstring)) { 252 i++; 253 WSTR_PTR_INC(wstring,1); 254 } 255 return i; 256 } 257 258 static void add_data_cmn(char c, re_wc **o, int *offset, int *pmax, 259 unsigned char dtype) 260 { 261 re_wc *tmp, *pwc; 262 int max = *pmax, current_size, new_size; 263 264 if (*offset == max) { 265 current_size = max * sizeof(re_wc); 266 new_size = max*2*sizeof(re_wc); 267 tmp = sal_alloc(new_size,"re_wc1"); 268 sal_memset(tmp, 0, current_size); 269 sal_memcpy(tmp, *o, current_size); 270 sal_free(*o); 271 *o = tmp; 272 *pmax = max * 2; 273 } 274 275 /* first add the data type and then data */ 276 pwc = *o + *offset; 277 pwc->ctrl = dtype; 278 pwc->c = c; 279 *offset = *offset + 1; 280 return; 281 } 282 283 #define ADD_DATA(c, po, of, m) \ 284 add_data_cmn((c), (po), (of), (m), POST_EN_DATA) 285 286 #define ADD_META_DATA(c, po, of, m) \ 287 add_data_cmn((c), (po), (of), (m), POST_EN_META) 288 289 static int is_metachar(char c) 290 { 291 if ((c == '(') || (c == '.') || (c == ')') || (c == '+') || 292 (c == '*') || (c == '|') || (c == '{') || (c == '}') || 293 (c == '?') || (c == '\\')) { 294 return 1; 295 } 296 return 0; 297 } 298 299 #define INFINITE -1 300 301 static int parse_digit_from_range(re_wc **pb, char *mc) 302 { 303 /* re_wc *s; */ 304 re_wc *b; 305 int d, ti = 0; 306 char tmp[12]; 307 308 b = *pb; 309 WSTR_PTR_INC(b, 1); 310 311 /* skip whitespaces */ 312 while (WSTR_DATA_VALID(b) && 313 ((WSTR_GET_DATA(b) < '0') || (WSTR_GET_DATA(b) > '9')) && 314 (WSTR_GET_DATA(b) != ',') && (WSTR_GET_DATA(b) != '}')) { 315 WSTR_PTR_INC(b,1); 316 } 317 318 /* s = b;*/ 319 while (WSTR_DATA_VALID(b) && 320 ((WSTR_GET_DATA(b) >= '0') && (WSTR_GET_DATA(b) <= '9'))) { 321 tmp[ti++] = WSTR_GET_DATA(b); 322 WSTR_PTR_INC(b,1); 323 } 324 tmp[ti] = '\0'; 325 326 if (ti > 0) { 327 d = RE_SAL_TOI(tmp,10); 328 } else { 329 d = INFINITE; 330 } 331 332 /* eat everything upto sep */ 333 *mc = '\0'; 334 while (WSTR_DATA_VALID(b) && 335 (WSTR_GET_DATA(b) != ',') && (WSTR_GET_DATA(b) != '}')) { 336 WSTR_PTR_INC(b,1); 337 } 338 *mc = WSTR_GET_DATA(b); 339 *pb = b; 340 return d; 341 } 342 343 static char *classed="dDwWsSnrt."; 344 345 typedef struct re_class_info { 346 char c; 347 re_wc *exp; 348 int (*make_class_str)(int); 349 unsigned int flags; 350 } re_class_info; 351 352 static const unsigned int digit_tbl[] = { 353 0x00000000, 354 0x03ff0000, 355 0x00000000, 356 0x00000000, 357 0x00000000, 358 0x00000000, 359 0x00000000, 360 0x00000000 361 }; 362 363 static const unsigned int wtbl[] = { 364 0x00000000, 365 0x00000000, 366 0x07fffffe, 367 0x07fffffe, 368 0x00000000, 369 0x00000000, 370 0x00000000, 371 0x00000000 372 }; 373 374 static const unsigned int spacetbl[] = { 375 0x00003e00, 376 0x00000001, 377 0x00000000, 378 0x00000000, 379 0x00000000, 380 0x00000000, 381 0x00000000, 382 0x00000000 383 }; 384 385 static const unsigned int isupper[] = { 386 0x00000000, 387 0x00000000, 388 0x07fffffe, 389 0x00000000, 390 0x00000000, 391 0x00000000, 392 0x00000000, 393 0x00000000 394 }; 395 396 static const unsigned int islower[] = { 397 0x00000000, 398 0x00000000, 399 0x00000000, 400 0x07fffffe, 401 0x00000000, 402 0x00000000, 403 0x00000000, 404 0x00000000 405 }; 406 407 static const unsigned int isprintable[] = { 408 0x00000000, 409 0xffffffff, 410 0xffffffff, 411 0x7fffffff, 412 0x00000000, 413 0x00000000, 414 0x00000000, 415 0x00000000 416 }; 417 418 #if (DUMP_SYMBOL_CLASSES == 1) || (ENABLE_FINAL_DFA_DUMP == 1) || (ENABLE_POST_DUMP == 1) 419 static int printable(unsigned char c) 420 { 421 if (isprintable[c/32] & (1 << (c % 32))) { 422 return 1; 423 } 424 return 0; 425 } 426 #endif 427 428 static int re_tolower(int c) 429 { 430 c = c & 0xff; 431 432 return (isupper[c/32] & (1 << (c%32))) ? c + 32 : c; 433 } 434 435 static int re_toupper(int c) 436 { 437 c = c & 0xff; 438 439 return (islower[c/32] & (1 << (c%32))) ? c - 32 : c; 440 } 441 442 static int re_isdigit(int c) 443 { 444 c = c & 0xff; 445 return (digit_tbl[c/32] & (1 << (c%32))) ? 1 : 0; 446 } 447 448 static int iswordc(int c) 449 { 450 c = c & 0xff; 451 return (wtbl[c/32] & (1 << (c%32))) ? 1 : 0; 452 } 453 454 static int re_isspace(int c) 455 { 456 c = c & 0xff; 457 return (spacetbl[c/32] & (1 << (c%32))) ? 1 : 0; 458 } 459 460 461 static int isnextline(int i) 462 { 463 if (i == 0xa) { 464 return 1; 465 } 466 return 0; 467 } 468 static int isreturn(int i) 469 { 470 if (i == 0xd) { 471 return 1; 472 } 473 return 0; 474 } 475 static int istab(int i) 476 { 477 if (i == 0x9) { 478 return 1; 479 } 480 return 0; 481 } 482 483 static int dot(int i) 484 { 485 #if OPT_DONT_MATCH_NL_ON_DOT == 1 486 if (i == 0xa) { 487 return 0; 488 } 489 #endif 490 return 1; 491 } 492 493 static re_class_info class_info[] = { 494 /* \d class */ 495 { 496 'd', NULL, re_isdigit, 1 497 }, 498 /* \D class */ 499 { 500 'D', NULL, re_isdigit, 0 501 }, 502 /* \w class */ 503 { 504 'w', NULL, iswordc, 1 505 }, 506 /* \W class */ 507 { 508 'W', NULL, iswordc, 0 509 }, 510 /* \s class */ 511 { 512 's', NULL, re_isspace, 1 513 }, 514 /* \s class */ 515 { 516 'S', NULL, re_isspace, 0 517 }, 518 { 519 'n', NULL, isnextline, 1 520 }, 521 { 522 'r', NULL, isreturn, 1 523 }, 524 { 525 't', NULL, istab, 1 526 }, 527 { 528 '.', NULL, dot, 1 529 }, 530 }; 531 532 static re_wc *get_class_bitmap(char c, unsigned int *bitmap) 533 { 534 int idx, r; 535 char *pc = classed; 536 re_class_info *pclass_info; 537 int i; 538 539 while(*pc && (*pc != c)) { 540 pc++; 541 } 542 if (!*pc) { 543 RE_SAL_DPRINT(("Failed to find class info : %c\n", c)); 544 return NULL; 545 } 546 idx = pc - classed; 547 pclass_info = &class_info[idx]; 548 549 for (i = 0; i < 8; i++) { 550 bitmap[i] = 0; 551 } 552 553 for (i = 0; i < REGEX_MAX_CHARACTER_CLASSES; i++) { 554 r = !!pclass_info->make_class_str(i); 555 if (r == pclass_info->flags) { 556 bitmap[i/32] |= (1 << (i % 32)); 557 } 558 } 559 /*RE_SAL_DPRINT(("string for class %c : %s\n", c, s)); */ 560 return 0; 561 } 562 563 static int _regex_decode_hex(char *pre, unsigned int *val) 564 { 565 char tmp[5], *re = pre; 566 int d; 567 568 tmp[0] = '0'; 569 tmp[1] = 'x'; 570 tmp[2] = *re; 571 tmp[3] = *(re+1); 572 tmp[4] = '\0'; 573 d = RE_SAL_TOI(tmp,16); 574 *val = (unsigned int ) d; 575 return 0; 576 } 577 578 static int 579 re_make_char_class_bitmap(char **pre, unsigned int *bitmap, int ignore_neg, 580 unsigned int re_flag) 581 { 582 unsigned int lc = 0, tc, d; 583 int esc = 0, neg = 0; 584 int i, range = 0, j, oct[4]; 585 int lcuc = (re_flag & BCM_TR3_REGEX_CFLAG_EXPAND_LCUC) ? 1 : 0; 586 char *re = *pre, *start; 587 char bitmap_tmp[32]; 588 589 if (*re++ != '[') { 590 return -1; 591 } 592 start = re; 593 if (*re == '^') { 594 if (!ignore_neg) { 595 neg = 1; 596 } 597 re++; 598 start = re; 599 } 600 601 sal_memset(bitmap, 0, sizeof(unsigned int)*8); 602 sal_memset(bitmap_tmp, 0, 32); 603 604 for(; *re && !(*re == ']' && !esc); re++) { 605 if ((*re == '-') && !esc && (re != start)) { 606 range = 1; 607 continue; 608 } 609 if (!esc && (*re == '\\')) { 610 esc = 0; 611 switch(*(re+1)) { 612 case 'n': 613 tc = 0xa; 614 re++; 615 break; 616 case 'r': 617 tc = 0xd; 618 re++; 619 break; 620 case 't': 621 tc = 9; 622 re++; 623 break; 624 case 'u': 625 re += 2; 626 case 'x': 627 re += 1; 628 if (_regex_decode_hex(re+1, &d)) { 629 return -1; 630 } 631 re += 2; 632 tc = d; 633 break; 634 default: 635 if ((*re >= '0') && (*re <= '9')) { 636 /* octal */ 637 j = 0; 638 while (*re && (*re >= '0') && (*re <= '9') && (j < 2)) { 639 oct[j++] = *re++; 640 } 641 re--; 642 tc = 0; 643 while(j > 0) { 644 tc = (tc*8) + (oct[j-1] - '0'); 645 j--; 646 } 647 } else { 648 esc = 1; 649 } 650 break; 651 } 652 if (esc) { 653 continue; 654 } 655 } else { 656 tc = *re; 657 } 658 if (!range) { 659 lc = tc; 660 } 661 /* add range from lc to *re */ 662 for (i=lc; i<=tc;i++) { 663 bitmap_tmp[i/8] |= 1 << (i % 8); 664 } 665 esc = 0; 666 range = 0; 667 } 668 *pre = re; 669 670 for (i = 0; i < REGEX_MAX_CHARACTER_CLASSES; i++) { 671 if (!!(bitmap_tmp[i/8] & (1 << (i % 8))) == neg) { 672 continue; 673 } 674 bitmap[i/32] |= 1 << (i % 32); 675 if (lcuc && (wtbl[i/32] & (1 << (i % 32)))) { 676 tc = i + ((i >= 'a') ? -32 : 32 ); 677 bitmap[tc/32] |= 1 << (tc % 32); 678 } 679 } 680 return 0; 681 } 682 683 #ifndef REGEX_DEBUG_STACK 684 685 #define DEFINE_STACK(nt,t) \ 686 struct stack_of_##nt { \ 687 t *pstack; \ 688 t *stack; \ 689 }; 690 691 #define DECLARE_STACK(nt) struct stack_of_##nt 692 693 #define STACK_INIT(s,size,sn) \ 694 (s)->pstack = (s)->stack = sal_alloc(sizeof(*(s)->stack)*size, (sn)) 695 696 #define STACK_RESET(s) (s)->pstack = (s)->stack 697 698 #define STACK_VALID(s) ((s)->stack ? 1 : 0) 699 700 #define STACK_DEINIT(s) if ((s)->stack) sal_free((s)->stack) 701 702 #define STACK_PUSH(s,p) *(s)->pstack++ = (p) 703 704 #define STACK_POP(s) *--(s)->pstack 705 706 #define STACK_EMPTY(s) ((s)->pstack == (s)->stack) 707 708 #else 709 710 #define DEFINE_STACK(nt,t) \ 711 struct stack_of_##nt { \ 712 t *stack; \ 713 int size; \ 714 int top; \ 715 int high; \ 716 } 717 718 #define DECLARE_STACK(nt) struct stack_of_##nt 719 720 #define STACK_INIT(s, sz, sn) \ 721 do { \ 722 (s)->stack = sal_alloc(sizeof(*(s)->stack) * sz, (sn)); \ 723 if ((s)->stack != NULL) { \ 724 (s)->size = sz; \ 725 (s)->top = 0; \ 726 (s)->high = 0; \ 727 } \ 728 } while (0) 729 730 #define STACK_RESET(s) \ 731 assert(NULL != (s)->stack); \ 732 (s)->top = 0 733 734 #define STACK_VALID(s) (NULL != (s)->stack ? 1 : 0) 735 736 #define STACK_DEINIT(s) \ 737 if (NULL != (s)->stack) { \ 738 sal_free((s)->stack); \ 739 } 740 741 #define STACK_PUSH(s,p) \ 742 assert(NULL != (s)->stack); \ 743 assert((s)->size > (s)->top); \ 744 (s)->stack[(s)->top] = (p); \ 745 (s)->top++; \ 746 if ((s)->top > (s)->high) { \ 747 (s)->high = (s)->top; \ 748 } 749 750 #define STACK_POP(s) \ 751 ({ \ 752 assert(NULL != (s)->stack); \ 753 assert((s)->top > 0); \ 754 (s)->top--; \ 755 (s)->stack[(s)->top]; \ 756 }) 757 758 #define STACK_EMPTY(s) (0 == (s)->top) 759 760 #endif /* REGEX_DEBUG_STACK */ 761 762 typedef struct re_transition_group_s { 763 int num_transitions; 764 unsigned int transition_map[8]; 765 } re_transition_group; 766 767 typedef struct re_transition_class_s { 768 int id; 769 int num_transitions; 770 unsigned int transition_map[8]; 771 } re_transition_class; 772 773 typedef struct re_membuf_blk_s { 774 void *buf; 775 int size; 776 int free_offset; 777 int unit_size; 778 struct re_membuf_blk_s *next; 779 } re_membuf_blk_t; 780 781 struct re_dfa_state_t; 782 783 typedef struct avn_s { 784 int balance; 785 struct re_dfa_state_t *data; 786 struct avn_s *ds[2]; 787 } avn_t; 788 789 typedef struct re_dfa_state_t re_dfa_state_t; 790 typedef struct re_dfa_t 791 { 792 re_dfa_state_t **states; 793 int num_states; 794 int size; 795 re_transition_class *class_array; 796 int num_classes; 797 re_membuf_blk_t *nbuf; 798 re_membuf_blk_t *avbuf; 799 avn_t *avtree; 800 } re_dfa_t; 801 802 /* 803 * Represents an NFA state plus zero or one or two arrows exiting. 804 * if c == Match, no arrows out; matching state. 805 * If c == Split, unlabeled arrows to out and out1 (if != NULL). 806 * If c < 256, labeled arrow with character c to out. 807 */ 808 enum 809 { 810 Split = 256, 811 Match = 257 812 }; 813 814 typedef struct re_nfa_state_t re_nfa_state_t; 815 struct re_nfa_state_t 816 { 817 int class; 818 re_nfa_state_t *out; 819 re_nfa_state_t *out1; 820 int id; 821 int lastlist; 822 }; 823 824 #define RE_NFA_STATES(l) (l)->state_map 825 826 #define RE_NFA_LIST_LENGTH(l) (l)->num_states 827 828 #define RE_NFA_STATE_IN_LIST(l,i) (l)->state_map[(i)] 829 830 DEFINE_STACK(nfa_states, re_nfa_state_t *); 831 832 static int state_map_byte_size; 833 834 typedef struct re_nfa_list_t 835 { 836 int num_states; 837 unsigned int *state_map; 838 } re_nfa_list_t; 839 840 #define NFA_SMAP_BYTE_SIZE(n) ((n)->state_map_byte_size) 841 842 #define NFA_SMAP_WORD_SIZE(n) (((n)->num_states+31)/32) 843 844 #define NFA_LIST_RESET(nfa,l) \ 845 { \ 846 (l)->num_states = 0; \ 847 sal_memset((l)->state_map, 0, NFA_SMAP_BYTE_SIZE(nfa)); \ 848 } 849 850 typedef struct re_nfa_t { 851 re_nfa_state_t *root_state; 852 int state_map_byte_size; 853 re_nfa_state_t **state_map; 854 unsigned int *class_map[REGEX_MAX_CHARACTER_CLASSES]; 855 int num_states; 856 int state_map_size; 857 re_membuf_blk_t *nbuf; 858 DECLARE_STACK(nfa_states) *stk; 859 } re_nfa_t; 860 861 static int nfa_free(re_nfa_t *ns); 862 863 static re_membuf_blk_t* 864 _alloc_membuf_block(re_membuf_blk_t **plist, int count, int unit_size) 865 { 866 int size; 867 re_membuf_blk_t *pb; 868 869 size = sizeof(re_membuf_blk_t) + (unit_size * count); 870 pb = sal_alloc(size,"membuf"); 871 sal_memset(pb, 0, size); 872 pb->buf = (void*) (pb+1); 873 pb->free_offset = 0; 874 pb->unit_size = unit_size; 875 pb->size = count; 876 877 pb->next = *plist; 878 *plist = pb; 879 return pb; 880 } 881 882 static void * 883 _alloc_space_for_nfa_state_list(re_dfa_t *pdfa, int llen) 884 { 885 int alloc; 886 re_membuf_blk_t *pb; 887 void *b; 888 889 pb = pdfa->nbuf; 890 alloc = ((pb == NULL) || ((pb->size - (pb->free_offset+1)) < llen)); 891 if (alloc) { 892 pb = _alloc_membuf_block(&pdfa->nbuf, 893 NFA_BLOCK_SIZE, sizeof(unsigned int)); 894 } 895 896 b = pb->buf + sizeof(unsigned int)*pb->free_offset; 897 pb->free_offset += llen; 898 return b; 899 } 900 901 static avn_t* 902 _alloc_space_for_avltree_nodes(re_dfa_t *pdfa, int count, int llen) 903 { 904 int alloc; 905 re_membuf_blk_t *pb; 906 avn_t *b; 907 908 pb = pdfa->avbuf; 909 alloc = ((pb == NULL) || ((pb->size - (pb->free_offset+1)) < llen)); 910 if (alloc) { 911 pb = _alloc_membuf_block(&pdfa->avbuf, count, sizeof(avn_t)); 912 } 913 914 b = pb->buf + sizeof(avn_t)*pb->free_offset; 915 pb->free_offset += llen; 916 return b; 917 } 918 919 static re_nfa_state_t* 920 _alloc_space_for_nfa_nodes(re_nfa_t *pnfa, int count, int llen) 921 { 922 int alloc; 923 re_membuf_blk_t *pb; 924 re_nfa_state_t *b; 925 926 pb = pnfa->nbuf; 927 alloc = ((pb == NULL) || ((pb->size - (pb->free_offset+1)) < llen)); 928 if (alloc) { 929 pb = _alloc_membuf_block(&pnfa->nbuf, count, sizeof(re_nfa_state_t)); 930 } 931 932 b = pb->buf + sizeof(re_nfa_state_t)*pb->free_offset; 933 pb->free_offset += llen; 934 return b; 935 } 936 937 static void _free_buf_blocks(re_membuf_blk_t *nb) 938 { 939 re_membuf_blk_t *t; 940 941 while(nb) { 942 t = nb->next; 943 sal_free(nb); 944 nb = t; 945 } 946 } 947 948 static int listid; 949 950 /* 951 * Represents a DFA state: a cached NFA state list. 952 */ 953 struct re_dfa_state_t 954 { 955 re_nfa_list_t l; 956 unsigned int flags; 957 int *transition_list; 958 }; 959 960 #define RE_DFA_STATE_ARCS(d) (d)->transition_list 961 962 /* 963 * In order to conserve space, flags field is encoded and contains the 964 * following in encoded fashion. 965 * - state_id 966 * - final 967 * - marked 968 * .. 969 */ 970 #define RE_DFA_STATEID(d) ((d)->flags & 0x7ffff) 971 #define RE_DFA_SET_STATEID(d,s) \ 972 (d)->flags = ((d)->flags & 0xfff80000) | ((s) & 0x7ffff) 973 974 #define RE_DFA_IS_FINAL(d) ((((d)->flags >> 19) & 0x1ff) > 0) 975 #define RE_DFA_FINAL(d) (((d)->flags >> 19) & 0x1ff) 976 #define RE_DFA_SET_FINAL(d,m) \ 977 (d)->flags = ((d)->flags & 0xf007ffff) | (((m) & 0x1ff) << 19) 978 979 #define RE_DFA_IS_MARKED(d) (((d)->flags >> 28) & 0x1) 980 #define RE_DFA_SET_MARKED(d,m) \ 981 (d)->flags = ((d)->flags & 0xefffffff) | (((m) & 0x1) << 28) 982 983 #define RE_DFA_IS_ADDED_TO_LIST(d) (((d)->flags >> 29) & 0x1) 984 #define RE_DFA_ADD_TO_LIST(d) (d)->flags |= (1 << 29) 985 986 #define RE_DFA_SET_BLOCK_MSTR(d) (d)->flags |= (1 << 30) 987 988 #define RE_CONNECT_DFA_STATES(d1,d2,c) (d1)->transition_list[(c)] = RE_DFA_STATEID(d2) 989 990 #define DFA_BLOCK_SIZE 1024 991 992 unsigned int mem_cou; 993 994 static re_dfa_state_t* _alloc_dfa_state_block(re_dfa_state_t**tbl, 995 int num_classes) 996 { 997 re_dfa_state_t *ps; 998 int *transition_list = NULL, szs, szt, i, count; 999 1000 count = DFA_BLOCK_SIZE; 1001 szs = sizeof(re_dfa_state_t)*count; 1002 ps = sal_alloc(szs,"dfasb"); 1003 if (!ps) { 1004 goto error; 1005 } 1006 mem_cou += szs; 1007 /* allocate transition list and attach to states */ 1008 szt = sizeof(int)*count*num_classes; 1009 transition_list = sal_alloc(szt,"dfalst"); 1010 if (!transition_list) { 1011 goto error; 1012 } 1013 mem_cou += szt; 1014 sal_memset(ps, 0, szs); 1015 sal_memset(transition_list, 0xff, szt); 1016 1017 for (i = 0; i < count; i++) { 1018 tbl[i] = &ps[i]; 1019 ps[i].transition_list = transition_list; 1020 transition_list += num_classes; 1021 } 1022 1023 RE_DFA_SET_BLOCK_MSTR(&ps[0]); 1024 1025 return ps; 1026 1027 error: 1028 if (ps) { 1029 sal_free(ps); 1030 } 1031 1032 if (transition_list) { 1033 sal_free(transition_list); 1034 } 1035 return NULL; 1036 } 1037 1038 static re_transition_group *_add_to_transition_group_list(re_transition_group **top, int top_size, re_transition_group *this) 1039 { 1040 re_transition_group *new_grp, *ptmp; 1041 int matched = 0, i, j, off; 1042 1043 off = -1; 1044 for (i = 0; i < top_size; i++) { 1045 ptmp = top[i]; 1046 if (ptmp == NULL) { 1047 if (off == -1) { 1048 off = i; 1049 } 1050 continue; 1051 } 1052 matched = 1; 1053 /* compare the tr group */ 1054 for (j = 0; j < 8; j++) { 1055 if (this->transition_map[j] != ptmp->transition_map[j]) { 1056 matched = 0; 1057 break; 1058 } 1059 } 1060 if (matched) { 1061 break; 1062 } 1063 } 1064 1065 if (!matched) { 1066 assert((off >= 0) && (off < top_size)); 1067 new_grp = sal_alloc(sizeof(re_transition_group),"trgrp"); 1068 sal_memcpy(new_grp, this, sizeof(re_transition_group)); 1069 top[off] = new_grp; 1070 } 1071 return 0; 1072 } 1073 1074 #define RE_RESET_TRANSITION_MAP(ptr) sal_memset((ptr), 0, sizeof(re_transition_group)) 1075 1076 #define RE_ADD_TRANSITION_TO_GROUP(ptr,tr) \ 1077 { \ 1078 if (((ptr)->transition_map[(tr)/32] & (1 << ((tr) % 32))) == 0) { \ 1079 (ptr)->num_transitions++; \ 1080 (ptr)->transition_map[(tr)/32] |= (1 << ((tr) % 32)); \ 1081 } \ 1082 } 1083 1084 #if 0 1085 static int 1086 sort_transition_group(void *a, void *b) 1087 { 1088 re_transition_group *pa, *pb; 1089 pa = *((re_transition_group**) a); 1090 pb = *((re_transition_group**) b); 1091 return pa->num_transitions - pb->num_transitions; 1092 } 1093 #endif 1094 1095 static int 1096 sort_transition_class(void *a, void *b) 1097 { 1098 re_transition_class *pa, *pb; 1099 int ma, mb, i, j; 1100 1101 pa = (re_transition_class*) a; 1102 pb = (re_transition_class*) b; 1103 1104 ma = -1; 1105 for (i = 0; i < 8; i++) { 1106 if (pa->transition_map[i] == 0) { 1107 continue; 1108 } 1109 for (j = 0; j < 32; j++) { 1110 if (pa->transition_map[i] & (1 << (j % 32))) { 1111 ma = (i*32) + j; 1112 break; 1113 } 1114 } 1115 if (ma >= 0) { 1116 break; 1117 } 1118 } 1119 mb = -1; 1120 for (i = 0; i < 8; i++) { 1121 if (pb->transition_map[i] == 0) { 1122 continue; 1123 } 1124 for (j = 0; j < 32; j++) { 1125 if (pb->transition_map[i] & (1 << (j % 32))) { 1126 mb = (i*32) + j; 1127 break; 1128 } 1129 } 1130 if (mb >= 0) { 1131 break; 1132 } 1133 } 1134 return ma - mb; 1135 } 1136 1137 static int _regex_add_token_one_char(re_transition_group **top, int top_size, unsigned char c) 1138 { 1139 re_transition_group curmap; 1140 1141 RE_RESET_TRANSITION_MAP(&curmap); 1142 RE_ADD_TRANSITION_TO_GROUP(&curmap, c); 1143 _add_to_transition_group_list(top, top_size, &curmap); 1144 return 0; 1145 } 1146 1147 static int _regex_add_token_multi(re_transition_group **top, int top_size, unsigned int *bitmap) 1148 { 1149 re_transition_group curmap; 1150 int i; 1151 1152 RE_RESET_TRANSITION_MAP(&curmap); 1153 for (i = 0; i < REGEX_MAX_CHARACTER_CLASSES; i++) { 1154 if (bitmap[i/32] & (1 << (i % 32))) { 1155 RE_ADD_TRANSITION_TO_GROUP(&curmap, i); 1156 } 1157 } 1158 _add_to_transition_group_list(top, top_size, &curmap); 1159 return 0; 1160 } 1161 1162 static int 1163 re_add_single_class(re_transition_class *pclass_array, int num_classes, unsigned int c, 1164 re_wc **o, int *used, int *size) 1165 { 1166 int i, class_id; 1167 1168 for (i = 0; i < num_classes; i++) { 1169 #if 0 1170 if (pclass_array[i].num_transitions != 1) { 1171 continue; 1172 } 1173 #endif 1174 if (pclass_array[i].transition_map[c/32] & (1 << (c % 32))) { 1175 class_id = pclass_array[i].id; 1176 if (is_metachar(class_id)) { 1177 ADD_DATA('\\', o, used, size); 1178 } 1179 ADD_DATA(class_id, o, used, size); 1180 return 0; 1181 } 1182 } 1183 return -1; 1184 } 1185 1186 static int 1187 re_add_multi_class(re_transition_class *pclass_array, int num_classes, 1188 unsigned int *bitmap, re_wc **o, int *used, int *size) 1189 { 1190 int i, j, class_id, first = 1, matched; 1191 1192 ADD_DATA('(', o, used, size); 1193 for (i = 0; i < num_classes; i++) { 1194 for (j = 0; j < 8; j++) { 1195 matched = 0; 1196 if (pclass_array[i].transition_map[j] & (bitmap[j])) { 1197 matched = 1; 1198 } 1199 if (matched) { 1200 class_id = pclass_array[i].id; 1201 if (!first) { 1202 ADD_DATA('|', o, used, size); 1203 } 1204 if (is_metachar(class_id)) { 1205 ADD_DATA('\\', o, used, size); 1206 } 1207 ADD_DATA(class_id, o, used, size); 1208 first = 0; 1209 break; 1210 } 1211 } 1212 } 1213 ADD_DATA(')', o, used, size); 1214 return 0; 1215 } 1216 1217 #ifdef OPTIMIZE_PATTERN 1218 /* 1219 * Optimize the patterns. Some of the optimizations are: 1220 * remove trailing .* 1221 */ 1222 static int 1223 re_optimize_patterns(char **patterns, int num_pattern) 1224 { 1225 int p, esc = 0; 1226 char *mark = NULL, *re; 1227 return 0; 1228 for(p=0; p <num_pattern; p++) { 1229 re = patterns[p]; 1230 while(*re) { 1231 if (*re == '\\') { 1232 esc = !!esc; 1233 } else if (!esc && (*re == '.')) { 1234 if (*(re + 1) == '+') { 1235 re++; 1236 mark = re; 1237 re++; 1238 } else if (*(re+1) == '*') { 1239 mark = re; 1240 re++; 1241 } 1242 } else { 1243 mark = NULL; 1244 } 1245 re++; 1246 } 1247 if (mark) { 1248 *mark = '\0'; 1249 } 1250 } 1251 return 0; 1252 } 1253 #endif /* OPTIMIZE_PATTERN */ 1254 1255 static int 1256 re_case_adjust(char **patterns, int num_pattern, unsigned int *re_flags) 1257 { 1258 int pi, esc = 0,remap=0; 1259 char *re; 1260 unsigned int u; 1261 char buf[5]; 1262 1263 for (pi = 0; pi < num_pattern; pi++) { 1264 if ((re_flags[pi] & (BCM_TR3_REGEX_CFLAG_EXPAND_UC | 1265 BCM_TR3_REGEX_CFLAG_EXPAND_LC)) == 0) { 1266 continue; 1267 } 1268 re = patterns[pi]; 1269 while(*re) { 1270 if (*re == '\\') { 1271 esc = !esc; 1272 re++; 1273 continue; 1274 } 1275 if (esc) { 1276 switch(*re) { 1277 case 'x': 1278 case 'X': 1279 if (_regex_decode_hex(re+1, &u)) { 1280 return -1; 1281 } 1282 if (re_flags[pi] & BCM_TR3_REGEX_CFLAG_EXPAND_UC) { 1283 if ((u >= 97) && (u <= 122)) { 1284 u = u - 32; 1285 remap=1; 1286 } 1287 } else if (re_flags[pi] & BCM_TR3_REGEX_CFLAG_EXPAND_LC) { 1288 if ((u >= 65) && (u <= 90)) { 1289 u = u + 32; 1290 remap=1; 1291 } 1292 } 1293 if(remap) 1294 { 1295 sal_memset(buf,0,sizeof(buf)); 1296 RE_SAL_ITOA(buf,u,16); 1297 *(re+1) = *buf; 1298 *(re+2) = *(buf+1); 1299 remap=0; 1300 } 1301 re += 3; 1302 break; 1303 default: 1304 re++; 1305 break; 1306 } 1307 esc = 0; 1308 continue; 1309 } 1310 if (re_flags[pi] & BCM_TR3_REGEX_CFLAG_EXPAND_UC) { 1311 if ((*re >= 97) && (*re <= 122)) { 1312 *re = *re - 32; 1313 } 1314 } else if (re_flags[pi] & BCM_TR3_REGEX_CFLAG_EXPAND_LC) { 1315 if ((*re >= 65) && (*re <= 90)) { 1316 *re = *re + 32; 1317 } 1318 } 1319 re++; 1320 } 1321 } 1322 return 0; 1323 } 1324 1325 /* 1326 * decompose the transitions into unique classes. The idea is to 1327 * extract the least common individual transitions which can 1328 * be uniquely represented. Say for example if the pattern 1329 * is /abc/, it can be represented by character a, b and c. But if 1330 * the pattern is /a.c/, in this case '.' will be represented as 1331 * (\0|\1|\2|...\254|\255), it not only makes the pattern big, also 1332 * the possible symbols in the patterns are 256. Whereas this can be 1333 * represented as 3 symbols, ie. S1 ==> {a}, S2 ==> {b} and 1334 * S3 =={anything not a and b}, so we can now represent the same pattern 1335 * /a.c/ as /S1(S1|S2|S3)S2/ which makes the symbol table size just 3 1336 * instead of 256. 1337 */ 1338 static int 1339 re_make_symbol_classes_from_pattern(char **patterns, int num_pattern, 1340 unsigned int *re_flag, 1341 re_transition_class **pclass_array, int *num_classes) 1342 { 1343 int cl_num = 0, i, j, k, count, p, esc = 0, rv = 0; 1344 unsigned int bitmap[REGEX_MAX_CHARACTER_CLASS_WORDS], oct[4], u; 1345 re_transition_group **transition_list; 1346 re_transition_class *class_array = NULL, *class; 1347 char *re; 1348 #if DUMP_SYMBOL_CLASSES == 1 1349 int lc = -1; 1350 #endif 1351 int first_unused; 1352 int transition_list_max; 1353 int patterns_length = 0; 1354 1355 for (p = 0; p < num_pattern; p++) { 1356 patterns_length += sal_strlen(patterns[p]); 1357 } 1358 /* 1359 * This calculates the maximum number of classes that can be coded in the patterns. 1360 * There are 9 classes that are signified by a backslash followed by a letter (see 1361 * below). Each of those are use two characters. Other character classes (ranges) 1362 * take, at a minimum, two characters for an opening and closing square bracket, two 1363 * characters for the beginning and ending values and one character for the dash for a 1364 * total of five characters. Add to this the single character classes to get a safe 1365 * maximum. 1366 * 1367 * Note that these classes are later condensed into the minimum number of classes 1368 * required which can be, at most, REGEX_MAX_CHARACTER_CLASSES. 1369 */ 1370 #define NUM_2CHAR_CLASSES 9 1371 #define RANGE_SIZE 5 1372 transition_list_max = ((patterns_length - NUM_2CHAR_CLASSES * 2) / RANGE_SIZE) + NUM_2CHAR_CLASSES + REGEX_MAX_CHARACTER_CLASSES; 1373 transition_list = sal_alloc(transition_list_max * sizeof(transition_list[0]), "transition_list"); 1374 1375 sal_memset(transition_list, 0, transition_list_max * sizeof(transition_list[0])); 1376 1377 for(p=0; p <num_pattern; p++) { 1378 re = patterns[p]; 1379 while(*re) { 1380 switch(*re) { 1381 case '\\': 1382 if (!esc) { 1383 esc = 1; 1384 } else { 1385 _regex_add_token_one_char(transition_list, transition_list_max, *re); 1386 esc = 0; 1387 } 1388 break; 1389 case '[': 1390 if (esc) { 1391 _regex_add_token_one_char(transition_list, transition_list_max, *re); 1392 esc = 0; 1393 } else { 1394 re_make_char_class_bitmap(&re, bitmap, 1, 1395 re_flag ? re_flag[p] : 0); 1396 _regex_add_token_multi(transition_list, transition_list_max, bitmap); 1397 } 1398 break; 1399 case '{': 1400 if (esc) { 1401 _regex_add_token_one_char(transition_list, transition_list_max, *re); 1402 esc = 0; 1403 } else { 1404 while (*re != '}') { 1405 re++; 1406 } 1407 } 1408 break; 1409 default: 1410 if (!esc) { 1411 if (!((*re == '(') || (*re == ')') || 1412 (*re == '|') || (*re == '*') || (*re == '+'))) { 1413 if (*re == '.') { 1414 #if 0 1415 get_class_bitmap(*re, bitmap); 1416 _regex_add_token_multi(transition_list, transition_list_max, bitmap); 1417 #endif 1418 } else { 1419 if ((re_flag) && 1420 (re_flag[p] & BCM_TR3_REGEX_CFLAG_EXPAND_LCUC) && 1421 (re_tolower(*re) != re_toupper(*re))) { 1422 _regex_add_token_one_char(transition_list, transition_list_max, re_tolower(*re)); 1423 _regex_add_token_one_char(transition_list, transition_list_max, re_toupper(*re)); 1424 } else { 1425 _regex_add_token_one_char(transition_list, transition_list_max, *re); 1426 } 1427 } 1428 } 1429 } else { 1430 switch(*re) { 1431 case 'd': 1432 case 'D': 1433 case 'w': 1434 case 'W': 1435 case 's': 1436 case 'S': 1437 case 'n': 1438 case 'r': 1439 case 't': 1440 get_class_bitmap(*re, bitmap); 1441 _regex_add_token_multi(transition_list, transition_list_max, bitmap); 1442 break; 1443 case 'u': 1444 re += 2; 1445 case 'x': 1446 if (_regex_decode_hex(re+1, &u)) { 1447 rv = -1; 1448 goto fail; 1449 } 1450 re += 2; 1451 _regex_add_token_one_char(transition_list, transition_list_max, (char)u); 1452 break; 1453 default: 1454 if ((*re >= '0') && (*re <= '9')) { 1455 /* octal */ 1456 j = 0; 1457 while (*re && (*re >= '0') && (*re <= '9') && (j < 2)) { 1458 oct[j++] = *re++; 1459 } 1460 re--; 1461 i = 0; 1462 while(j > 0) { 1463 i = (i*8) + (oct[j-1] - '0'); 1464 j--; 1465 } 1466 _regex_add_token_one_char(transition_list, transition_list_max, i); 1467 } else { 1468 _regex_add_token_one_char(transition_list, transition_list_max, *re); 1469 } 1470 break; 1471 } 1472 esc = 0; 1473 } 1474 break; 1475 } 1476 re++; 1477 } 1478 } 1479 1480 #if OPT_DONT_MATCH_NL_ON_DOT == 1 1481 _regex_add_token_one_char(transition_list, transition_list_max, 0xa); 1482 #endif 1483 1484 sal_memset(bitmap, 0xff, sizeof(bitmap)); 1485 for (i = 0; (NULL != transition_list[i]) && (i < transition_list_max); i++) { 1486 for (j = 0; j < 8; j++) { 1487 bitmap[j] &= ~transition_list[i]->transition_map[j]; 1488 } 1489 } 1490 1491 /* Now add a transition for all characters not already in a transition. */ 1492 for (j = 0; j < COUNTOF(bitmap); j++) { 1493 if (bitmap[j]) { 1494 _regex_add_token_multi(transition_list, transition_list_max, bitmap); 1495 break; 1496 } 1497 } 1498 1499 /* Put characters that are listed in more than one class in their own class. This 1500 * should result in each character appearing in at most one class. */ 1501 for (i = 0; i < REGEX_MAX_CHARACTER_CLASSES; i++) { 1502 /* k counts the number of classes in which a character is found. */ 1503 k = 0; 1504 for (j = 0; j < transition_list_max; j++) { 1505 if (transition_list[j] == NULL) { 1506 continue; 1507 } 1508 if (BITMASK_IS_SET(transition_list[j]->transition_map, i)) { 1509 k++; 1510 } 1511 /* If a character is in more than one class, no need to search for more 1512 * classes. It will definitely be moved to a new class. Proceed to the code 1513 * that removes this character from all classes. */ 1514 if (k >= 2) { 1515 break; 1516 } 1517 } 1518 if (k >= 2) { 1519 for (j = 0; j < transition_list_max; j++) { 1520 if (transition_list[j] == NULL) { 1521 continue; 1522 } 1523 if (BITMASK_IS_SET(transition_list[j]->transition_map, i)) { 1524 /* if this was the last character in the class, delete the class. */ 1525 if (transition_list[j]->num_transitions == 1) { 1526 sal_free(transition_list[j]); 1527 transition_list[j] = NULL; 1528 } else { 1529 BITMASK_UNSET(transition_list[j]->transition_map, i); 1530 transition_list[j]->num_transitions--; 1531 } 1532 } 1533 } 1534 /* Now create a new class with only this character. */ 1535 _regex_add_token_one_char(transition_list, transition_list_max, i); 1536 } 1537 } 1538 1539 /* This variable holds the index of the first unused entry in transition_list. Initialize to 1540 * an invalid index. */ 1541 first_unused = -1; 1542 /* Compact and remove any null class pointers and count the number of classes. */ 1543 for (count = 0, i = 0; i < transition_list_max; i++) { 1544 if (NULL == transition_list[i]) { 1545 if (first_unused < 0) { 1546 first_unused = i; 1547 } 1548 } else { 1549 if (first_unused >= 0) { 1550 transition_list[first_unused] = transition_list[i]; 1551 transition_list[i] = NULL; 1552 for (j = first_unused; j <= i; j++) { 1553 if (NULL == transition_list[j]) { 1554 first_unused = j; 1555 break; 1556 } 1557 } 1558 } 1559 count++; 1560 } 1561 } 1562 1563 class_array = sal_alloc(sizeof(class_array[0]) * REGEX_MAX_CHARACTER_CLASSES, "class_array"); 1564 sal_memset(class_array, 0, sizeof(class_array[0]) * REGEX_MAX_CHARACTER_CLASSES); 1565 cl_num = 0; 1566 for (i = 0; i < count; i++) { 1567 assert(NULL != transition_list[i]); 1568 class = &class_array[cl_num]; 1569 class->num_transitions = 0; 1570 for (j = 0; j < REGEX_MAX_CHARACTER_CLASSES; j++) { 1571 if (BITMASK_IS_SET(transition_list[i]->transition_map, j)) { 1572 BITMASK_SET(class->transition_map, j); 1573 class->num_transitions++; 1574 } 1575 } 1576 if (class->num_transitions) { 1577 cl_num++; 1578 } 1579 } 1580 1581 _shr_sort(class_array, count, sizeof(re_transition_class), sort_transition_class); 1582 1583 for (i = 0; i < cl_num; i++) { 1584 class_array[i].id = i; 1585 } 1586 1587 #if DUMP_SYMBOL_CLASSES == 1 1588 RE_SAL_DPRINT(("\n\nNumber of classes: %d: \n", cl_num)); 1589 for (i = 0; i < cl_num; i++) { 1590 class = &class_array[i]; 1591 lc = -1; 1592 RE_SAL_DPRINT(("\nClass %d: ", class->id)); 1593 for (j = 0; j < REGEX_MAX_CHARACTER_CLASSES; j++) { 1594 if (BITMASK_IS_SET(class->transition_map, j)) { 1595 if (lc == -1) { 1596 lc = j; 1597 } 1598 } else { 1599 if (lc >= 0) { 1600 RE_SAL_DPRINT(("[")); 1601 if (printable(lc)) { 1602 RE_SAL_DPRINT(("%c", lc)); 1603 } else { 1604 RE_SAL_DPRINT(("\\%d", lc)); 1605 } 1606 RE_SAL_DPRINT(("-")); 1607 if (printable(j - 1)) { 1608 RE_SAL_DPRINT(("%c", j - 1)); 1609 } else { 1610 RE_SAL_DPRINT(("\\%d", j - 1)); 1611 } 1612 RE_SAL_DPRINT(("]")); 1613 lc = -1; 1614 } 1615 } 1616 } 1617 if (lc >= 0) { 1618 if (printable(lc)) { 1619 RE_SAL_DPRINT(("[%c", lc)); 1620 } else { 1621 RE_SAL_DPRINT(("[\\%d", lc)); 1622 } 1623 RE_SAL_DPRINT(("-\\255]")); 1624 } 1625 RE_SAL_DPRINT(("\n")); 1626 1627 } 1628 #endif 1629 1630 *pclass_array = class_array; 1631 *num_classes = cl_num; 1632 1633 fail: 1634 /* free up transition_lists */ 1635 if (transition_list) { 1636 for (i = 0; i < transition_list_max; i++) { 1637 if (transition_list[i]) { 1638 sal_free(transition_list[i]); 1639 } 1640 } 1641 sal_free(transition_list); 1642 } 1643 if (rv) { 1644 *num_classes = 0; 1645 *pclass_array = NULL; 1646 sal_free(class_array); 1647 } 1648 return rv; 1649 } 1650 1651 #if ENABLE_POST_DUMP==1 1652 static void dump_post(re_wc *postfix, int detail) 1653 { 1654 re_wc *p; 1655 1656 RE_SAL_DPRINT(("\n-------Postfix for re\n\n")); 1657 for (p = postfix; WSTR_DATA_VALID(p); WSTR_PTR_INC(p, 1)) { 1658 RE_SAL_DPRINT(("%s%d:", POST_EN_IS_META(p) ? "m" : "c", p->c)); 1659 } 1660 RE_SAL_DPRINT(("\n")); 1661 for(p=postfix; WSTR_DATA_VALID(p); WSTR_PTR_INC(p,1)) { 1662 if (POST_EN_IS_META(p)) { 1663 if (printable(p->c)) { 1664 RE_SAL_DPRINT(("%c", p->c)); 1665 } 1666 else 1667 { 1668 RE_SAL_DPRINT(("[m%d]", p->c)); 1669 } 1670 } else { 1671 RE_SAL_DPRINT(("[%d]", p->c)); 1672 } 1673 } 1674 RE_SAL_DPRINT(("\n")); 1675 } 1676 #endif 1677 1678 static re_wc* 1679 re_convert_tokens_to_class(char *re, unsigned int re_flag, 1680 re_transition_class *pclass_array, int num_classes) 1681 { 1682 re_wc *output_wchar; 1683 int re_length, used = 0, esc = 0, mod_re_length = 0, c; 1684 unsigned int d; 1685 int oct[4], j; 1686 unsigned int bitmap[8]; 1687 1688 re_length = sal_strlen(re); 1689 if (!re_length) { 1690 return NULL; 1691 } 1692 1693 /* 1694 * each character uses 2 bytes, since \0 is valid data, so inorder to 1695 * distinguish end of string with \0, we store metadata and character. 1696 */ 1697 mod_re_length = re_length + 1; 1698 if (0 == (re_flag & BCM_TR3_REGEX_CFLAG_ANCHORED)) { 1699 mod_re_length += 2; 1700 } 1701 output_wchar = sal_alloc(mod_re_length * sizeof(re_wc), "re2class"); 1702 used = 0; 1703 1704 /* If the RE is not anchored at the beginning of the packet, then insert an atom that 1705 * will match anything (.*) to begin the RE. */ 1706 if (0 == (re_flag & BCM_TR3_REGEX_CFLAG_ANCHORED)) { 1707 get_class_bitmap('.', bitmap); 1708 if (re_add_multi_class(pclass_array, num_classes, 1709 bitmap, &output_wchar, &used, &mod_re_length)) { 1710 RE_SAL_DPRINT(("\n-------Error re_add_multi_class '.'\n\n")); 1711 goto fail; 1712 } 1713 ADD_DATA('*', &output_wchar, &used, &mod_re_length); 1714 } 1715 1716 while(*re) { 1717 switch(*re) { 1718 case '\\': 1719 if (!esc) { 1720 esc = 1; 1721 } else { 1722 if (re_add_single_class(pclass_array, num_classes, *re, 1723 &output_wchar, &used, &mod_re_length)) { 1724 RE_SAL_DPRINT(("\n-------Error re_add_single_class '\'\n\n")); 1725 goto fail; 1726 } 1727 esc = 0; 1728 } 1729 break; 1730 case '[': 1731 if (esc) { 1732 esc = 0; 1733 if (re_add_single_class(pclass_array, num_classes, 1734 *re, &output_wchar, &used, &mod_re_length)) { 1735 RE_SAL_DPRINT(("\n-------Error re_add_single_class '['\n\n")); 1736 goto fail; 1737 } 1738 } else { 1739 re_make_char_class_bitmap(&re, bitmap, 0, re_flag ? re_flag : 0); 1740 if (re_add_multi_class(pclass_array, num_classes, 1741 bitmap, &output_wchar, &used, &mod_re_length)) { 1742 RE_SAL_DPRINT(("\n-------Error re_add_multi_class '['\n\n")); 1743 goto fail; 1744 } 1745 } 1746 break; 1747 case '{': 1748 if (esc) { 1749 esc = 0; 1750 if (re_add_single_class(pclass_array, num_classes, 1751 *re, &output_wchar, &used, &mod_re_length)) { 1752 RE_SAL_DPRINT(("\n-------Error re_add_single_class '{'\n\n")); 1753 goto fail; 1754 } 1755 } else { 1756 do { 1757 ADD_DATA(*re, &output_wchar, &used, &mod_re_length); 1758 } while (*re++ != '}'); 1759 continue; 1760 } 1761 break; 1762 default: 1763 if (!esc) { 1764 if (*re == '.') { 1765 get_class_bitmap(*re, bitmap); 1766 if (re_add_multi_class(pclass_array, num_classes, 1767 bitmap, &output_wchar, &used, &mod_re_length)) { 1768 RE_SAL_DPRINT(("\n-------Error re_add_multi_class default '.'\n\n")); 1769 goto fail; 1770 } 1771 } else { 1772 if (is_metachar(*re)) { 1773 ADD_DATA(*re, &output_wchar, &used, &mod_re_length); 1774 } else { 1775 if ((re_flag & BCM_TR3_REGEX_CFLAG_EXPAND_LCUC) && 1776 (re_tolower(*re) != re_toupper(*re))) { 1777 ADD_DATA('(', &output_wchar, &used, &mod_re_length); 1778 if (re_add_single_class(pclass_array, num_classes, 1779 re_tolower(*re), &output_wchar, &used, &mod_re_length)) { 1780 RE_SAL_DPRINT(("\n-------Error re_add_single_class meta '{'\n\n")); 1781 goto fail; 1782 } 1783 ADD_DATA('|', &output_wchar, &used, &mod_re_length); 1784 if (re_add_single_class(pclass_array, num_classes, 1785 re_toupper(*re), &output_wchar, &used, &mod_re_length)) { 1786 RE_SAL_DPRINT(("\n-------Error re_add_single_class meta '|'\n\n")); 1787 goto fail; 1788 } 1789 ADD_DATA(')', &output_wchar, &used, &mod_re_length); 1790 } else { 1791 if (re_add_single_class(pclass_array, num_classes, 1792 *re, &output_wchar, &used, &mod_re_length)) { 1793 RE_SAL_DPRINT(("\n-------Error re_add_single_class meta '}'\n\n")); 1794 goto fail; 1795 } 1796 } 1797 } 1798 } 1799 } else { 1800 switch(*re) { 1801 case 'd': 1802 case 'D': 1803 case 'w': 1804 case 'W': 1805 case 's': 1806 case 'S': 1807 case 'n': 1808 case 'r': 1809 case 't': 1810 get_class_bitmap(*re, bitmap); 1811 if (re_add_multi_class(pclass_array, num_classes, 1812 bitmap, &output_wchar, &used, &mod_re_length)) { 1813 RE_SAL_DPRINT(("\n-------Error re_add_multi_class special 'dDwWsSnrt'\n\n")); 1814 goto fail; 1815 } 1816 break; 1817 case 'u': 1818 re += 2; /* ?? */ 1819 case 'x': 1820 if (_regex_decode_hex(re+1, &d)) { 1821 goto fail; 1822 } 1823 re += 2; 1824 if (re_add_single_class(pclass_array, num_classes, d, 1825 &output_wchar, &used, &mod_re_length)) { 1826 RE_SAL_DPRINT(("\n-------Error re_add_single_class 'x'\n\n")); 1827 goto fail; 1828 } 1829 break; 1830 default: 1831 c = *re; 1832 if ((*re >= '0') && (*re <= '9')) { 1833 /* octal */ 1834 j = 0; 1835 while (*re && (*re >= '0') && (*re <= '9') && (j < 2)) { 1836 oct[j++] = *re++; 1837 } 1838 re--; 1839 c = 0; 1840 while(j > 0) { 1841 c = (c*8) + (oct[j-1] - '0'); 1842 j--; 1843 } 1844 } 1845 if (re_add_single_class(pclass_array, num_classes, 1846 c, &output_wchar, &used, &mod_re_length)) { 1847 RE_SAL_DPRINT(("\n-------Error re_add_single_class default\n\n")); 1848 goto fail; 1849 } 1850 break; 1851 } 1852 esc = 0; 1853 } 1854 break; 1855 } 1856 re++; 1857 } 1858 1859 ADD_META_DATA('\0', &output_wchar, &used, &mod_re_length); 1860 1861 #if ENABLE_POST_DUMP==1 1862 RE_SAL_DPRINT(("\nchar re\n")); 1863 dump_post(output_wchar, 1); 1864 #endif 1865 1866 return output_wchar; 1867 1868 fail: 1869 sal_free(output_wchar); 1870 return NULL; 1871 } 1872 1873 static re_wc * re_preprocess(re_wc *re) 1874 { 1875 int min, max; 1876 int l, used = 0, esc = 0, m, c, j, skip; 1877 char mc; 1878 int toklen = 0, star; 1879 int ts[100], stackp, curtok_off = 0; 1880 re_wc *curtok = NULL, *o; 1881 1882 #define pusht(off) ts[stackp++] = (off) 1883 #define popt() (stackp == 0) ? -1 : ts[--stackp] 1884 1885 stackp = 0; 1886 1887 l = wstrlen(re); 1888 if (!l) { 1889 return NULL; 1890 } 1891 1892 m = l+1; 1893 o = sal_alloc(m*sizeof(re_wc),"repreprocess"); 1894 used = 0; 1895 1896 while(WSTR_DATA_VALID(re)) { 1897 /* make sure we have enough room */ 1898 switch(WSTR_GET_DATA(re)) { 1899 case '{': 1900 if (esc) { 1901 ADD_DATA(WSTR_GET_DATA(re), &o, &used, &m); 1902 } else { 1903 #if 0 1904 if (!curtok) { 1905 goto FAIL; 1906 } 1907 #endif 1908 if (toklen <= 0) { 1909 goto FAIL; 1910 } 1911 /* decode min, max */ 1912 min = parse_digit_from_range(&re, &mc); 1913 if (min == INFINITE) { 1914 goto FAIL; 1915 } else if (mc == '}') { 1916 max = min; 1917 } else { 1918 max = parse_digit_from_range(&re, &mc); 1919 } 1920 skip = 1; 1921 1922 /* repeat the previous token */ 1923 if (min) { 1924 /* since token is already put in output once, do it min-1*/ 1925 for (c = 0; c < min; c++) { 1926 if (skip) { 1927 skip--; 1928 continue; 1929 } 1930 j = 0; 1931 while (j < toklen) { 1932 curtok = o + curtok_off; 1933 ADD_DATA(WSTR_GET_DATA_AT_OFF(curtok,j), 1934 &o, &used, &m); 1935 j++; 1936 } 1937 } 1938 } 1939 star = 0; 1940 if (max == INFINITE) { 1941 max = 1; 1942 star = 1; 1943 } else { 1944 max -= min; 1945 } 1946 if (max > 0) { 1947 for (c = 0; c < max; c++) { 1948 if (skip == 0) { 1949 j = 0; 1950 while (j < toklen) { 1951 curtok = o + curtok_off; 1952 ADD_DATA(WSTR_GET_DATA_AT_OFF(curtok,j), 1953 &o, &used, &m); 1954 j++; 1955 } 1956 } else { 1957 skip--; 1958 } 1959 ADD_DATA(star ? '*' : '?', &o, &used, &m); 1960 } 1961 } 1962 curtok = NULL; 1963 toklen = 0; 1964 } 1965 break; 1966 1967 case '(': 1968 pusht(used); 1969 ADD_DATA(WSTR_GET_DATA(re), &o, &used, &m); 1970 break; 1971 1972 case ')': 1973 ADD_DATA(WSTR_GET_DATA(re), &o, &used, &m); 1974 curtok_off = popt(); 1975 toklen = used - curtok_off; 1976 break; 1977 1978 case '\\': 1979 curtok_off = used; 1980 ADD_DATA(WSTR_GET_DATA(re), &o, &used, &m); 1981 WSTR_PTR_INC(re,1); 1982 ADD_DATA(WSTR_GET_DATA(re), &o, &used, &m); 1983 toklen = 2; 1984 break; 1985 1986 default: 1987 curtok_off = used; 1988 toklen = 1; 1989 ADD_DATA(WSTR_GET_DATA(re), &o, &used, &m); 1990 break; 1991 } 1992 WSTR_PTR_INC(re,1); 1993 } 1994 ADD_META_DATA('\0', &o, &used, &m); 1995 return o; 1996 FAIL: 1997 sal_free(o); 1998 return NULL; 1999 } 2000 2001 #define REPOST_STK_SIZE 100 2002 static re_wc* re2post(re_wc *re) 2003 { 2004 int nalt, natom, lmc = 0; 2005 int size, used = 0; 2006 re_wc *dst, *post; /* *start */ 2007 struct { 2008 int nalt; 2009 int natom; 2010 } paren[REPOST_STK_SIZE], *p; 2011 2012 if (!re) { 2013 return NULL; 2014 } 2015 /* start = re; */ 2016 p = paren; 2017 size = wstrlen(re) * 4; 2018 post = dst = sal_alloc(sizeof(re_wc)*size,"re2post"); 2019 nalt = 0; 2020 natom = 0; 2021 for(; WSTR_DATA_VALID(re); WSTR_PTR_INC(re,1)) { 2022 switch(WSTR_GET_DATA(re)) { 2023 case '(': 2024 if (natom > 1) { 2025 --natom; 2026 ADD_META_DATA('.', &dst, &used, &size); 2027 } 2028 if (p >= paren+REPOST_STK_SIZE) { 2029 RE_SAL_DPRINT(("paren stack full..\n")); 2030 goto fail; 2031 } 2032 p->nalt = nalt; 2033 p->natom = natom; 2034 p++; 2035 nalt = 0; 2036 natom = 0; 2037 lmc = 0; 2038 break; 2039 case '|': 2040 if (natom == 0) { 2041 RE_SAL_DPRINT(("No atoms to connect..\n")); 2042 goto fail; 2043 } 2044 while(--natom > 0) { 2045 ADD_META_DATA('.', &dst, &used, &size); 2046 } 2047 nalt++; 2048 lmc = 0; 2049 break; 2050 case ')': 2051 if (p == paren) { 2052 RE_SAL_DPRINT(("point to paren to and yet paren found..\n")); 2053 goto fail; 2054 } 2055 if (natom == 0) { 2056 RE_SAL_DPRINT(("No atom in ) case....\n")); 2057 return NULL; 2058 } 2059 while(--natom > 0) { 2060 ADD_META_DATA('.', &dst, &used, &size); 2061 } 2062 for(; nalt > 0; nalt--) { 2063 ADD_META_DATA('|', &dst, &used, &size); 2064 } 2065 --p; 2066 nalt = p->nalt; 2067 natom = p->natom; 2068 natom++; 2069 lmc = 0; 2070 break; 2071 case '*': 2072 case '+': 2073 case '?': 2074 if (lmc) { 2075 RE_SAL_DPRINT(("error: meta char without atoms\n")); 2076 goto fail; 2077 } 2078 if (natom == 0) { 2079 RE_SAL_DPRINT(("No atom in + or * or ? case....\n")); 2080 goto fail; 2081 } 2082 ADD_META_DATA(WSTR_GET_DATA(re), &dst, &used, &size); 2083 lmc = 1; 2084 break; 2085 default: 2086 lmc = 0; 2087 if (natom > 1) { 2088 --natom; 2089 ADD_META_DATA('.', &dst, &used, &size); 2090 } 2091 if (WSTR_GET_DATA(re) == '\\') { 2092 WSTR_PTR_INC(re,1); 2093 } 2094 ADD_DATA(WSTR_GET_DATA(re), &dst, &used, &size); 2095 natom++; 2096 break; 2097 } 2098 } 2099 if (p != paren) { 2100 return NULL; 2101 } 2102 while(--natom > 0) { 2103 ADD_META_DATA('.', &dst, &used, &size); 2104 } 2105 for(; nalt > 0; nalt--) { 2106 ADD_META_DATA('|', &dst, &used, &size); 2107 } 2108 ADD_META_DATA('\0', &dst, &used, &size); 2109 2110 #if ENABLE_POST_DUMP==1 2111 dump_post(post, 1); 2112 #endif 2113 2114 return post; 2115 2116 fail: 2117 sal_free(dst); 2118 return NULL; 2119 } 2120 2121 2122 /* Allocate and initialize re_nfa_state_t */ 2123 re_nfa_state_t* 2124 new_nfa_state(re_nfa_t *pnfa, int class, re_nfa_state_t *out, re_nfa_state_t *out1) 2125 { 2126 re_nfa_state_t *state, **prev; 2127 int size; 2128 2129 if (pnfa->state_map_size == pnfa->num_states) { 2130 prev = pnfa->state_map; 2131 size = sizeof(re_nfa_state_t*)*(pnfa->state_map_size+NFA_STATE_BLOCK_SIZE); 2132 pnfa->state_map = sal_alloc(size,"nfa_stpp"); 2133 sal_memset(pnfa->state_map, 0, size); 2134 if (prev) { 2135 sal_memcpy(pnfa->state_map, prev, 2136 sizeof(re_nfa_state_t*)*pnfa->state_map_size); 2137 sal_free(prev); 2138 } 2139 2140 pnfa->state_map_size += NFA_STATE_BLOCK_SIZE; 2141 } 2142 2143 2144 /* alloc new block for NFA states if full */ 2145 state = _alloc_space_for_nfa_nodes(pnfa, DFA_STATE_BLOCK_SIZE, 1); 2146 2147 state->lastlist = 0; 2148 state->class = class; 2149 state->out = out; 2150 state->out1 = out1; 2151 state->id = pnfa->num_states++; 2152 pnfa->state_map[state->id] = state; 2153 return state; 2154 } 2155 2156 typedef struct re_nfa_frag_t re_nfa_frag_t; 2157 typedef union re_nfa_ptrl_t re_nfa_ptrl_t; 2158 struct re_nfa_frag_t 2159 { 2160 re_nfa_state_t *start; 2161 re_nfa_ptrl_t *out; 2162 }; 2163 2164 DEFINE_STACK(frag, re_nfa_frag_t); 2165 2166 /* Initialize re_nfa_frag_t struct. */ 2167 static re_nfa_frag_t frag(re_nfa_state_t *start, re_nfa_ptrl_t *out) 2168 { 2169 re_nfa_frag_t n = { start, out }; 2170 return n; 2171 } 2172 2173 /* 2174 * Since the out pointers in the list are always 2175 * uninitialized, we use the pointers themselves 2176 * as storage for the Ptrlists. 2177 */ 2178 union re_nfa_ptrl_t 2179 { 2180 re_nfa_ptrl_t *next; 2181 re_nfa_state_t *s; 2182 }; 2183 2184 /* Create singleton list containing just outp. */ 2185 static re_nfa_ptrl_t* list1(re_nfa_state_t **outp) 2186 { 2187 re_nfa_ptrl_t *l; 2188 2189 l = (re_nfa_ptrl_t*)outp; 2190 l->next = NULL; 2191 return l; 2192 } 2193 2194 /* Patch the list of states at out to point to start. */ 2195 static void patch(re_nfa_ptrl_t *l, re_nfa_state_t *s) 2196 { 2197 re_nfa_ptrl_t *next; 2198 2199 for(; l; l=next) { 2200 next = l->next; 2201 l->s = s; 2202 } 2203 } 2204 2205 /* Join the two lists l1 and l2, returning the combination. */ 2206 static re_nfa_ptrl_t* ptrl_append(re_nfa_ptrl_t *l1, re_nfa_ptrl_t *l2) 2207 { 2208 re_nfa_ptrl_t *oldl1; 2209 2210 oldl1 = l1; 2211 while(l1->next) { 2212 l1 = l1->next; 2213 } 2214 l1->next = l2; 2215 return oldl1; 2216 } 2217 2218 static re_nfa_state_t* post2nfa(re_nfa_t *pnfa, re_wc *postfix, int match_idx) 2219 { 2220 re_wc *p; 2221 re_nfa_frag_t e1, e2, e; 2222 re_nfa_state_t *s; 2223 re_nfa_state_t *matchstate; 2224 DECLARE_STACK(frag) fstack; 2225 2226 if (postfix == NULL) { 2227 return NULL; 2228 } 2229 2230 STACK_INIT(&fstack, 1024, "post_stk"); 2231 2232 if (!STACK_VALID(&fstack)) { 2233 return NULL; 2234 } 2235 2236 #define push(s) STACK_PUSH(&fstack,s) 2237 #define pop() STACK_POP(&fstack) 2238 #define validate_stack if (STACK_EMPTY(&fstack)) break 2239 2240 for(p=postfix; WSTR_DATA_VALID(p); WSTR_PTR_INC(p,1)) { 2241 if (POST_EN_IS_META(p)) { 2242 switch(p->c) { 2243 case '.': /* catenate */ 2244 validate_stack; 2245 e2 = pop(); 2246 validate_stack; 2247 e1 = pop(); 2248 patch(e1.out, e2.start); 2249 push(frag(e1.start, e2.out)); 2250 break; 2251 case '|': /* alternate */ 2252 validate_stack; 2253 e2 = pop(); 2254 validate_stack; 2255 e1 = pop(); 2256 s = new_nfa_state(pnfa, Split, e1.start, e2.start); 2257 push(frag(s, ptrl_append(e1.out, e2.out))); 2258 break; 2259 case '?': /* zero or one */ 2260 validate_stack; 2261 e = pop(); 2262 s = new_nfa_state(pnfa, Split, e.start, NULL); 2263 push(frag(s, ptrl_append(e.out, list1(&s->out1)))); 2264 break; 2265 case '*': /* zero or more */ 2266 validate_stack; 2267 e = pop(); 2268 s = new_nfa_state(pnfa, Split, e.start, NULL); 2269 patch(e.out, s); 2270 push(frag(s, list1(&s->out1))); 2271 break; 2272 case '+': /* one or more */ 2273 validate_stack; 2274 e = pop(); 2275 s = new_nfa_state(pnfa, Split, e.start, NULL); 2276 patch(e.out, s); 2277 push(frag(e.start, list1(&s->out1))); 2278 break; 2279 } 2280 } else { 2281 s = new_nfa_state(pnfa, p->c, NULL, NULL); 2282 push(frag(s, list1(&s->out))); 2283 } 2284 } 2285 2286 e = pop(); 2287 if (!STACK_EMPTY(&fstack)) { 2288 2289 return NULL; 2290 } 2291 STACK_DEINIT(&fstack); 2292 2293 matchstate = new_nfa_state(pnfa, Match + match_idx, NULL, NULL); 2294 patch(e.out, matchstate); 2295 return e.start; 2296 #undef pop 2297 #undef push 2298 } 2299 2300 static void all_states_connected_by_epsilon(re_nfa_t *nfa, 2301 re_nfa_list_t *l, re_nfa_state_t *s); 2302 static void step(re_nfa_t *nfa, re_nfa_list_t*, int, re_nfa_list_t*); 2303 2304 /* Compute initial state list */ 2305 static re_nfa_list_t* closure_0(re_nfa_t *nfa, re_nfa_state_t *start, 2306 re_nfa_list_t *l) 2307 { 2308 listid++; 2309 NFA_LIST_RESET(nfa, l); 2310 all_states_connected_by_epsilon(nfa, l, start); 2311 return l; 2312 } 2313 2314 static void all_states_connected_by_epsilon(re_nfa_t *nfa, 2315 re_nfa_list_t *nlist, re_nfa_state_t *s) 2316 { 2317 DECLARE_STACK(nfa_states) *stk; 2318 2319 stk = nfa->stk; 2320 2321 STACK_RESET(stk); 2322 STACK_PUSH(stk, s); 2323 2324 while(!STACK_EMPTY(stk)) { 2325 s = STACK_POP(stk); 2326 if (s->lastlist == listid) { 2327 continue; 2328 } 2329 2330 if (s->class == Split) { 2331 STACK_PUSH(stk, s->out); 2332 STACK_PUSH(stk, s->out1); 2333 continue; 2334 } 2335 s->lastlist = listid; 2336 nlist->state_map[s->id/32] |= (1 << (s->id % 32)); 2337 nlist->num_states++; 2338 } 2339 } 2340 2341 static void step(re_nfa_t *nfa, re_nfa_list_t *clist, 2342 int c, re_nfa_list_t *nlist) 2343 { 2344 int i, j, word_size; 2345 re_nfa_state_t *s; 2346 unsigned int val, *cmap; 2347 2348 listid++; 2349 NFA_LIST_RESET(nfa, nlist); 2350 2351 cmap = nfa->class_map[c]; 2352 word_size = NFA_SMAP_WORD_SIZE(nfa); 2353 for (i=0; i<word_size; i++) { 2354 val = cmap[i] & clist->state_map[i]; 2355 for (j = 0; val && (j < 32); j++) { 2356 if ((val & (1 << j)) == 0) { 2357 continue; 2358 } 2359 val &= ~(1 << j); 2360 s = nfa->state_map[(i*32)+j]; 2361 all_states_connected_by_epsilon(nfa, nlist, s->out); 2362 } 2363 } 2364 } 2365 2366 /* Compare lists: first by length, then by members. */ 2367 static int 2368 listcmp(re_nfa_list_t *l1, re_nfa_list_t *l2) 2369 { 2370 int i; 2371 2372 if (l1->num_states < l2->num_states) { 2373 return -1; 2374 } 2375 if (l1->num_states > l2->num_states) { 2376 return 1; 2377 } 2378 2379 i = sal_memcmp(l1->state_map, l2->state_map, state_map_byte_size); 2380 i = (i < 0) ? -1 : ((i > 0) ? 1 : 0); 2381 return i; 2382 } 2383 2384 static re_dfa_state_t* 2385 _lookup_dfa_from_cache(re_dfa_t *pdfa, re_nfa_list_t *l) 2386 { 2387 int i; 2388 avn_t *node; 2389 2390 node = pdfa->avtree; 2391 while(node) { 2392 i = listcmp(&node->data->l, l); 2393 if (i == 0) { 2394 return node->data; 2395 } else { 2396 node = (i < 0) ? node->ds[1] : node->ds[0]; 2397 } 2398 } 2399 return NULL; 2400 } 2401 2402 static avn_t *rotate_single(avn_t *root, int dir) 2403 { 2404 avn_t *save = root->ds[!dir]; 2405 root->ds[!dir] = save->ds[dir]; 2406 save->ds[dir] = root; 2407 return save; 2408 } 2409 2410 static avn_t *rotate_double (avn_t *root, int dir) 2411 { 2412 avn_t *save = root->ds[!dir]->ds[dir]; 2413 2414 root->ds[!dir]->ds[dir] = save->ds[!dir]; 2415 save->ds[!dir] = root->ds[!dir]; 2416 root->ds[!dir] = save; 2417 2418 save = root->ds[!dir]; 2419 root->ds[!dir] = save->ds[dir]; 2420 save->ds[dir] = root; 2421 2422 return save; 2423 } 2424 2425 static avn_t * 2426 _add_dfa_state_to_cache(avn_t *root, avn_t *newen, 2427 re_dfa_state_t* d, int *done) 2428 { 2429 int dir, bal, diff; 2430 avn_t *n, *nn; 2431 2432 if (!root) { 2433 newen->balance = 0; 2434 newen->data = d; 2435 newen->ds[0] = newen->ds[1] = NULL; 2436 return newen; 2437 } else { 2438 diff = listcmp(&root->data->l, &d->l); 2439 if (diff == 0) { 2440 return root; 2441 } 2442 dir = (diff < 0); 2443 root->ds[dir] = _add_dfa_state_to_cache(root->ds[dir], newen, d, done); 2444 if ( !*done ) { 2445 root->balance += (dir == 0) ? -1 : +1; 2446 if (root->balance == 0) { 2447 *done = 1; 2448 } else if ((root->balance > 1) || (root->balance < -1)) { 2449 n = root->ds[dir]; 2450 bal = (dir == 0) ? -1 : 1; 2451 if ( n->balance == bal ) { 2452 root->balance = n->balance = 0; 2453 root = rotate_single(root, !dir); 2454 } 2455 else { 2456 n = root->ds[dir]; 2457 nn = n->ds[!dir]; 2458 2459 if (nn->balance == 0) { 2460 root->balance = n->balance = 0; 2461 } else if (nn->balance == bal) { 2462 root->balance = -bal; 2463 n->balance = 0; 2464 } else { 2465 root->balance = 0; 2466 n->balance = bal; 2467 } 2468 2469 nn->balance = 0; 2470 root = rotate_double(root, !dir ); 2471 } 2472 *done = 1; 2473 } 2474 } 2475 } 2476 return root; 2477 } 2478 2479 2480 /* 2481 * Return the cached re_dfa_state_t for list l, 2482 * creating a new one if needed. 2483 */ 2484 static int state_id = 0; 2485 2486 static re_dfa_state_t* 2487 new_dfa_state(re_nfa_list_t *l, int num_classes, re_dfa_t *pdfa, re_nfa_t *nfa) 2488 { 2489 int size, done; 2490 re_dfa_state_t *d, **prev; 2491 avn_t *avn; 2492 2493 /* lookup dfa state (list of nfa states) in cache if exist. */ 2494 d = _lookup_dfa_from_cache(pdfa, l); 2495 if (d) { 2496 return d; 2497 } 2498 2499 /* DFA states are stored as an array. If the number of entries 2500 * in the array is equal to array size, grow the array */ 2501 if (pdfa->num_states == pdfa->size) { 2502 if(pdfa->num_states >= REGEX_MAX_DFA_STATES) { 2503 /* Stop */ 2504 return NULL; 2505 } 2506 prev = pdfa->states; 2507 size = sizeof(re_dfa_state_t*)*(pdfa->size+DFA_BLOCK_SIZE); 2508 pdfa->states = sal_alloc(size,"dfa_stpp"); 2509 if(! pdfa->states) { 2510 pdfa->states = prev; 2511 return NULL; 2512 } 2513 mem_cou += size; 2514 if (prev) { 2515 sal_memcpy(pdfa->states, prev, sizeof(re_dfa_state_t*)*pdfa->size); 2516 sal_free(prev); 2517 } 2518 2519 /* Alloc dfa state block */ 2520 if (!_alloc_dfa_state_block(pdfa->states + pdfa->size, num_classes)) { 2521 return NULL; 2522 } 2523 pdfa->size += DFA_BLOCK_SIZE; 2524 } 2525 2526 d = pdfa->states[pdfa->num_states]; 2527 d->l.state_map = _alloc_space_for_nfa_state_list(pdfa, NFA_SMAP_WORD_SIZE(nfa)); 2528 mem_cou += NFA_SMAP_WORD_SIZE(nfa); 2529 sal_memcpy(d->l.state_map, l->state_map, NFA_SMAP_BYTE_SIZE(nfa)); 2530 d->l.num_states = RE_NFA_LIST_LENGTH(l); 2531 2532 /* alloc space for avl node */ 2533 avn = _alloc_space_for_avltree_nodes(pdfa, DFA_BLOCK_SIZE, 1); 2534 mem_cou += DFA_BLOCK_SIZE; 2535 done = 0; 2536 pdfa->avtree = _add_dfa_state_to_cache(pdfa->avtree, avn, d, &done); 2537 2538 return d; 2539 } 2540 2541 static re_dfa_state_t* 2542 next_dfa_state_on_transition(re_dfa_state_t *d, int c, re_nfa_list_t *l1, 2543 int num_classes, re_dfa_t *pdfa, re_nfa_t *nfa) 2544 { 2545 step(nfa, &d->l, c, l1); 2546 return new_dfa_state(l1, num_classes, pdfa, nfa); 2547 } 2548 2549 static int add_state_to_dfa(re_dfa_t *pdfa, re_dfa_state_t *d) 2550 { 2551 #if DUMP_DFA_STATE == 1 2552 int num_states = 0; 2553 #endif 2554 2555 /* check if already exist */ 2556 if (RE_DFA_IS_ADDED_TO_LIST(d)) { 2557 return 0; 2558 } 2559 RE_DFA_SET_STATEID(d, pdfa->num_states); 2560 RE_DFA_ADD_TO_LIST(d); 2561 2562 #if DUMP_DFA_STATE == 1 2563 { 2564 int k, l, word_size; 2565 word_size = state_map_byte_size / sizeof(unsigned int); 2566 RE_SAL_DPRINT(("DFA State %d represents nfa states:\n", pdfa->num_states)); 2567 for (k = 0; k < word_size; k++) { 2568 if (d->l.state_map[k] == 0) { 2569 continue; 2570 } 2571 for (l = 0; l < 32; l++) { 2572 if (d->l.state_map[k] & (1 << l)) { 2573 num_states++; 2574 RE_SAL_DPRINT((" %d,", (k*32)+l)); 2575 } 2576 } 2577 } 2578 RE_SAL_DPRINT(("\n")); 2579 RE_SAL_DPRINT(("DFA State %d represents %d nfa states total\n\n", pdfa->num_states, num_states)); 2580 } 2581 #endif 2582 pdfa->num_states++; 2583 return 0; 2584 } 2585 2586 static re_dfa_state_t* 2587 get_next_unmarked_dstate(re_dfa_t *l, int skip) 2588 { 2589 int ii; 2590 re_dfa_state_t *d; 2591 2592 if (skip < 0) { 2593 skip = 0; 2594 } 2595 2596 for (ii = skip; ii < l->num_states; ii++) { 2597 d = l->states[ii]; 2598 if(!d) { 2599 return NULL; 2600 } 2601 if (!RE_DFA_IS_MARKED(d)) { 2602 return d; 2603 } 2604 } 2605 return NULL; 2606 } 2607 2608 static int get_transition_list(re_nfa_t *nfa, re_dfa_state_t *d, 2609 unsigned char *transition_list, int *ntr) 2610 { 2611 re_nfa_state_t *s; 2612 int c, i, j, word_size, ctr; 2613 unsigned int val; 2614 unsigned int transition_map[8]; 2615 2616 ctr = *ntr = 0; 2617 sal_memset(transition_map, 0, sizeof(unsigned int)*8); 2618 2619 word_size = NFA_SMAP_WORD_SIZE(nfa); 2620 for (i=0; i<word_size; i++) { 2621 if (d->l.state_map[i] == 0) { 2622 continue; 2623 } 2624 val = d->l.state_map[i]; 2625 for (j = 0; val && (j < 32); j++) { 2626 if ((val & (1 << j)) == 0) { 2627 continue; 2628 } 2629 val &= ~(1 << j); 2630 s = nfa->state_map[(i*32)+j]; 2631 if (s->class >= Match) { 2632 continue; 2633 } 2634 c = s->class & 0xff; 2635 if ((transition_map[c/32] & (1 << (c % 32))) == 0) { 2636 transition_list[ctr++] = c; 2637 transition_map[c/32] |= (1 << (c % 32)); 2638 } 2639 } 2640 } 2641 *ntr = ctr; 2642 return 0; 2643 } 2644 2645 static int dfa_free(re_dfa_t *l); 2646 2647 static int nfa_to_dfa(re_nfa_t *nfa, re_dfa_t *pdfa, int num_classes) 2648 { 2649 re_dfa_state_t *d, *d1; 2650 re_nfa_state_t *s; 2651 int i, k, l, c, word_size, byte_size, from = 0, rv = REGEX_ERROR_NONE, ntr, match_id; 2652 unsigned int val; 2653 re_nfa_list_t l1 = { 0, NULL }; 2654 re_nfa_list_t l2 = { 0, NULL }; 2655 unsigned char transition_list[REGEX_MAX_CHARACTER_CLASSES]; 2656 DECLARE_STACK(nfa_states) nfa_stk; 2657 int running_divisor = 0; 2658 soc_timeout_t timeout; 2659 #if DUMP_DFA_STATE == 1 2660 int *nlist = NULL, nc; 2661 #endif 2662 2663 mem_cou=0; 2664 listid = 0; 2665 2666 byte_size = NFA_SMAP_BYTE_SIZE(nfa); 2667 l1.state_map = sal_alloc(byte_size, "tmp_l1"); 2668 if(!l1.state_map) { 2669 rv = REGEX_ERROR_NO_MEMORY; 2670 goto fail; 2671 } 2672 sal_memset(l1.state_map, 0, byte_size); 2673 l2.state_map = sal_alloc(byte_size, "tmp_l2"); 2674 if(!l2.state_map) { 2675 rv = REGEX_ERROR_NO_MEMORY; 2676 goto fail; 2677 } 2678 sal_memset(l2.state_map, 0, byte_size); 2679 #if DUMP_DFA_STATE == 1 2680 nlist = sal_alloc((nfa->num_states * sizeof(int)), "dbg_nlist"); 2681 if (nlist == NULL) { 2682 RE_SAL_DPRINT(("\nUnable to allocate NFA debug info for %d states\n", nfa->num_states)); 2683 rv = REGEX_ERROR_NO_MEMORY; 2684 goto fail; 2685 } 2686 #endif 2687 2688 STACK_INIT(&nfa_stk, NFA_STACK_SIZE, "nfa_stk"); 2689 nfa->stk = &nfa_stk; 2690 2691 d = new_dfa_state(closure_0(nfa, nfa->root_state, &l1), num_classes, pdfa, nfa); 2692 if (!d) { 2693 rv = REGEX_ERROR_NO_MEMORY; 2694 goto fail; 2695 } 2696 2697 #if DUMP_DFA_STATE == 1 2698 RE_SAL_DPRINT(("\nDFA State representation of %d NFA states:\n", nfa->num_states)); 2699 #endif 2700 2701 add_state_to_dfa(pdfa, d); 2702 2703 while((d = get_next_unmarked_dstate(pdfa, from++))) { 2704 get_transition_list(nfa, d, transition_list, &ntr); 2705 for (i = 0; i < ntr; i++) { 2706 c = transition_list[i]; 2707 d1 = next_dfa_state_on_transition(d, c, &l1, num_classes, pdfa, nfa); 2708 if (!d1) { 2709 rv = REGEX_ERROR_EXPANSION_FAIL; 2710 goto fail; 2711 } 2712 /* Case of memory corruption */ 2713 if (mem_cou >= REGEX_MAX_MEM_USAGE) { /* 100 MB */ 2714 rv = REGEX_ERROR_EXPANSION_FAIL; 2715 goto fail; 2716 } 2717 /* Timeout is checked when there is change in the mem_cou 2718 to reduce the cycles. */ 2719 if ((running_divisor) != (mem_cou & 0xf00000)) { 2720 if (running_divisor == 0) { 2721 soc_timeout_init(&timeout, REGEX_MAX_TIMEOUT, 0); 2722 } 2723 running_divisor = mem_cou & 0xf00000; 2724 if (soc_timeout_check(&timeout)) { 2725 rv = REGEX_ERROR_EXPANSION_FAIL; 2726 goto fail; 2727 } 2728 } 2729 add_state_to_dfa(pdfa, d1); 2730 RE_CONNECT_DFA_STATES(d, d1, c); 2731 } 2732 RE_DFA_SET_MARKED(d, 1); 2733 } 2734 if((from-1) < pdfa->num_states) { 2735 /* Case of stack corruption */ 2736 rv = REGEX_ERROR_EXPANSION_FAIL; 2737 goto fail; 2738 } 2739 2740 /* update the final states distinctly to differentiate nfa fragments */ 2741 word_size = NFA_SMAP_WORD_SIZE(nfa); 2742 for (i = 0; i < pdfa->num_states; i++) { 2743 match_id = -1; 2744 #if DUMP_DFA_STATE == 1 2745 nc = 0; 2746 #endif 2747 d = pdfa->states[i]; 2748 for (k = 0; k < word_size; k++) { 2749 if (d->l.state_map[k] == 0) { 2750 continue; 2751 } 2752 val = d->l.state_map[k]; 2753 for (l = 0; val && (l < 32); l++) { 2754 if ((d->l.state_map[k] & (1 << l)) == 0) { 2755 continue; 2756 } 2757 val &= ~(1 << l); 2758 #if DUMP_DFA_STATE == 1 2759 if (nlist != NULL) { 2760 nlist[nc++] = (k*32)+l; 2761 } 2762 #endif 2763 s = nfa->state_map[(k * 32) + l]; 2764 if ((s->class >= Match) && (match_id == -1)) { 2765 RE_DFA_SET_FINAL(d, (s->class - Match + 1)); 2766 match_id = RE_DFA_FINAL(d); 2767 } 2768 } 2769 } 2770 #if DUMP_DFA_STATE == 1 2771 if ((match_id != -1) && (nlist != NULL)) { 2772 RE_SAL_DPRINT(("DFA FINAL State %d represents %d nfa states : matchid %d\n", 2773 i, nc, RE_DFA_FINAL(d))); 2774 for (k = 0; k < nc; k++) { 2775 RE_SAL_DPRINT((" %d,", nlist[k])); 2776 } 2777 RE_SAL_DPRINT(("\n\n")); 2778 } 2779 #endif 2780 } 2781 2782 fail: 2783 /* free up temp nfa stack */ 2784 STACK_DEINIT(&nfa_stk); 2785 /* free up temp list */ 2786 if (l1.state_map != NULL) { 2787 sal_free(l1.state_map); 2788 } 2789 if (l2.state_map != NULL) { 2790 sal_free(l2.state_map); 2791 } 2792 #if DUMP_DFA_STATE == 1 2793 if (nlist != NULL) { 2794 sal_free(nlist); 2795 } 2796 #endif 2797 2798 if (rv < 0) { 2799 /* error, free up resources. */ 2800 dfa_free(pdfa); 2801 pdfa = NULL; 2802 } 2803 return rv; 2804 } 2805 2806 #ifdef DFA_MINIMIZE 2807 2808 typedef struct re_inv_dfa_s { 2809 int *inv_delta; 2810 int *inv_delta_set; 2811 } re_inv_dfa_t; 2812 2813 static int create_inverted_dfa(re_dfa_t *dfa, re_inv_dfa_t *idfa) 2814 { 2815 int n, c; 2816 int lastDelta = 0, *inv_lists, *inv_list_last; 2817 int s, i, j, t, go_on; 2818 int rv = REGEX_ERROR_NONE; 2819 2820 n = dfa->num_states + 1; 2821 inv_lists = inv_list_last = NULL; 2822 2823 idfa->inv_delta = sal_alloc(sizeof(int) * n*dfa->num_classes,"inv_delta"); 2824 if(!(idfa->inv_delta)) { 2825 rv = REGEX_ERROR_NO_MEMORY; 2826 goto fail; 2827 } 2828 sal_memset(idfa->inv_delta, 0, sizeof(int) * n*dfa->num_classes); 2829 idfa->inv_delta_set = sal_alloc(sizeof(int) *2*n*dfa->num_classes,"inv_delta_set"); 2830 if(!(idfa->inv_delta_set)) { 2831 rv = REGEX_ERROR_NO_MEMORY; 2832 goto fail; 2833 } 2834 sal_memset(idfa->inv_delta_set, 0, sizeof(int) *2*n*dfa->num_classes); 2835 2836 lastDelta = 0; 2837 inv_lists = sal_alloc(sizeof(int)*n,"inv_lists"); 2838 if(!inv_lists) { 2839 rv = REGEX_ERROR_NO_MEMORY; 2840 goto fail; 2841 } 2842 sal_memset(inv_lists, 0, sizeof(int)*n); 2843 inv_list_last = sal_alloc(sizeof(int)*n,"inv_list_last"); 2844 if(!inv_list_last) { 2845 rv = REGEX_ERROR_NO_MEMORY; 2846 goto fail; 2847 } 2848 sal_memset(inv_list_last, 0, sizeof(int)*n); 2849 2850 #if ENABLE_INVERTED_DFA_DUMP == 1 2851 RE_SAL_DPRINT(("\nInverted DFA:\n")); 2852 #endif 2853 for (c = 0; c < dfa->num_classes; c++) { 2854 for (s = 0; s < n; s++) { 2855 inv_list_last[s] = -1; 2856 idfa->inv_delta[(s*dfa->num_classes) + c] = -1; 2857 } 2858 2859 idfa->inv_delta[(0*dfa->num_classes)+c] = 0; 2860 inv_list_last[0] = 0; 2861 2862 for (s = 1; s < n; s++) { 2863 t = dfa->states[s-1]->transition_list[c] + 1; 2864 2865 if (inv_list_last[t] == -1) { 2866 #if ENABLE_INVERTED_DFA_DUMP == 1 2867 RE_SAL_DPRINT((" Class %3d, state %3d, transition %3d, inv_delta[%3d]: %3d\n", 2868 c, s, t-1, (t*dfa->num_classes)+c, s)); 2869 #endif 2870 idfa->inv_delta[(t*dfa->num_classes) + c] = s; 2871 inv_list_last[t] = s; 2872 } 2873 else { 2874 inv_lists[inv_list_last[t]] = s; 2875 inv_list_last[t] = s; 2876 } 2877 } 2878 2879 for (s = 0; s < n; s++) { 2880 i = idfa->inv_delta[(s*dfa->num_classes) + c]; 2881 idfa->inv_delta[(s*dfa->num_classes) + c] = lastDelta; 2882 #if ENABLE_INVERTED_DFA_DUMP == 1 2883 RE_SAL_DPRINT((" Class %3d, state %3d, inv_delta[%3d]: %3d\n", 2884 c, s, (s*dfa->num_classes)+c, lastDelta)); 2885 #endif 2886 j = inv_list_last[s]; 2887 go_on = (i != -1); 2888 while (go_on) { 2889 go_on = (i != j); 2890 #if ENABLE_INVERTED_DFA_DUMP == 1 2891 RE_SAL_DPRINT((" Class %3d, state %3d, inv_delta_set[%3d]: %3d\n", 2892 c, s, lastDelta, i)); 2893 #endif 2894 idfa->inv_delta_set[lastDelta++] = i; 2895 i = inv_lists[i]; 2896 } 2897 idfa->inv_delta_set[lastDelta++] = -1; 2898 } 2899 } 2900 2901 fail: 2902 if(inv_lists) 2903 sal_free(inv_lists); 2904 if(inv_list_last) 2905 sal_free(inv_list_last); 2906 /* idfa freed in calling func*/ 2907 return rv; 2908 } 2909 2910 static void free_inverted_dfa(re_inv_dfa_t *idfa) 2911 { 2912 if (idfa->inv_delta) { 2913 sal_free(idfa->inv_delta); 2914 idfa->inv_delta = NULL; 2915 } 2916 if (idfa->inv_delta_set) { 2917 sal_free(idfa->inv_delta_set); 2918 idfa->inv_delta_set = NULL; 2919 } 2920 } 2921 2922 typedef struct re_dm_block_cb_s { 2923 int *block; 2924 int *b_forward; 2925 int *b_backward; 2926 int num_block; 2927 int b0_off; 2928 int b_max; 2929 } re_dm_block_cb_t; 2930 2931 static int create_block_list(re_dfa_t *l, re_inv_dfa_t *idfa, 2932 re_dm_block_cb_t *bcb) 2933 { 2934 int n = l->num_states + 1, s, found, t, last, b_i; 2935 2936 bcb->block = sal_alloc(sizeof(int)*2*n,"blklist"); 2937 if (bcb->block == NULL) { 2938 goto fail; 2939 } 2940 sal_memset(bcb->block, 0, sizeof(int)*2*n); 2941 bcb->b_forward = sal_alloc(sizeof(int)*2*n,"bbfwd"); 2942 if (bcb->b_forward == NULL) { 2943 goto fail; 2944 } 2945 sal_memset(bcb->b_forward, 0, sizeof(int)*2*n); 2946 bcb->b_backward = sal_alloc(sizeof(int)*2*n,"bbbwd"); 2947 if (bcb->b_backward == NULL) { 2948 goto fail; 2949 } 2950 sal_memset(bcb->b_backward, 0, sizeof(int)*2*n); 2951 2952 bcb->num_block = n; 2953 bcb->b0_off = n; 2954 2955 bcb->b_forward[bcb->b0_off] = 0; 2956 bcb->b_backward[bcb->b0_off] = 0; 2957 bcb->b_forward[0] = bcb->b0_off; 2958 bcb->b_backward[0] = bcb->b0_off; 2959 bcb->block[0] = bcb->b0_off; 2960 bcb->block[bcb->b0_off] = 1; 2961 2962 for (s = 1; s < n; s++) { 2963 int b = bcb->b0_off+1; 2964 found = 0; 2965 while (!found && b <= bcb->num_block) { 2966 t = bcb->b_forward[b]; 2967 2968 if (RE_DFA_IS_FINAL(l->states[s-1])) { 2969 found = RE_DFA_IS_FINAL(l->states[t-1]) && 2970 (RE_DFA_FINAL(l->states[s-1]) == RE_DFA_FINAL(l->states[t-1])); 2971 } 2972 else { 2973 found = !RE_DFA_IS_FINAL(l->states[t-1]); 2974 } 2975 2976 if (found) { 2977 bcb->block[s] = b; 2978 bcb->block[b]++; 2979 2980 last = bcb->b_backward[b]; 2981 bcb->b_forward[last] = s; 2982 bcb->b_forward[s] = b; 2983 2984 bcb->b_backward[b] = s; 2985 bcb->b_backward[s] = last; 2986 } 2987 2988 b++; 2989 } 2990 2991 if (!found) { 2992 bcb->block[s] = b; 2993 bcb->block[b]++; 2994 2995 bcb->b_forward[b] = s; 2996 bcb->b_forward[s] = b; 2997 bcb->b_backward[b] = s; 2998 bcb->b_backward[s] = b; 2999 3000 bcb->num_block++; 3001 } 3002 } 3003 3004 bcb->b_max = bcb->b0_off; 3005 for (b_i = bcb->b0_off+1; b_i <= bcb->num_block; b_i++) { 3006 if (bcb->block[bcb->b_max] < bcb->block[b_i]) { 3007 bcb->b_max = b_i; 3008 } 3009 } 3010 return REGEX_ERROR_NONE; 3011 fail: 3012 /* All free at calling func */ 3013 return REGEX_ERROR_NO_MEMORY; 3014 } 3015 3016 static void free_dm_block(re_dm_block_cb_t *bcb) 3017 { 3018 if (bcb->block) { 3019 sal_free(bcb->block); 3020 bcb->block = NULL; 3021 } 3022 if (bcb->b_forward) { 3023 sal_free(bcb->b_forward); 3024 bcb->b_forward = NULL; 3025 } 3026 if (bcb->b_backward) { 3027 sal_free(bcb->b_backward); 3028 bcb->b_backward = NULL; 3029 } 3030 } 3031 3032 static re_dfa_t * dfa_minimize(re_dfa_t *dfa_list) 3033 { 3034 int numStates = dfa_list->num_states, n, c; 3035 re_dm_block_cb_t bcb; 3036 int *l_forward, *l_backward, anchorL; 3037 re_inv_dfa_t idfa; 3038 int numSplit, *twin, *vsd, *vd, numd; 3039 int s, i, j, t, last, blk_i; 3040 int index, indexD, indexTwin, b; 3041 int *trans, *move, amount, size; 3042 unsigned int *kill; 3043 int B_j, a, min_s; 3044 3045 if (dfa_list->num_states == 0) { 3046 return dfa_list; 3047 } 3048 3049 #ifndef SEARCH_FOR_MORE_MATCHES_AFTER_MATCH 3050 /* 3051 Eliminate transitions from final states before inverting 3052 the DFA. (Such states can arise when there are regexes 3053 with wildcards/ranges.) This code assumes that only the 3054 first match is necessary -- there will be no further 3055 searches for "greedy" regexes/matches. Once one of the 3056 regexes is a match, the match ID will be returned. For 3057 non-anchored regexes, this can save considerable state 3058 space. Also, all the transitions from final states are 3059 not actually installed in the hardware anyway - what 3060 actually gets installed are jump to idle transitions. 3061 This code eliminates not only those extra transitions, 3062 but also results in eliminating any states that become 3063 non-reachable as a result of removing transitions from 3064 final states, as those states will then be removed when 3065 minimizing the DFA. 3066 */ 3067 3068 for (i = 0; i < numStates; i++) { 3069 if (RE_DFA_FINAL(dfa_list->states[i])) { 3070 for (c = 0; c < dfa_list->num_classes; c++) { 3071 dfa_list->states[i]->transition_list[c] = -1; 3072 } 3073 } 3074 } 3075 #endif 3076 l_forward = l_backward = twin = vsd = vd = trans = move = NULL; 3077 kill = NULL; 3078 n = numStates+1; 3079 3080 sal_memset(&idfa, 0, sizeof(re_inv_dfa_t)); 3081 sal_memset(&bcb, 0, sizeof(re_dm_block_cb_t)); 3082 if (create_inverted_dfa(dfa_list, &idfa)) { 3083 goto fail; 3084 } 3085 3086 /* create blocks */ 3087 if (create_block_list(dfa_list, &idfa, &bcb)) { 3088 goto fail; 3089 } 3090 3091 l_forward = sal_alloc(sizeof(int)*((n*dfa_list->num_classes)+1),"lfwd"); 3092 if(!l_forward) { 3093 goto fail; 3094 } 3095 sal_memset(l_forward, 0, sizeof(int)*((n*dfa_list->num_classes)+1)); 3096 l_backward = sal_alloc(sizeof(int)*((n*dfa_list->num_classes)+1),"lbwd"); 3097 if(!l_backward) { 3098 goto fail; 3099 } 3100 sal_memset(l_backward, 0, sizeof(int)*((n*dfa_list->num_classes)+1)); 3101 3102 anchorL = n*dfa_list->num_classes; 3103 3104 l_forward[anchorL] = anchorL; 3105 l_backward[anchorL] = anchorL; 3106 3107 blk_i = (bcb.b_max == bcb.b0_off) ? bcb.b0_off+1 : bcb.b0_off; 3108 3109 index = (blk_i - bcb.b0_off)*dfa_list->num_classes; 3110 while (index < (blk_i + 1 - bcb.b0_off)*dfa_list->num_classes) { 3111 last = l_backward[anchorL]; 3112 l_forward[last] = index; 3113 l_forward[index] = anchorL; 3114 l_backward[index] = last; 3115 l_backward[anchorL] = index; 3116 index++; 3117 } 3118 3119 while (blk_i <= bcb.num_block) { 3120 if (blk_i != bcb.b_max) { 3121 index = (blk_i - bcb.b0_off)*dfa_list->num_classes; 3122 while (index < (blk_i + 1 - bcb.b0_off)*dfa_list->num_classes) { 3123 last = l_backward[anchorL]; 3124 l_forward[last] = index; 3125 l_forward[index] = anchorL; 3126 l_backward[index] = last; 3127 l_backward[anchorL] = index; 3128 index++; 3129 } 3130 } 3131 blk_i++; 3132 } 3133 3134 twin = sal_alloc(sizeof(int)*2*n,"twin"); 3135 if(!twin){ 3136 goto fail; 3137 } 3138 sal_memset(twin, 0, sizeof(int)*2*n); 3139 vsd = sal_alloc(sizeof(int)*2*n,"vsd"); 3140 if(!vsd) { 3141 goto fail; 3142 } 3143 sal_memset(vsd, 0, sizeof(int)*2*n); 3144 vd = sal_alloc(sizeof(int)*n,"vd"); 3145 if(!vd) { 3146 goto fail; 3147 } 3148 sal_memset(vd, 0, sizeof(int)*n); 3149 3150 while (l_forward[anchorL] != anchorL) { 3151 int B_j_a = l_forward[anchorL]; 3152 l_forward[anchorL] = l_forward[B_j_a]; 3153 l_backward[l_forward[anchorL]] = anchorL; 3154 l_forward[B_j_a] = 0; 3155 B_j = bcb.b0_off + B_j_a / dfa_list->num_classes; 3156 a = B_j_a % dfa_list->num_classes; 3157 3158 numd = 0; 3159 s = bcb.b_forward[B_j]; 3160 while (s != B_j) { 3161 t = idfa.inv_delta[(s*dfa_list->num_classes) + a]; 3162 while (idfa.inv_delta_set[t] != -1) { 3163 vd[numd++] = idfa.inv_delta_set[t++]; 3164 } 3165 s = bcb.b_forward[s]; 3166 } 3167 3168 numSplit = 0; 3169 3170 for (indexD = 0; indexD < numd; indexD++) { 3171 s = vd[indexD]; 3172 blk_i = bcb.block[s]; 3173 vsd[blk_i] = -1; 3174 twin[blk_i] = 0; 3175 } 3176 3177 for (indexD = 0; indexD < numd; indexD++) { 3178 s = vd[indexD]; 3179 blk_i = bcb.block[s]; 3180 3181 if (vsd[blk_i] < 0) { 3182 vsd[blk_i] = 0; 3183 t = bcb.b_forward[blk_i]; 3184 while (t != blk_i && (t != 0 || bcb.block[0] == B_j) && 3185 (t == 0 || bcb.block[dfa_list->states[t-1]->transition_list[a]+1] == B_j)) { 3186 vsd[blk_i]++; 3187 t = bcb.b_forward[t]; 3188 } 3189 } 3190 } 3191 3192 for (indexD = 0; indexD < numd; indexD++) { 3193 s = vd[indexD]; 3194 blk_i = bcb.block[s]; 3195 3196 if (vsd[blk_i] != bcb.block[blk_i]) { 3197 int B_k = twin[blk_i]; 3198 if (B_k == 0) { 3199 B_k = ++bcb.num_block; 3200 bcb.b_forward[B_k] = B_k; 3201 bcb.b_backward[B_k] = B_k; 3202 3203 twin[blk_i] = B_k; 3204 3205 twin[numSplit++] = blk_i; 3206 } 3207 3208 bcb.b_forward[bcb.b_backward[s]] = bcb.b_forward[s]; 3209 bcb.b_backward[bcb.b_forward[s]] = bcb.b_backward[s]; 3210 3211 last = bcb.b_backward[B_k]; 3212 bcb.b_forward[last] = s; 3213 bcb.b_forward[s] = B_k; 3214 bcb.b_backward[s] = last; 3215 bcb.b_backward[B_k] = s; 3216 3217 bcb.block[s] = B_k; 3218 bcb.block[B_k]++; 3219 bcb.block[blk_i]--; 3220 3221 vsd[blk_i]--; 3222 } 3223 } 3224 3225 for (indexTwin = 0; indexTwin < numSplit; indexTwin++) { 3226 int blk_i = twin[indexTwin]; 3227 int B_k = twin[blk_i]; 3228 for (c = 0; c < dfa_list->num_classes; c++) { 3229 int B_i_c = (blk_i-bcb.b0_off)*dfa_list->num_classes+c; 3230 int B_k_c = (B_k-bcb.b0_off)*dfa_list->num_classes+c; 3231 if (l_forward[B_i_c] > 0) { 3232 last = l_backward[anchorL]; 3233 l_backward[anchorL] = B_k_c; 3234 l_forward[last] = B_k_c; 3235 l_backward[B_k_c] = last; 3236 l_forward[B_k_c] = anchorL; 3237 } 3238 else { 3239 if (bcb.block[blk_i] <= bcb.block[B_k]) { 3240 last = l_backward[anchorL]; 3241 l_backward[anchorL] = B_i_c; 3242 l_forward[last] = B_i_c; 3243 l_backward[B_i_c] = last; 3244 l_forward[B_i_c] = anchorL; 3245 } 3246 else { 3247 last = l_backward[anchorL]; 3248 l_backward[anchorL] = B_k_c; 3249 l_forward[last] = B_k_c; 3250 l_backward[B_k_c] = last; 3251 l_forward[B_k_c] = anchorL; 3252 } 3253 } 3254 } 3255 } 3256 } 3257 3258 free_inverted_dfa(&idfa); 3259 sal_free(twin); 3260 sal_free(vsd); 3261 sal_free(vd); 3262 twin = vsd = vd = NULL; 3263 3264 trans = sal_alloc(sizeof(int)*numStates,"trans"); 3265 if(!trans) { 3266 goto fail; 3267 } 3268 sal_memset(trans, 0, sizeof(int)*numStates); 3269 3270 size = ((numStates+31)/32)*sizeof(unsigned int); 3271 kill = sal_alloc(size,"kill"); 3272 if(!kill) { 3273 goto fail; 3274 } 3275 sal_memset(kill, 0, size); 3276 3277 move = sal_alloc(sizeof(int)*numStates,"move"); 3278 if(!move) { 3279 goto fail; 3280 } 3281 sal_memset(move, 0, sizeof(int)*numStates); 3282 3283 for (b = bcb.b0_off+1; b <= bcb.num_block; b++) { 3284 s = bcb.b_forward[b]; 3285 min_s = s; 3286 for (; s != b; s = bcb.b_forward[s]) { 3287 if (min_s > s) { 3288 min_s = s; 3289 } 3290 } 3291 min_s--; 3292 for (s = bcb.b_forward[b]-1; s != b-1; s = bcb.b_forward[s+1]-1) { 3293 trans[s] = min_s; 3294 kill[s/32] |= (s != min_s) ? (1 << (s % 32)) : 0 ; 3295 } 3296 } 3297 3298 free_dm_block(&bcb); 3299 3300 sal_free(l_forward); 3301 sal_free(l_backward); 3302 l_forward = l_backward = NULL; 3303 3304 amount = 0; 3305 size = ((numStates+31)/32)*sizeof(unsigned int); 3306 for (i = 0; i < numStates; i++) { 3307 if (kill[i/32] & (1 << (i%32))) { 3308 amount++; 3309 } else { 3310 move[i] = amount; 3311 } 3312 } 3313 3314 for (i = 0, j = 0; i < numStates; i++) { 3315 if ((kill[i/32] & (1 << (i % 32))) == 0) { 3316 for (c = 0; c < dfa_list->num_classes; c++) { 3317 if ( dfa_list->states[i]->transition_list[c] >= 0 ) { 3318 dfa_list->states[j]->transition_list[c] = trans[ dfa_list->states[i]->transition_list[c] ]; 3319 dfa_list->states[j]->transition_list[c] -= move[ dfa_list->states[j]->transition_list[c] ]; 3320 } 3321 else { 3322 dfa_list->states[j]->transition_list[c] = dfa_list->states[i]->transition_list[c]; 3323 } 3324 } 3325 3326 RE_DFA_SET_FINAL(dfa_list->states[j], RE_DFA_FINAL(dfa_list->states[i])); 3327 j++; 3328 } 3329 } 3330 numStates = j; 3331 3332 sal_free(trans); 3333 sal_free(kill); 3334 sal_free(move); 3335 trans = move = NULL; 3336 kill = NULL; 3337 /* free up unused states */ 3338 if (j % DFA_BLOCK_SIZE) { 3339 j += DFA_BLOCK_SIZE - (j % DFA_BLOCK_SIZE); 3340 } 3341 3342 /* 3343 Note, this unusual loop and free is because of the way 3344 the transition list is allocated in blocks of 3345 DFA_BLOCK_SIZE. 3346 */ 3347 3348 for (; j < dfa_list->num_states; j += DFA_BLOCK_SIZE) { 3349 sal_free(dfa_list->states[j]->transition_list); 3350 sal_free(dfa_list->states[j]); 3351 } 3352 3353 dfa_list->num_states = numStates; 3354 return dfa_list; 3355 3356 fail: 3357 free_inverted_dfa(&idfa); 3358 free_dm_block(&bcb); 3359 dfa_free(dfa_list); 3360 if(l_forward) { 3361 sal_free(l_forward); 3362 } 3363 if(l_backward) { 3364 sal_free(l_backward); 3365 } 3366 if(twin) { 3367 sal_free(twin); 3368 } 3369 if(vsd) { 3370 sal_free(vsd); 3371 } 3372 if(vd) { 3373 sal_free(vd); 3374 } 3375 if(trans) { 3376 sal_free(trans); 3377 } 3378 if(move) { 3379 sal_free(move); 3380 } 3381 if(kill) { 3382 sal_free(kill); 3383 } 3384 3385 return NULL; 3386 } 3387 3388 #endif /* DFA_MINIMIZE */ 3389 3390 #if ENABLE_NFA_DUMP == 1 3391 static void dump_nfa(re_nfa_t *nfa, re_nfa_state_t *root) 3392 { 3393 int i; 3394 re_nfa_state_t *s; 3395 3396 RE_SAL_DPRINT(("Entry state is : %d\n", root->id)); 3397 for (i=0; i<nfa->num_states; i++) { 3398 s = nfa->state_map[i]; 3399 if (s->class >= Match) { 3400 RE_SAL_DPRINT(("State [FINAL match %d] %d:\n", (s->class - Match), s->id)); 3401 } else { 3402 RE_SAL_DPRINT(("State %d:\n", s->id)); 3403 } 3404 if (s->class == Split) { 3405 RE_SAL_DPRINT(("\t With epsilon to out %3d\n", s->out->id)); 3406 RE_SAL_DPRINT(("\t With epsilon to out1 %3d\n", s->out1->id)); 3407 } else { 3408 if (s->out) { 3409 RE_SAL_DPRINT(("\tWith input %3d to out %3d\n", s->class, s->out->id)); 3410 } 3411 if (s->out1) { 3412 RE_SAL_DPRINT(("\tWith input %3d to out1 %3d\n", s->class, s->out1->id)); 3413 } 3414 } 3415 } 3416 } 3417 #endif 3418 3419 /* 3420 * Create a single NFA corresponding to all the patterns. 3421 * The function does the following: 3422 * - convert each pattern to class representation 3423 * - preprocess the pattern and expand it for example 3424 * \d is expanded to (0|1|2|..|8|9) etc. 3425 * - convert the pattern to postfix represetation. Note 3426 * the postfix representation is not string but utilizes 2bytes 3427 * to represent the character since the pattern might have \0 in 3428 * between which would terminate the string. 3429 * - postfix representation of the pattern is then converted to NFA. 3430 * - All the NFA are joined together using Split (epsilon transition.) 3431 * - If all goes well, the final NFA is returned back to caller. 3432 */ 3433 static int make_nfa(char **re, unsigned int *res_flags, 3434 int num_pattern, re_nfa_t **ppnfa, 3435 re_transition_class *pclass_array, int num_classes) 3436 { 3437 re_wc *post; 3438 re_nfa_state_t **sub_nfa = NULL, *n1, *n2, *s; 3439 re_nfa_t *pnfa; 3440 int pattern; 3441 re_wc *re1, *re2; 3442 int rv = REGEX_ERROR_NONE, i; 3443 3444 pnfa = sal_alloc(sizeof(*pnfa), "NFA"); 3445 if(!pnfa) { 3446 rv = REGEX_ERROR_NO_MEMORY; 3447 goto fail; 3448 } 3449 sal_memset(pnfa, 0, sizeof(*pnfa)); 3450 3451 /* 3452 * array to store the individual NFA strands till they are all 3453 * combined into single final NFA. 3454 */ 3455 sub_nfa = sal_alloc(sizeof(sub_nfa[0]) * num_pattern, "sub_nfa"); 3456 if (sub_nfa == NULL) { 3457 rv = REGEX_ERROR_NO_MEMORY; 3458 goto fail; 3459 } 3460 3461 for (pattern=0; pattern < num_pattern; pattern++) { 3462 re1 = re_convert_tokens_to_class(re[pattern], 3463 res_flags ? res_flags[pattern] : 0, 3464 pclass_array, num_classes); 3465 if (!re1) { 3466 rv = REGEX_ERROR_EXPANSION_FAIL; 3467 RE_SAL_DPRINT(("\n-------Error %d converting tokens\n\n", rv)); 3468 goto fail; 3469 } 3470 re2 = re_preprocess(re1); 3471 sal_free(re1); 3472 if (!re2) { 3473 rv = REGEX_ERROR_EXPANSION_FAIL; 3474 RE_SAL_DPRINT(("\n-------Error %d re_preprocess\n\n", rv)); 3475 goto fail; 3476 } 3477 3478 post = re2post(re2); 3479 sal_free(re2); 3480 if (!post) { 3481 rv = REGEX_ERROR_NO_POST; 3482 RE_SAL_DPRINT(("\n-------Error %d re2post\n\n", rv)); 3483 goto fail; 3484 } 3485 sub_nfa[pattern] = post2nfa(pnfa, post, pattern); 3486 sal_free(post); 3487 if (sub_nfa[pattern] == NULL) { 3488 rv = REGEX_ERROR_EXPANSION_FAIL; 3489 RE_SAL_DPRINT(("\n-------Error %d post2nfa\n\n", rv)); 3490 goto fail; 3491 } 3492 #if ENABLE_NFA_DUMP == 1 3493 RE_SAL_DPRINT(("\n-------NFA for %s\n\n", re[pattern])); 3494 dump_nfa(pnfa, sub_nfa[pattern]); 3495 #endif 3496 } 3497 3498 if (num_pattern == 1) { 3499 pnfa->root_state = sub_nfa[0]; 3500 } else { 3501 for (pattern = 0; pattern < num_pattern - 1; pattern++) { 3502 n1 = sub_nfa[pattern]; 3503 n2 = sub_nfa[pattern+1]; 3504 sub_nfa[pattern+1] = new_nfa_state(pnfa, Split, n1, n2); 3505 } 3506 pnfa->root_state = sub_nfa[pattern]; 3507 } 3508 3509 #if ENABLE_NFA_DUMP == 1 3510 RE_SAL_DPRINT(("--------\n\n\n--- Final NFA ---\n\n")); 3511 dump_nfa(pnfa, pnfa->root_state); 3512 #endif 3513 3514 /* 3515 * store the byte size required to represent all the states in NFA. 3516 * The reason to store it, the information is required in dfa 3517 * computation and required like millions of times, this just 3518 * optimizes computation a bit. 3519 */ 3520 pnfa->state_map_byte_size = ((pnfa->num_states + 31) / 32) * sizeof(unsigned int); 3521 state_map_byte_size = pnfa->state_map_byte_size; 3522 3523 /* 3524 * create a class map bitvector. This optimizes traversing the 3525 * NFA of specified transation. 3526 */ 3527 for (i = 0; i < num_classes; i++) { 3528 pnfa->class_map[i] = sal_alloc(NFA_SMAP_BYTE_SIZE(pnfa), "nfa_class_map"); 3529 if(!(pnfa->class_map[i])) { 3530 rv = REGEX_ERROR_NO_MEMORY; 3531 goto fail; 3532 } 3533 sal_memset(pnfa->class_map[i], 0, NFA_SMAP_BYTE_SIZE(pnfa)); 3534 } 3535 3536 for (i = 0; i < pnfa->num_states; i++) { 3537 s = pnfa->state_map[i]; 3538 if (s->class > 255) { 3539 continue; 3540 } 3541 if (s->class >= num_classes) { 3542 rv = REGEX_ERROR_EXPANSION_FAIL; 3543 RE_SAL_DPRINT(("\n-------Error %d too many classes\n\n", rv)); 3544 goto fail; 3545 } 3546 pnfa->class_map[s->class][s->id / 32] |= (1 << (s->id % 32)); 3547 } 3548 3549 fail: 3550 /* free sub NFA */ 3551 if (rv) { 3552 RE_SAL_DPRINT(("\n-------Error %d creating NFA\n\n", rv)); 3553 nfa_free(pnfa); 3554 pnfa = NULL; 3555 } 3556 if(sub_nfa) { 3557 sal_free(sub_nfa); 3558 } 3559 *ppnfa = pnfa; 3560 return rv; 3561 } 3562 3563 #if ENABLE_FINAL_DFA_DUMP == 1 3564 regex_cb_error_t 3565 bcm_regex_dfa_dump(unsigned int flags, int match_idx, int in_state, 3566 int from_c, int to_c, int to_state, 3567 int num_dfa_state, void *user_data) 3568 { 3569 static int last_state = -1; 3570 static int numFinal = 0; 3571 3572 if (flags & DFA_TRAVERSE_START) { 3573 last_state = -1; 3574 numFinal = 0; 3575 return REGEX_CB_OK; 3576 } 3577 3578 if (flags & DFA_TRAVERSE_END) { 3579 RE_SAL_DPRINT(("\nNum FINAL states %d\n", numFinal)); 3580 return REGEX_CB_OK; 3581 } 3582 3583 /* if last state is not same as this state, insert goto IDLE state */ 3584 if (last_state != in_state) { 3585 if (flags & DFA_STATE_FINAL) { 3586 numFinal++; 3587 RE_SAL_DPRINT(("\nState %d [FINAL]: Match ID %d\n", 3588 in_state, match_idx)); 3589 } else { 3590 RE_SAL_DPRINT(("\nState %d:\n", in_state)); 3591 } 3592 last_state = in_state; 3593 } 3594 3595 if ((from_c == -1) || (to_c == -1)) { 3596 return 0; 3597 } 3598 3599 RE_SAL_DPRINT((" %4d -> %4d ", in_state, to_state)); 3600 RE_SAL_DPRINT(("[")); 3601 RE_SAL_DPRINT(("\\%-3d", from_c)); 3602 RE_SAL_DPRINT(("-")); 3603 RE_SAL_DPRINT(("\\%-3d", to_c)); 3604 RE_SAL_DPRINT(("]")); 3605 if (printable(from_c) && printable(to_c)) { 3606 RE_SAL_DPRINT((" (%2c-%-2c)", from_c, to_c)); 3607 } else if (printable(from_c)) { 3608 RE_SAL_DPRINT((" (%2c-'')", from_c)); 3609 } else if (printable(to_c)) { 3610 RE_SAL_DPRINT((" (''-%-2c)", to_c)); 3611 } 3612 RE_SAL_DPRINT((";\n")); 3613 return REGEX_CB_OK; 3614 } 3615 #endif 3616 3617 static int dfa_free(re_dfa_t *l) 3618 { 3619 int i; 3620 3621 if (!l) { 3622 return 0; 3623 } 3624 3625 for (i = 0; i < l->num_states; i+= DFA_BLOCK_SIZE) { 3626 sal_free(l->states[i]->transition_list); 3627 sal_free(l->states[i]); 3628 } 3629 3630 sal_free(l->states); 3631 3632 if (l->class_array) { 3633 sal_free(l->class_array); 3634 } 3635 3636 _free_buf_blocks(l->nbuf); 3637 _free_buf_blocks(l->avbuf); 3638 3639 sal_free(l); 3640 return 0; 3641 } 3642 3643 static int 3644 make_dfa(int num_pattern, re_dfa_t **ppdfa, re_nfa_t **ppnfa, re_transition_class *class_array, 3645 int num_classes) 3646 { 3647 re_dfa_t *pdfa; 3648 re_nfa_t *pnfa = *ppnfa; 3649 int rv = 0; 3650 3651 pdfa = sal_alloc(sizeof(*pdfa), "DFA"); 3652 sal_memset(pdfa, 0, sizeof(*pdfa)); 3653 pdfa->size = 0; 3654 pdfa->states = NULL; 3655 pdfa->num_states = 0; 3656 pdfa->class_array = class_array; 3657 pdfa->num_classes = num_classes; 3658 3659 rv = nfa_to_dfa(pnfa, pdfa, num_classes); 3660 /* free up NFA, check rv after it */ 3661 nfa_free(pnfa); 3662 *ppnfa = NULL; 3663 3664 if (rv) { 3665 /* pdfa freed inside nfa_to_dfa */ 3666 rv = REGEX_ERROR_NO_DFA; 3667 goto fail; 3668 } 3669 3670 #if ENABLE_DFA_DUMP_BEFORE_MINIMIZATION == 1 3671 RE_SAL_DPRINT(("\nTotal of %d DFA states before minimization\n", pdfa->num_states)); 3672 RE_SAL_DPRINT(("\nTotal of %d char classes before minimization\n\n", pdfa->num_classes)); 3673 if (bcm_regex_dfa_traverse(pdfa, bcm_regex_dfa_dump, NULL)) { 3674 return -1; 3675 } 3676 RE_SAL_DPRINT(("-----------------------------------\n\n\n")); 3677 #endif 3678 3679 #if DFA_MINIMIZE == 1 3680 RE_SAL_DPRINT(("\nMinimizing %d DFA states\n", pdfa->num_states)); 3681 pdfa = dfa_minimize(pdfa); 3682 if (!pdfa) { 3683 rv = REGEX_ERROR_NO_DFA; 3684 goto fail; 3685 } 3686 RE_SAL_DPRINT(("-----------------------------------\n\n\n")); 3687 3688 #if ENABLE_FINAL_DFA_DUMP == 1 3689 RE_SAL_DPRINT(("\nTotal of %d DFA states after minimization\n", pdfa->num_states)); 3690 RE_SAL_DPRINT(("\nTotal of %d char classes after minimization\n\n", pdfa->num_classes)); 3691 RE_SAL_DPRINT(("Minimal DFA is\n")); 3692 if (bcm_regex_dfa_traverse(pdfa, bcm_regex_dfa_dump, NULL)) { 3693 return -1; 3694 } 3695 #endif 3696 #endif 3697 *ppdfa = pdfa; 3698 return rv; 3699 fail: 3700 *ppdfa = NULL; 3701 3702 return rv; 3703 } 3704 3705 static int nfa_free(re_nfa_t *nfa) 3706 { 3707 int i; 3708 3709 if (nfa == NULL) { 3710 return 0; 3711 } 3712 3713 for (i = 0; i < COUNTOF(nfa->class_map); i++) { 3714 if (nfa->class_map[i]) { 3715 sal_free(nfa->class_map[i]); 3716 nfa->class_map[i] = NULL; 3717 } 3718 } 3719 3720 if (nfa->state_map) { 3721 sal_free(nfa->state_map); 3722 nfa->state_map = NULL; 3723 } 3724 3725 _free_buf_blocks(nfa->nbuf); 3726 nfa->nbuf = NULL; 3727 sal_free(nfa); 3728 nfa = NULL; 3729 return 0; 3730 } 3731 3732 /* 3733 * Compiles the set of patterns into a single DFA. If the ppdfa is 3734 * not NULL, computed DFA is not freed and is preserved so that 3735 * user/application can inspect the DFA, ie for the API layer to 3736 * transform the DFA to device specific HW representation of the DFA. 3737 * 3738 * Note: This function is not reentrant. 3739 */ 3740 int 3741 bcm_regex_compile(char **re, unsigned int *res_flags, int num_pattern, 3742 unsigned int cflags, void** ppdfa) 3743 { 3744 int rv = REGEX_ERROR_NONE, num_classes = 0, p, ptlen; 3745 re_dfa_t *pdfa = NULL; 3746 re_transition_class *class_array = NULL; 3747 re_nfa_t *pnfa = NULL; 3748 char **nre; 3749 3750 *ppdfa = NULL; 3751 3752 listid = 0; 3753 state_id = 0; 3754 3755 if (num_pattern <= 0) { 3756 return 0; 3757 } 3758 3759 nre = sal_alloc(sizeof(char*)*num_pattern,"tmp_re"); 3760 if (nre == NULL) { 3761 return REGEX_ERROR_NO_MEMORY; 3762 } 3763 sal_memset(nre, 0, sizeof(char*)*num_pattern); 3764 3765 for(p=0; p<num_pattern; p++) { 3766 if (re[p] == NULL) { 3767 continue; 3768 } 3769 /* If the re begins with the start anchor metacharacter, ignore that character and 3770 * set the flag which indicates this regex is anchored at the start of the 3771 * packet. */ 3772 if (START_ANCHOR_CHAR == re[p][0]) { 3773 if (sal_strlen(re[p]) <= 1) { 3774 continue; 3775 } 3776 nre[p] = sal_strdup(&re[p][1]); 3777 res_flags[p] |= BCM_TR3_REGEX_CFLAG_ANCHORED; 3778 } else { 3779 nre[p] = sal_strdup(re[p]); 3780 } 3781 if (NULL == nre[p]) { 3782 rv = REGEX_ERROR_NO_MEMORY; 3783 goto fail; 3784 } 3785 ptlen = sal_strlen(nre[p]); 3786 if ((nre[p][ptlen - 1] == '$') && 3787 ((ptlen > 1) ? (nre[p][ptlen - 2] != '\\') : 1)) { 3788 nre[p][ptlen - 1] = '\0'; 3789 } 3790 } 3791 3792 #ifdef OPTIMIZE_PATTERN 3793 re_optimize_patterns(nre, num_pattern); 3794 #endif 3795 3796 rv = re_case_adjust(nre, num_pattern, res_flags); 3797 3798 /* 3799 * make the classes so that we can replace the tokens with the classes. 3800 * this reduces the number of transitions and arcs and hence 3801 * computational complexity. 3802 */ 3803 rv = re_make_symbol_classes_from_pattern(nre, num_pattern, 3804 res_flags, &class_array, &num_classes); 3805 if (rv) { 3806 rv = REGEX_ERROR_INVALID_CLASS; 3807 goto fail; 3808 } 3809 3810 rv = make_nfa(nre, res_flags, num_pattern, &pnfa, class_array, num_classes); 3811 if (rv) { 3812 sal_free(class_array); 3813 rv = REGEX_ERROR_NO_NFA; 3814 goto fail; 3815 } 3816 3817 if (make_dfa(num_pattern, &pdfa, &pnfa, class_array, num_classes) || !pdfa) { 3818 rv = REGEX_ERROR_NO_DFA; 3819 goto fail; 3820 } 3821 3822 /* return the number of DFA states */ 3823 rv = pdfa->num_states; 3824 3825 fail: 3826 for(p=0; p<num_pattern; p++) { 3827 if (nre[p]) { 3828 sal_free(nre[p]); 3829 } 3830 } 3831 sal_free(nre); 3832 if (pnfa) { 3833 nfa_free(pnfa); 3834 } 3835 if ((rv < 0) || (!ppdfa)) { 3836 if (pdfa) { 3837 dfa_free(pdfa); 3838 } 3839 return rv; 3840 } 3841 *ppdfa = (void*)pdfa; 3842 3843 RE_SAL_DPRINT(("\nCreated DFA with %d states\n", pdfa->num_states)); 3844 3845 return rv; 3846 } 3847 3848 typedef struct _re_state_compress_s { 3849 int state_id; 3850 unsigned int transition_map[8]; 3851 unsigned int num_ranges; 3852 struct _re_state_compress_s *next; 3853 } _re_state_compress; 3854 3855 static _re_state_compress* 3856 _re_find_compress_state(_re_state_compress **h, int state_id) 3857 { 3858 /* 3859 _re_state_compress *ps; 3860 */ 3861 3862 while (*h && ((*h)->state_id != state_id)) { 3863 h = &(*h)->next; 3864 } 3865 return *h; 3866 } 3867 3868 static int 3869 _re_add_tr_to_compress_state(_re_state_compress **h, 3870 int to_state_id, unsigned int *bitmap) 3871 { 3872 _re_state_compress *ps; 3873 int i; 3874 3875 ps = _re_find_compress_state(h, to_state_id); 3876 if (!ps) { 3877 ps = sal_alloc(sizeof(_re_state_compress),"zipst"); 3878 sal_memset(ps, 0, sizeof(_re_state_compress)); 3879 /* add to list */ 3880 ps->state_id = to_state_id; 3881 ps->next = *h; 3882 *h = ps; 3883 } 3884 3885 for (i = 0; i < 8; i++) { 3886 ps->transition_map[i] |= bitmap[i]; 3887 } 3888 return 0; 3889 } 3890 3891 int bcm_regex_dfa_traverse(void *dfa, regex_dfa_state_cb compile_dfa_cb, 3892 void *user_data) 3893 { 3894 re_dfa_state_t *state; 3895 re_dfa_t *dfa_list = (re_dfa_t *)dfa; 3896 unsigned flags = 0; 3897 int c, to_state, rv = REGEX_ERROR_NONE; 3898 int match_idx, i, j, k, lc, has_transition; 3899 re_transition_class *class; 3900 _re_state_compress *dlist[8], *pd, *else_jump_destination=NULL; 3901 int jump_count; 3902 int jump_to_all_classes; 3903 3904 3905 sal_memset(dlist, 0, sizeof(_re_state_compress*)*8); 3906 3907 /* 3908 * Dummy callback to indicate start of iteration. Application might do 3909 * something specific like init or something. 3910 */ 3911 if (compile_dfa_cb(DFA_TRAVERSE_START, -1, -1, -1, -1, -1, dfa_list->num_states, user_data)) { 3912 return REGEX_ERROR; 3913 } 3914 3915 /* 3916 Call user provided callback for each DFA state. compress the 3917 transitions so as to minimize the memory requirements. 3918 3919 Note that each state will originally have a transition for 3920 each character class. During compression, these transitions 3921 are folded together to make a smaller number of transitions 3922 that go to the same states. 3923 3924 The optimization below reduces the number of transitions 3925 even further. 3926 3927 Note: class->transition_map really represents a map of the 3928 different characters that are covered by the classes. 3929 3930 For the future, the transition compression should be 3931 changed to be done only once rather than for each 3932 traversal. 3933 */ 3934 for (i = 0; i < dfa_list->num_states; i++) { 3935 state = dfa_list->states[i]; 3936 flags = 0; 3937 match_idx = -1; 3938 has_transition = 0; 3939 jump_to_all_classes = 1; 3940 3941 for (j = 0; j < dfa_list->num_classes; j++) { 3942 if (state->transition_list[j] == -1) { 3943 jump_to_all_classes = 0; 3944 continue; 3945 } 3946 has_transition++; 3947 c = j; 3948 to_state = state->transition_list[j]; 3949 class = &dfa_list->class_array[c]; 3950 3951 _re_add_tr_to_compress_state(&dlist[to_state % COUNTOF(dlist)], 3952 to_state, class->transition_map); 3953 } 3954 3955 /* 3956 * dlist now contains one entry for each jump destination. If there are jumps to 3957 * every character class, then find the destination with the largest number of 3958 * ranges (i.e., will have the most number of jump instructions) and replace it 3959 * with a single jump instruction for all characters (i.e., an else clause). 3960 */ 3961 3962 else_jump_destination = NULL; 3963 if (0 != jump_to_all_classes) { 3964 jump_count = 0; 3965 for (j = 0; j < COUNTOF(dlist); j++) { 3966 pd = dlist[j]; 3967 while (pd) { 3968 lc = -1; 3969 for (k = 0; k < REGEX_MAX_CHARACTER_CLASSES; k++) { 3970 if (pd->transition_map[k / WORDS2BITS(1)] & (1 << (k % WORDS2BITS(1)))) { 3971 if (lc == -1) { 3972 pd->num_ranges++; 3973 lc = k; 3974 } 3975 } else { 3976 lc = -1; 3977 } 3978 } 3979 if (pd->num_ranges > jump_count) { 3980 jump_count = pd->num_ranges; 3981 else_jump_destination = pd; 3982 } 3983 pd = pd->next; 3984 } 3985 } 3986 3987 /* 3988 * A destination is found which can save at least one jump, remove it from 3989 * the list of destinations. 3990 */ 3991 if (jump_count > 1) { 3992 for (j = 0; j < COUNTOF(dlist); j++) { 3993 if (dlist[j] == else_jump_destination) { 3994 dlist[j] = else_jump_destination->next; 3995 } else { 3996 pd = dlist[j]; 3997 while (pd) { 3998 if (pd->next == else_jump_destination) { 3999 pd->next = else_jump_destination->next; 4000 break; 4001 } 4002 pd = pd->next; 4003 } 4004 } 4005 } 4006 } else { 4007 else_jump_destination = NULL; 4008 } 4009 } 4010 4011 if (RE_DFA_IS_FINAL(state)) { 4012 match_idx = RE_DFA_FINAL(state) - 1; 4013 flags = DFA_STATE_FINAL; 4014 if (!has_transition) { 4015 if (compile_dfa_cb(DFA_STATE_FINAL, 4016 match_idx, RE_DFA_STATEID(state), 4017 -1, -1, -1, dfa_list->num_states, user_data)) { 4018 rv = REGEX_ERROR; 4019 goto done; 4020 } 4021 } 4022 } 4023 4024 for (j = 0; j < COUNTOF(dlist); j++) { 4025 while (dlist[j]) { 4026 pd = dlist[j]; 4027 to_state = pd->state_id; 4028 lc = -1; 4029 for (k = 0; k < REGEX_MAX_CHARACTER_CLASSES; k++) { 4030 if (pd->transition_map[k / WORDS2BITS(1)] & (1 << (k % WORDS2BITS(1)))) { 4031 if (lc == -1) { 4032 lc = k; 4033 } 4034 } else if (lc >= 0) { 4035 if (compile_dfa_cb(flags, match_idx, 4036 RE_DFA_STATEID(state), lc, k-1, 4037 pd->state_id, dfa_list->num_states, 4038 user_data)) { 4039 rv = REGEX_ERROR; 4040 goto done; 4041 } 4042 lc = -1; 4043 } 4044 } 4045 if (lc >= 0) { 4046 if (compile_dfa_cb(flags, match_idx, RE_DFA_STATEID(state), 4047 lc, REGEX_MAX_CHARACTER_CLASSES-1, pd->state_id, dfa_list->num_states, user_data)) { 4048 rv = REGEX_ERROR; 4049 goto done; 4050 } 4051 } 4052 dlist[j] = pd->next; 4053 sal_free(pd); 4054 } 4055 dlist[j] = NULL; 4056 } 4057 4058 /* 4059 If an "else" jump destination has been found, process it here. 4060 */ 4061 4062 if (NULL != else_jump_destination) { 4063 if (compile_dfa_cb(flags, match_idx, RE_DFA_STATEID(state), 4064 0, REGEX_MAX_CHARACTER_CLASSES - 1, 4065 else_jump_destination->state_id, dfa_list->num_states, user_data)) { 4066 rv = REGEX_ERROR; 4067 goto done; 4068 } 4069 sal_free(else_jump_destination); 4070 else_jump_destination = NULL; 4071 } 4072 } 4073 4074 /* indicate end of traverse, so that any house keeping can be done 4075 * now */ 4076 compile_dfa_cb(DFA_TRAVERSE_END, -1, -1, -1, -1, -1, dfa_list->num_states, user_data); 4077 4078 done: 4079 if (NULL != else_jump_destination) { 4080 sal_free(else_jump_destination); 4081 } 4082 for (i = 0; i < COUNTOF(dlist); i++) { 4083 while(dlist[i]) { 4084 pd = dlist[i]->next; 4085 sal_free(dlist[i]); 4086 dlist[i] = pd; 4087 } 4088 } 4089 return rv; 4090 } 4091 4092 int bcm_regex_dfa_free(void *dfa) 4093 { 4094 dfa_free((re_dfa_t*)dfa); 4095 return 0; 4096 } 4097 4098 #ifndef BROADCOM_SDK 4099 4100 int 4101 main(int argc, char **argv) 4102 { 4103 int rv, num_pat = 0, i, valid, bi; 4104 char *pc[64], tmp_re[512], c; 4105 unsigned int re_flags[512]; 4106 unsigned int def_flags = 0 /* BCM_TR3_REGEX_CFLAG_EXPAND_LCUC */; 4107 void *dfa; 4108 FILE *fp; 4109 4110 fp = fopen("patterns.txt", "r"); 4111 4112 bi = 0; 4113 while((c = getc(fp)) != EOF) { 4114 if ((c == '\n') || (c == '\r')) { 4115 valid = 0; 4116 i = 0; 4117 while (i < bi) { 4118 if ((tmp_re[i] != ' ') && (tmp_re[i] != '\t')) { 4119 valid = 1; 4120 break; 4121 } 4122 } 4123 4124 if (valid) { 4125 tmp_re[bi] = '\0'; 4126 pc[num_pat] = sal_alloc(512,"main"); 4127 strcpy(pc[num_pat], tmp_re); 4128 re_flags[num_pat] = def_flags; 4129 num_pat++; 4130 } 4131 bi = 0; 4132 continue; 4133 } 4134 tmp_re[bi++] = c; 4135 } 4136 4137 rv = bcm_regex_compile(pc, re_flags, num_pat, 0, &dfa); 4138 if (rv <= 0) { 4139 RE_SAL_DPRINT(("\n FAILED error=%d, re=%s\n", rv, argv[1])); 4140 } 4141 4142 dfa_free(dfa); 4143 4144 for (i=0; i<num_pat; i++) { 4145 sal_free(pc[i]); 4146 } 4147 4148 #if MEM_PROFILE == 1 4149 re_dump_mem_leak(); 4150 #endif 4151 4152 return 0; 4153 } 4154 #endif 4155 4156 4157 #else 4158 int regex_supported = 0; 4159 #endif