3 * Author: Tatu Ylonen <ylo@ngs.fi>
5 * Copyright (c) 1991 Tatu Ylonen, Espoo, Finland
7 * Permission to use, copy, modify, distribute, and sell this software
8 * and its documentation for any purpose is hereby granted without
9 * fee, provided that the above copyright notice appear in all copies.
10 * This software is provided "as is" without express or implied
13 * Created: Thu Sep 26 17:14:05 1991 ylo
14 * Last modified: Mon Nov 4 17:06:48 1991 ylo
15 * Ported to Think C: 19 Jan 1992 guido@cwi.nl
17 * This code draws many ideas from the regular expression packages by
18 * Henry Spencer of the University of Toronto and Richard Stallman of
19 * the Free Software Foundation.
21 * Bugs fixed and lots of reorganization by Jeffrey C. Ollie, April
22 * 1997 Thanks for bug reports and ideas from Andrew Kuchling, Tim
23 * Peters, Guido van Rossum, Ka-Ping Yee, Sjoerd Mullender, and
24 * probably one or two others that I'm forgetting.
29 The SILC Regex API and modifications by Pekka Riikonen, under the same
30 license as the original code. We've added the following features:
32 - RE_SYNTAX_POSIX POSIX extended regular expression syntax
33 - RE_REPEAT bounded repeat a{n,m} (RE_SYNTAX_POSIX)
34 - RE_NOTBOL bol fails to match (conforming POSIX regex API)
35 - RE_NOTEOL eol fails to match (conforming POSIX regex API)
36 - SilcStack support compile/match without real memory allocations
41 #define RE_NREGS 128 /* number of registers available */
43 /* bit definitions for syntax */
44 #define RE_NO_BK_PARENS 1 /* no quoting for parentheses */
45 #define RE_NO_BK_VBAR 2 /* no quoting for vertical bar */
46 #define RE_BK_PLUS_QM 4 /* quoting needed for + and ? */
47 #define RE_TIGHT_VBAR 8 /* | binds tighter than ^ and $ */
48 #define RE_NEWLINE_OR 16 /* treat newline as or */
49 #define RE_CONTEXT_INDEP_OPS 32 /* ^$?*+ are special in all contexts */
50 #define RE_ANSI_HEX 64 /* ansi sequences (\n etc) and \xhh */
51 #define RE_NO_GNU_EXTENSIONS 128 /* no gnu extensions */
52 #define RE_NOTBOL 256 /* bol fails to match */
53 #define RE_NOTEOL 512 /* eol fails to match */
54 #define RE_REPEAT 1024 /* bounded repeat expression */
56 /* definitions for some common regexp styles */
57 #define RE_SYNTAX_AWK (RE_NO_BK_PARENS|RE_NO_BK_VBAR|RE_CONTEXT_INDEP_OPS)
58 #define RE_SYNTAX_EGREP (RE_SYNTAX_AWK|RE_NEWLINE_OR)
59 #define RE_SYNTAX_GREP (RE_BK_PLUS_QM|RE_NEWLINE_OR)
60 #define RE_SYNTAX_POSIX (RE_SYNTAX_AWK|RE_REPEAT)
61 #define RE_SYNTAX_EMACS 0
64 typedef struct re_registers {
65 int start[RE_NREGS]; /* start offset of region */
66 int end[RE_NREGS]; /* end offset of region */
67 } *regexp_registers_t;
69 /* The original code blithely assumed that sizeof(short) == 2. Not
70 * always true. Original instances of "(short)x" were replaced by
71 * SHORT(x), where SHORT is #defined below. */
73 #define SHORT(x) ((x) & 0x8000 ? (x) - 0x10000 : (x))
75 /* The stack implementation is taken from an idea by Andrew Kuchling.
76 * It's a doubly linked list of arrays. The advantages of this over a
77 * simple linked list are that the number of mallocs required are
78 * reduced. It also makes it possible to statically allocate enough
79 * space so that small patterns don't ever need to call malloc.
81 * The advantages over a single array is that is periodically
82 * realloced when more space is needed is that we avoid ever copying
85 /* item_t is the basic stack element. Defined as a union of
86 * structures so that both registers, failure points, and counters can
87 * be pushed/popped from the stack. There's nothing built into the
88 * item to keep track of whether a certain stack item is a register, a
89 * failure point, or a counter. */
116 #define STACK_PAGE_SIZE 256
117 #define NUM_REGISTERS 256
119 /* A 'page' of stack items. */
121 typedef struct item_page_t
123 item_t items[STACK_PAGE_SIZE];
124 struct item_page_t *prev;
125 struct item_page_t *next;
128 typedef struct match_state
130 /* The number of registers that have been pushed onto the stack
131 * since the last failure point. */
135 /* Used to control when registers need to be pushed onto the
140 /* The number of failure points on the stack. */
144 /* Storage for the registers. Each register consists of two
145 * pointers to characters. So register N is represented as
146 * start[N] and end[N]. The pointers must be converted to
147 * offsets from the beginning of the string before returning the
148 * registers to the calling program. */
150 unsigned char *start[NUM_REGISTERS];
151 unsigned char *end[NUM_REGISTERS];
153 /* Keeps track of whether a register has changed recently. */
155 int changed[NUM_REGISTERS];
157 /* Structure to encapsulate the stack. */
160 /* index into the current page. If index == 0 and you need
161 * to pop an item, move to the previous page and set index
162 * = STACK_PAGE_SIZE - 1. Otherwise decrement index to
163 * push a page. If index == STACK_PAGE_SIZE and you need
164 * to push a page move to the next page and set index =
165 * 0. If there is no new next page, allocate a new page
166 * and link it in. Otherwise, increment index to push a
170 item_page_t *current; /* Pointer to the current page. */
171 item_page_t first; /* First page is statically allocated. */
175 /* Initialize a state object */
177 /* #define NEW_STATE(state) \ */
178 /* memset(&state, 0, (void *)(&state.stack) - (void *)(&state)); \ */
179 /* state.stack.current = &state.stack.first; \ */
180 /* state.stack.first.prev = NULL; \ */
181 /* state.stack.first.next = NULL; \ */
182 /* state.stack.index = 0; \ */
183 /* state.level = 1 */
185 #define NEW_STATE(state, nregs) \
188 for (i = 0; i < nregs; i++) \
190 state.start[i] = NULL; \
191 state.end[i] = NULL; \
192 state.changed[i] = 0; \
194 state.stack.current = &state.stack.first; \
195 state.stack.first.prev = NULL; \
196 state.stack.first.next = NULL; \
197 state.stack.index = 0; \
204 /* Free any memory that might have been malloc'd */
206 #define FREE_STATE(state) \
207 while(state.stack.first.next != NULL) \
209 state.stack.current = state.stack.first.next; \
210 state.stack.first.next = state.stack.current->next; \
211 silc_sfree(bufp->rstack, state.stack.current); \
214 /* Discard the top 'count' stack items. */
216 #define STACK_DISCARD(stack, count, on_error) \
217 stack.index -= count; \
218 while (stack.index < 0) \
220 if (stack.current->prev == NULL) \
222 stack.current = stack.current->prev; \
223 stack.index += STACK_PAGE_SIZE; \
226 /* Store a pointer to the previous item on the stack. Used to pop an
227 * item off of the stack. */
229 #define STACK_PREV(stack, top, on_error) \
230 if (stack.index == 0) \
232 if (stack.current->prev == NULL) \
234 stack.current = stack.current->prev; \
235 stack.index = STACK_PAGE_SIZE - 1; \
241 top = &(stack.current->items[stack.index])
243 /* Store a pointer to the next item on the stack. Used to push an item
244 * on to the stack. */
246 #define STACK_NEXT(stack, top, on_error) \
247 if (stack.index == STACK_PAGE_SIZE) \
249 if (stack.current->next == NULL) \
251 stack.current->next = \
252 (item_page_t *)silc_smalloc(bufp->rstack, sizeof(item_page_t)); \
253 if (stack.current->next == NULL) \
255 stack.current->next->prev = stack.current; \
256 stack.current->next->next = NULL; \
258 stack.current = stack.current->next; \
261 top = &(stack.current->items[stack.index++])
263 /* Store a pointer to the item that is 'count' items back in the
264 * stack. STACK_BACK(stack, top, 1, on_error) is equivalent to
265 * STACK_TOP(stack, top, on_error). */
267 #define STACK_BACK(stack, top, count, on_error) \
270 item_page_t *current; \
271 current = stack.current; \
272 index = stack.index - (count); \
275 if (current->prev == NULL) \
277 current = current->prev; \
278 index += STACK_PAGE_SIZE; \
280 top = &(current->items[index]); \
283 /* Store a pointer to the top item on the stack. Execute the
284 * 'on_error' code if there are no items on the stack. */
286 #define STACK_TOP(stack, top, on_error) \
287 if (stack.index == 0) \
289 if (stack.current->prev == NULL) \
291 top = &(stack.current->prev->items[STACK_PAGE_SIZE - 1]); \
295 top = &(stack.current->items[stack.index - 1]); \
298 /* Test to see if the stack is empty */
300 #define STACK_EMPTY(stack) ((stack.index == 0) && \
301 (stack.current->prev == NULL))
303 /* Return the start of register 'reg' */
305 #define GET_REG_START(state, reg) (state.start[reg])
307 /* Return the end of register 'reg' */
309 #define GET_REG_END(state, reg) (state.end[reg])
311 /* Set the start of register 'reg'. If the state of the register needs
312 * saving, push it on the stack. */
314 #define SET_REG_START(state, reg, text, on_error) \
315 if(state.changed[reg] < state.level) \
318 STACK_NEXT(state.stack, item, on_error); \
319 item->reg.num = reg; \
320 item->reg.start = state.start[reg]; \
321 item->reg.end = state.end[reg]; \
322 item->reg.level = state.changed[reg]; \
323 state.changed[reg] = state.level; \
326 state.start[reg] = text
328 /* Set the end of register 'reg'. If the state of the register needs
329 * saving, push it on the stack. */
331 #define SET_REG_END(state, reg, text, on_error) \
332 if(state.changed[reg] < state.level) \
335 STACK_NEXT(state.stack, item, on_error); \
336 item->reg.num = reg; \
337 item->reg.start = state.start[reg]; \
338 item->reg.end = state.end[reg]; \
339 item->reg.level = state.changed[reg]; \
340 state.changed[reg] = state.level; \
343 state.end[reg] = text
345 #define PUSH_FAILURE(state, xcode, xtext, on_error) \
348 STACK_NEXT(state.stack, item, on_error); \
349 item->fail.code = xcode; \
350 item->fail.text = xtext; \
351 item->fail.count = state.count; \
352 item->fail.level = state.level; \
353 item->fail.phantom = 0; \
359 /* Update the last failure point with a new position in the text. */
361 #define UPDATE_FAILURE(state, xtext, on_error) \
364 STACK_BACK(state.stack, item, state.count + 1, on_error); \
365 if (!item->fail.phantom) \
368 STACK_NEXT(state.stack, item2, on_error); \
369 item2->fail.code = item->fail.code; \
370 item2->fail.text = xtext; \
371 item2->fail.count = state.count; \
372 item2->fail.level = state.level; \
373 item2->fail.phantom = 1; \
380 STACK_DISCARD(state.stack, state.count, on_error); \
381 STACK_TOP(state.stack, item, on_error); \
382 item->fail.text = xtext; \
388 #define POP_FAILURE(state, xcode, xtext, on_empty, on_error) \
393 while(state.count > 0) \
395 STACK_PREV(state.stack, item, on_error); \
396 state.start[item->reg.num] = item->reg.start; \
397 state.end[item->reg.num] = item->reg.end; \
398 state.changed[item->reg.num] = item->reg.level; \
401 STACK_PREV(state.stack, item, on_empty); \
402 xcode = item->fail.code; \
403 xtext = item->fail.text; \
404 state.count = item->fail.count; \
405 state.level = item->fail.level; \
408 while (item->fail.text == NULL); \
411 enum regexp_compiled_ops /* opcodes for compiled regexp */
413 Cend, /* end of pattern reached */
414 Cbol, /* beginning of line */
415 Ceol, /* end of line */
416 Cset, /* character set. Followed by 32 bytes of set. */
417 Cexact, /* followed by a byte to match */
418 Canychar, /* matches any character except newline */
419 Cstart_memory, /* set register start addr (followed by reg number) */
420 Cend_memory, /* set register end addr (followed by reg number) */
421 Cmatch_memory, /* match a duplicate of reg contents (regnum follows)*/
422 Cjump, /* followed by two bytes (lsb,msb) of displacement. */
423 Cstar_jump, /* will change to jump/update_failure_jump at runtime */
424 Cfailure_jump, /* jump to addr on failure */
425 Cupdate_failure_jump, /* update topmost failure point and jump */
426 Cdummy_failure_jump, /* push a dummy failure point and jump */
427 Cbegbuf, /* match at beginning of buffer */
428 Cendbuf, /* match at end of buffer */
429 Cwordbeg, /* match at beginning of word */
430 Cwordend, /* match at end of word */
431 Cwordbound, /* match if at word boundary */
432 Cnotwordbound, /* match if not at word boundary */
433 Csyntaxspec, /* matches syntax code (1 byte follows) */
434 Cnotsyntaxspec, /* matches if syntax code does not match (1 byte foll)*/
438 enum regexp_syntax_op /* syntax codes for plain and quoted characters */
440 Rend, /* special code for end of regexp */
441 Rnormal, /* normal character */
442 Ranychar, /* any character except newline */
443 Rquote, /* the quote character */
444 Rbol, /* match beginning of line */
445 Reol, /* match end of line */
446 Roptional, /* match preceding expression optionally */
447 Rstar, /* match preceding expr zero or more times */
448 Rplus, /* match preceding expr one or more times */
449 Ror, /* match either of alternatives */
450 Ropenpar, /* opening parenthesis */
451 Rclosepar, /* closing parenthesis */
452 Rmemory, /* match memory register */
453 Rextended_memory, /* \vnn to match registers 10-99 */
454 Ropenset, /* open set. Internal syntax hard-coded below. */
455 /* the following are gnu extensions to "normal" regexp syntax */
456 Rbegbuf, /* beginning of buffer */
457 Rendbuf, /* end of buffer */
458 Rwordchar, /* word character */
459 Rnotwordchar, /* not word character */
460 Rwordbeg, /* beginning of word */
461 Rwordend, /* end of word */
462 Rwordbound, /* word bound */
463 Rnotwordbound, /* not word bound */
465 Ropenrep, /* opening bounded repeat */
469 #define Swhitespace 2
471 #define Soctaldigit 8
474 #define NUM_LEVELS 5 /* number of precedence levels in use */
475 #define MAX_NESTING 100 /* max nesting level of operators */
476 #define SYNTAX(ch) silc_re_syntax_table[(unsigned char)(ch)]
478 static int silc_regexp_syntax = RE_SYNTAX_POSIX;
479 static int silc_regexp_context_indep_ops;
480 static int silc_regexp_ansi_sequences;
481 static int silc_re_compile_initialized = 0;
482 static unsigned char silc_re_syntax_table[256];
483 static unsigned char silc_regexp_plain_ops[256];
484 static unsigned char silc_regexp_quoted_ops[256];
485 static unsigned char silc_regexp_precedencess[Rnum_ops];
487 void silc_re_compile_initialize(void)
491 static int syntax_table_inited = 0;
493 if (!syntax_table_inited)
495 syntax_table_inited = 1;
496 memset(silc_re_syntax_table, 0, 256);
497 for (a = 'a'; a <= 'z'; a++)
498 silc_re_syntax_table[a] = Sword;
499 for (a = 'A'; a <= 'Z'; a++)
500 silc_re_syntax_table[a] = Sword;
501 for (a = '0'; a <= '9'; a++)
502 silc_re_syntax_table[a] = Sword | Sdigit | Shexdigit;
503 for (a = '0'; a <= '7'; a++)
504 silc_re_syntax_table[a] |= Soctaldigit;
505 for (a = 'A'; a <= 'F'; a++)
506 silc_re_syntax_table[a] |= Shexdigit;
507 for (a = 'a'; a <= 'f'; a++)
508 silc_re_syntax_table[a] |= Shexdigit;
509 silc_re_syntax_table['_'] = Sword;
510 for (a = 9; a <= 13; a++)
511 silc_re_syntax_table[a] = Swhitespace;
512 silc_re_syntax_table[' '] = Swhitespace;
514 silc_re_compile_initialized = 1;
515 for (a = 0; a < 256; a++)
517 silc_regexp_plain_ops[a] = Rnormal;
518 silc_regexp_quoted_ops[a] = Rnormal;
520 for (a = '0'; a <= '9'; a++)
521 silc_regexp_quoted_ops[a] = Rmemory;
522 silc_regexp_plain_ops['\134'] = Rquote;
523 if (silc_regexp_syntax & RE_NO_BK_PARENS)
525 silc_regexp_plain_ops['('] = Ropenpar;
526 silc_regexp_plain_ops[')'] = Rclosepar;
530 silc_regexp_quoted_ops['('] = Ropenpar;
531 silc_regexp_quoted_ops[')'] = Rclosepar;
533 if (silc_regexp_syntax & RE_NO_BK_VBAR)
534 silc_regexp_plain_ops['\174'] = Ror;
536 silc_regexp_quoted_ops['\174'] = Ror;
537 silc_regexp_plain_ops['*'] = Rstar;
538 if (silc_regexp_syntax & RE_BK_PLUS_QM)
540 silc_regexp_quoted_ops['+'] = Rplus;
541 silc_regexp_quoted_ops['?'] = Roptional;
545 silc_regexp_plain_ops['+'] = Rplus;
546 silc_regexp_plain_ops['?'] = Roptional;
548 if (silc_regexp_syntax & RE_NEWLINE_OR)
549 silc_regexp_plain_ops['\n'] = Ror;
550 silc_regexp_plain_ops['\133'] = Ropenset;
551 silc_regexp_plain_ops['\136'] = Rbol;
552 silc_regexp_plain_ops['$'] = Reol;
553 silc_regexp_plain_ops['.'] = Ranychar;
554 if (!(silc_regexp_syntax & RE_NO_GNU_EXTENSIONS))
556 silc_regexp_quoted_ops['w'] = Rwordchar;
557 silc_regexp_quoted_ops['W'] = Rnotwordchar;
558 silc_regexp_quoted_ops['<'] = Rwordbeg;
559 silc_regexp_quoted_ops['>'] = Rwordend;
560 silc_regexp_quoted_ops['b'] = Rwordbound;
561 silc_regexp_quoted_ops['B'] = Rnotwordbound;
562 silc_regexp_quoted_ops['`'] = Rbegbuf;
563 silc_regexp_quoted_ops['\''] = Rendbuf;
565 if (silc_regexp_syntax & RE_ANSI_HEX)
566 silc_regexp_quoted_ops['v'] = Rextended_memory;
567 for (a = 0; a < Rnum_ops; a++)
568 silc_regexp_precedencess[a] = 4;
569 if (silc_regexp_syntax & RE_TIGHT_VBAR)
571 silc_regexp_precedencess[Ror] = 3;
572 silc_regexp_precedencess[Rbol] = 2;
573 silc_regexp_precedencess[Reol] = 2;
577 silc_regexp_precedencess[Ror] = 2;
578 silc_regexp_precedencess[Rbol] = 3;
579 silc_regexp_precedencess[Reol] = 3;
581 if (silc_regexp_syntax & RE_REPEAT)
583 if (silc_regexp_syntax & RE_NO_BK_PARENS)
585 silc_regexp_plain_ops['{'] = Ropenrep;
589 silc_regexp_quoted_ops['{'] = Ropenrep;
592 silc_regexp_precedencess[Rclosepar] = 1;
593 silc_regexp_precedencess[Rend] = 0;
594 silc_regexp_context_indep_ops = (silc_regexp_syntax & RE_CONTEXT_INDEP_OPS) != 0;
595 silc_regexp_ansi_sequences = (silc_regexp_syntax & RE_ANSI_HEX) != 0;
598 int silc_re_set_syntax(int syntax)
602 ret = silc_regexp_syntax;
603 silc_regexp_syntax = syntax;
604 silc_re_compile_initialize();
608 static int silc_hex_char_to_decimal(int ch)
610 if (ch >= '0' && ch <= '9')
612 if (ch >= 'a' && ch <= 'f')
613 return ch - 'a' + 10;
614 if (ch >= 'A' && ch <= 'F')
615 return ch - 'A' + 10;
619 static int silc_re_compile_fastmap_aux(unsigned char *code, int pos,
620 unsigned char *visited,
621 unsigned char *can_be_null,
622 unsigned char *fastmap)
629 return 0; /* we have already been here */
632 switch (code[pos++]) {
646 for (a = 0; a < 256; a++)
652 syntaxcode = code[pos++];
653 for (a = 0; a < 256; a++)
654 if (SYNTAX(a) & syntaxcode)
660 syntaxcode = code[pos++];
661 for (a = 0; a < 256; a++)
662 if (!(SYNTAX(a) & syntaxcode) )
669 if (*can_be_null == 0)
670 *can_be_null = 2; /* can match null, but only at end of buffer*/
675 for (a = 0; a < 256/8; a++)
676 if (code[pos + a] != 0)
677 for (b = 0; b < 8; b++)
678 if (code[pos + a] & (1 << b))
679 fastmap[(a << 3) + b] = 1;
685 fastmap[(unsigned char)code[pos]] = 1;
690 for (a = 0; a < 256; a++)
703 for (a = 0; a < 256; a++)
709 case Cdummy_failure_jump:
710 case Cupdate_failure_jump:
713 a = (unsigned char)code[pos++];
714 a |= (unsigned char)code[pos++] << 8;
715 pos += (int)SHORT(a);
718 /* argh... the regexp contains empty loops. This is not
719 good, as this may cause a failure stack overflow when
720 matching. Oh well. */
721 /* this path leads nowhere; pursue other paths. */
729 a = (unsigned char)code[pos++];
730 a |= (unsigned char)code[pos++] << 8;
731 a = pos + (int)SHORT(a);
732 return silc_re_compile_fastmap_aux(code, a, visited,
733 can_be_null, fastmap);
742 silc_set_errno(SILC_ERR_REGEX_OPCODE);
749 static int silc_re_do_compile_fastmap(unsigned char *buffer, int used, int pos,
750 unsigned char *can_be_null,
751 unsigned char *fastmap, SilcRegex bufp)
753 unsigned char small_visited[512], *visited;
756 if (used <= sizeof(small_visited))
757 visited = small_visited;
760 silc_stack_push(bufp->rstack, NULL);
761 visited = silc_smalloc(bufp->rstack, used);
763 silc_stack_pop(bufp->rstack);
768 memset(fastmap, 0, 256);
769 memset(visited, 0, used);
770 ret = silc_re_compile_fastmap_aux(buffer, pos, visited,
771 can_be_null, fastmap);
772 if (visited != small_visited) {
773 silc_sfree(bufp->rstack, visited);
774 silc_stack_pop(bufp->rstack);
779 int silc_re_compile_fastmap(SilcRegex bufp)
781 if (!bufp->fastmap || bufp->fastmap_accurate)
783 SILC_ASSERT(bufp->used > 0);
784 if (!silc_re_do_compile_fastmap(bufp->buffer,
788 bufp->fastmap, bufp))
790 if (bufp->buffer[0] == Cbol)
791 bufp->anchor = 1; /* begline */
793 if (bufp->buffer[0] == Cbegbuf)
794 bufp->anchor = 2; /* begbuf */
796 bufp->anchor = 0; /* none */
798 bufp->fastmap_accurate = 1;
805 * ... code for operand of star
807 * 2: ... code after star
809 * We change the star_jump to update_failure_jump if we can determine
810 * that it is safe to do so; otherwise we change it to an ordinary
817 * 2: ... code for operand of plus
819 * 3: ... code after plus
821 * For star_jump considerations this is processed identically to star.
825 static int silc_re_optimize_star_jump(SilcRegex bufp, unsigned char *code)
827 unsigned char map[256];
828 unsigned char can_be_null;
834 int num_instructions = 0;
836 a = (unsigned char)*code++;
837 a |= (unsigned char)*code++ << 8;
840 p1 = code + a + 3; /* skip the failure_jump */
841 /* Check that the jump is within the pattern */
842 if (p1<bufp->buffer || bufp->buffer+bufp->used<p1)
844 silc_set_errno(SILC_ERR_OVERFLOW);
848 SILC_ASSERT(p1[-3] == Cfailure_jump);
850 /* p1 points inside loop, p2 points to after loop */
851 if (!silc_re_do_compile_fastmap(bufp->buffer, bufp->used,
852 (int)(p2 - bufp->buffer),
853 &can_be_null, map, bufp))
854 goto make_normal_jump;
856 /* If we might introduce a new update point inside the
857 * loop, we can't optimize because then update_jump would
858 * update a wrong failure point. Thus we have to be
859 * quite careful here.
862 /* loop until we find something that consumes a character */
886 ch = (unsigned char)*p1++;
888 goto make_normal_jump;
893 for (b = 0; b < 256; b++)
894 if (b != '\n' && map[b])
895 goto make_normal_jump;
900 for (b = 0; b < 256; b++)
901 if ((p1[b >> 3] & (1 << (b & 7))) && map[b])
902 goto make_normal_jump;
908 goto make_normal_jump;
911 /* now we know that we can't backtrack. */
951 case Cupdate_failure_jump:
952 case Cdummy_failure_jump:
954 goto make_normal_jump;
963 /* make_update_jump: */
965 a += 3; /* jump to after the Cfailure_jump */
966 code[0] = Cupdate_failure_jump;
969 if (num_instructions > 1)
971 SILC_ASSERT(num_instructions == 1);
972 /* if the only instruction matches a single character, we can do
974 p1 = code + 3 + a; /* start of sole instruction */
975 if (*p1 == Cset || *p1 == Cexact || *p1 == Canychar ||
976 *p1 == Csyntaxspec || *p1 == Cnotsyntaxspec)
986 static int silc_re_optimize(SilcRegex bufp)
1022 case Cnotsyntaxspec:
1029 if (!silc_re_optimize_star_jump(bufp, code))
1035 case Cupdate_failure_jump:
1037 case Cdummy_failure_jump:
1052 #define NEXTCHAR(var) \
1055 goto ends_prematurely; \
1056 (var) = regex[pos]; \
1060 #define ALLOC(amount) \
1062 if (pattern_offset+(amount) > alloc) \
1064 pattern = silc_srealloc(bufp->rstack, alloc, pattern, \
1065 alloc + 256 + (amount)); \
1066 alloc += 256 + (amount); \
1068 goto out_of_memory; \
1072 #define STORE(ch) pattern[pattern_offset++] = (ch)
1074 #define CURRENT_LEVEL_START (starts[starts_base + current_level])
1076 #define SET_LEVEL_START starts[starts_base + current_level] = pattern_offset
1078 #define PUSH_LEVEL_STARTS \
1079 if (starts_base < (MAX_NESTING-1)*NUM_LEVELS) \
1080 starts_base += NUM_LEVELS; \
1084 #define POP_LEVEL_STARTS starts_base -= NUM_LEVELS
1086 #define PUT_ADDR(offset,addr) \
1088 int disp = (addr) - (offset) - 2; \
1089 pattern[(offset)] = disp & 0xff; \
1090 pattern[(offset)+1] = (disp>>8) & 0xff; \
1093 #define INSERT_JUMP(pos,type,addr) \
1095 int a, p = (pos), t = (type), ad = (addr); \
1096 for (a = pattern_offset - 1; a >= p; a--) \
1097 pattern[a + 3] = pattern[a]; \
1100 pattern_offset += 3; \
1103 #define SETBIT(buf,offset,bit) (buf)[(offset)+(bit)/8] |= (1<<((bit) & 7))
1105 #define SET_FIELDS \
1107 bufp->allocated = alloc; \
1108 bufp->buffer = pattern; \
1109 bufp->used = pattern_offset; \
1112 #define GETHEX(var) \
1114 unsigned char gethex_ch, gethex_value; \
1115 NEXTCHAR(gethex_ch); \
1116 gethex_value = silc_hex_char_to_decimal(gethex_ch); \
1117 if (gethex_value == 16) \
1119 NEXTCHAR(gethex_ch); \
1120 gethex_ch = silc_hex_char_to_decimal(gethex_ch); \
1121 if (gethex_ch == 16) \
1123 (var) = gethex_value * 16 + gethex_ch; \
1126 #define ANSI_TRANSLATE(ch) \
1133 ch = 7; /* audible bell */ \
1139 ch = 8; /* backspace */ \
1145 ch = 12; /* form feed */ \
1151 ch = 10; /* line feed */ \
1157 ch = 13; /* carriage return */ \
1169 ch = 11; /* vertical tab */ \
1172 case 'x': /* hex code */ \
1180 /* other characters passed through */ \
1182 ch = translate[(unsigned char)ch]; \
1188 SilcResult silc_re_compile_pattern(unsigned char *regex, int size,
1197 int pattern_offset = 0, alloc;
1198 int starts[NUM_LEVELS * MAX_NESTING];
1200 int future_jumps[MAX_NESTING];
1202 unsigned char ch = '\0';
1203 unsigned char *pattern;
1204 unsigned char *translate;
1207 int num_open_registers;
1208 int open_registers[RE_NREGS];
1209 int beginning_context;
1211 if (!silc_re_compile_initialized)
1212 silc_re_compile_initialize();
1214 bufp->fastmap_accurate = 0;
1215 bufp->uses_registers = 1;
1216 bufp->num_registers = 1;
1217 translate = bufp->translate;
1218 pattern = bufp->buffer;
1219 alloc = bufp->allocated;
1220 if (alloc == 0 || pattern == NULL)
1223 pattern = silc_smalloc(bufp->rstack, alloc);
1232 num_open_registers = 0;
1235 beginning_context = 1;
1237 /* we use Rend dummy to ensure that pending jumps are updated
1238 (due to low priority of Rend) before exiting the loop. */
1248 ch = translate[(unsigned char)ch];
1249 op = silc_regexp_plain_ops[(unsigned char)ch];
1253 op = silc_regexp_quoted_ops[(unsigned char)ch];
1254 if (op == Rnormal && silc_regexp_ansi_sequences)
1258 level = silc_regexp_precedencess[op];
1259 /* printf("ch='%c' op=%d level=%d current_level=%d
1260 curlevstart=%d\n", ch, op, level, current_level,
1261 CURRENT_LEVEL_START); */
1262 if (level > current_level)
1264 for (current_level++; current_level < level; current_level++)
1269 if (level < current_level)
1271 current_level = level;
1272 for (;num_jumps > 0 &&
1273 future_jumps[num_jumps-1] >= CURRENT_LEVEL_START;
1275 PUT_ADDR(future_jumps[num_jumps-1], pattern_offset);
1287 store_opcode_and_arg: /* opcode & ch must be set */
1305 SILC_VERIFY(op != Rquote);
1310 if (!beginning_context) {
1311 if (silc_regexp_context_indep_ops)
1321 if (!((pos >= size) ||
1322 ((silc_regexp_syntax & RE_NO_BK_VBAR) ?
1323 (regex[pos] == '\174') :
1324 (pos+1 < size && regex[pos] == '\134' &&
1325 regex[pos+1] == '\174')) ||
1326 ((silc_regexp_syntax & RE_NO_BK_PARENS)?
1327 (regex[pos] == ')'):
1328 (pos+1 < size && regex[pos] == '\134' &&
1329 regex[pos+1] == ')')))) {
1330 if (silc_regexp_context_indep_ops)
1342 if (beginning_context) {
1343 if (silc_regexp_context_indep_ops)
1348 if (CURRENT_LEVEL_START == pattern_offset)
1349 break; /* ignore empty patterns for ? */
1351 INSERT_JUMP(CURRENT_LEVEL_START, Cfailure_jump,
1352 pattern_offset + 3);
1358 if (beginning_context) {
1359 if (silc_regexp_context_indep_ops)
1364 if (CURRENT_LEVEL_START == pattern_offset)
1365 break; /* ignore empty patterns for + and * */
1368 INSERT_JUMP(CURRENT_LEVEL_START, Cfailure_jump,
1369 pattern_offset + 6);
1370 INSERT_JUMP(pattern_offset, Cstar_jump, CURRENT_LEVEL_START);
1371 if (op == Rplus) /* jump over initial failure_jump */
1372 INSERT_JUMP(CURRENT_LEVEL_START, Cdummy_failure_jump,
1373 CURRENT_LEVEL_START + 6);
1379 INSERT_JUMP(CURRENT_LEVEL_START, Cfailure_jump,
1380 pattern_offset + 6);
1381 if (num_jumps >= MAX_NESTING)
1384 future_jumps[num_jumps++] = pattern_offset;
1393 if (next_register < RE_NREGS)
1395 bufp->uses_registers = 1;
1397 STORE(Cstart_memory);
1398 STORE(next_register);
1399 open_registers[num_open_registers++] = next_register;
1400 bufp->num_registers++;
1411 if (paren_depth <= 0)
1412 goto parenthesis_error;
1414 current_level = silc_regexp_precedencess[Ropenpar];
1416 if (paren_depth < num_open_registers)
1418 bufp->uses_registers = 1;
1421 num_open_registers--;
1422 STORE(open_registers[num_open_registers]);
1429 goto bad_match_register;
1430 SILC_ASSERT(ch >= '0' && ch <= '9');
1431 bufp->uses_registers = 1;
1432 opcode = Cmatch_memory;
1434 goto store_opcode_and_arg;
1436 case Rextended_memory:
1439 if (ch < '0' || ch > '9')
1440 goto bad_match_register;
1442 if (a < '0' || a > '9')
1443 goto bad_match_register;
1444 ch = 10 * (a - '0') + ch - '0';
1445 if (ch == 0 || ch >= RE_NREGS)
1446 goto bad_match_register;
1447 bufp->uses_registers = 1;
1448 opcode = Cmatch_memory;
1449 goto store_opcode_and_arg;
1462 offset = pattern_offset;
1463 for (a = 0; a < 256/8; a++)
1467 ch = translate[(unsigned char)ch];
1473 ch = translate[(unsigned char)ch];
1480 while (ch != '\135' || firstchar)
1483 if (silc_regexp_ansi_sequences && ch == '\134')
1490 for (a = prev; a <= (int)ch; a++)
1491 SETBIT(pattern, offset, a);
1496 if (prev != -1 && ch == '-')
1500 SETBIT(pattern, offset, ch);
1505 ch = translate[(unsigned char)ch];
1508 SETBIT(pattern, offset, '-');
1511 for (a = 0; a < 256/8; a++)
1512 pattern[offset+a] ^= 0xff;
1518 /* The bounded repeat syntax: a{n}, a{n,} and a{n,m}. The first
1519 is compiled as n-1 Rnormals. The second is compiled as n-1
1520 Rnormals and one Rplus. The third is compiled as n-1 Rnormals
1521 and m-n Rnormals with Roptionals. 0 values have special
1526 goto normal_char; /* Consider literal */
1528 /* Get the preceding atom */
1530 goto normal_char; /* Consider literal */
1538 goto normal_char; /* Consider literal */
1541 while (isdigit(ch)) {
1548 goto repeat_value_error;
1554 /* Will not do any matching with a{0} */
1555 pattern_offset -= 2;
1559 /* Store min - 1 many Cexacts. */
1560 for (i = 0; i < min - 1; i++) {
1564 STORE((unsigned char)a);
1573 /* The a{n,} case */
1576 /* Store Rstar with a{0,} */
1581 /* Store min - 1 many Cexacts. */
1582 for (i = 0; i < min - 1; i++) {
1586 STORE((unsigned char)a);
1594 /* The a{n,m} case */
1598 goto repeat_value_error;
1601 while (isdigit(ch)) {
1608 goto repeat_value_error;
1610 goto repeat_value_error;
1613 /* Will not do any matching with a{0,0} */
1614 pattern_offset -= 2;
1622 /* Only optional matching with a{0,m}. */
1623 pattern_offset -= 2;
1625 /* Store min - 1 many Cexacts. */
1626 for (i = 0; min && i < min - 1; i++) {
1630 STORE((unsigned char)a);
1633 /* Store max - min Cexacts and Roptionals. */
1634 for (i = 0; i < max - min; i++) {
1638 STORE((unsigned char)a);
1640 INSERT_JUMP(CURRENT_LEVEL_START, Cfailure_jump,
1641 pattern_offset + 3);
1660 opcode = Csyntaxspec;
1662 goto store_opcode_and_arg;
1666 opcode = Cnotsyntaxspec;
1668 goto store_opcode_and_arg;
1682 opcode = Cwordbound;
1687 opcode = Cnotwordbound;
1695 beginning_context = (op == Ropenpar || op == Ror);
1697 if (starts_base != 0)
1698 goto parenthesis_error;
1699 SILC_ASSERT(num_jumps == 0);
1703 if (!silc_re_optimize(bufp))
1709 return SILC_ERR_REGEX_SPECIAL;
1713 return SILC_ERR_REGEX_REG;
1717 return SILC_ERR_REGEX_HEX;
1721 return SILC_ERR_REGEX_PAREN;
1725 return SILC_ERR_OUT_OF_MEMORY;
1729 return SILC_ERR_OVERFLOW;
1733 return SILC_ERR_REGEX_TOO_COMPLEX;
1737 return SILC_ERR_REGEX_REPEAT;
1745 #undef CURRENT_LEVEL_START
1746 #undef SET_LEVEL_START
1747 #undef PUSH_LEVEL_STARTS
1748 #undef POP_LEVEL_STARTS
1754 #define PREFETCH if (text == textend) goto fail
1756 #define NEXTCHAR(var) \
1758 var = (unsigned char)*text++; \
1760 var = translate[var]
1762 int silc_re_match(SilcRegex bufp, unsigned char *string, int size, int pos,
1763 regexp_registers_t old_regs, unsigned int flags)
1765 unsigned char *code;
1766 unsigned char *translate;
1767 unsigned char *text;
1768 unsigned char *textstart;
1769 unsigned char *textend;
1775 unsigned char *regstart;
1776 unsigned char *regend;
1780 SILC_ASSERT(pos >= 0 && size >= 0);
1781 SILC_ASSERT(pos <= size);
1783 text = string + pos;
1785 textend = string + size;
1787 code = bufp->buffer;
1789 translate = bufp->translate;
1791 NEW_STATE(state, bufp->num_registers);
1798 match_end = text - textstart;
1801 old_regs->start[0] = pos;
1802 old_regs->end[0] = match_end;
1803 if (!bufp->uses_registers)
1805 for (a = 1; a < RE_NREGS; a++)
1807 old_regs->start[a] = -1;
1808 old_regs->end[a] = -1;
1813 for (a = 1; a < bufp->num_registers; a++)
1815 if ((GET_REG_START(state, a) == NULL) ||
1816 (GET_REG_END(state, a) == NULL))
1818 old_regs->start[a] = -1;
1819 old_regs->end[a] = -1;
1822 old_regs->start[a] = GET_REG_START(state, a) - textstart;
1823 old_regs->end[a] = GET_REG_END(state, a) - textstart;
1825 for (; a < RE_NREGS; a++)
1827 old_regs->start[a] = -1;
1828 old_regs->end[a] = -1;
1833 return match_end - pos;
1837 if (text == textstart || text[-1] == '\n') {
1838 if (flags & RE_NOTBOL)
1840 goto continue_matching;
1846 if (text == textend || *text == '\n') {
1847 if (flags & RE_NOTEOL)
1849 goto continue_matching;
1856 if (code[ch/8] & (1<<(ch & 7)))
1859 goto continue_matching;
1866 if (ch != (unsigned char)*code++)
1868 goto continue_matching;
1875 goto continue_matching;
1880 SET_REG_START(state, reg, text, goto error);
1881 goto continue_matching;
1886 SET_REG_END(state, reg, text, goto error);
1887 goto continue_matching;
1892 regstart = GET_REG_START(state, reg);
1893 regend = GET_REG_END(state, reg);
1894 if ((regstart == NULL) || (regend == NULL))
1895 goto fail; /* or should we just match nothing? */
1896 regsize = regend - regstart;
1898 if (regsize > (textend - text))
1902 for (; regstart < regend; regstart++, text++)
1903 if (translate[*regstart] != translate[*text])
1907 for (; regstart < regend; regstart++, text++)
1908 if (*regstart != *text)
1910 goto continue_matching;
1912 case Cupdate_failure_jump:
1914 UPDATE_FAILURE(state, text, goto error);
1915 /* fall to next case */
1917 /* treat Cstar_jump just like Cjump if it hasn't been optimized */
1921 a = (unsigned char)*code++;
1922 a |= (unsigned char)*code++ << 8;
1923 code += (int)SHORT(a);
1924 if (code<bufp->buffer || bufp->buffer+bufp->used<code) {
1925 silc_set_errno(SILC_ERR_OVERFLOW);
1929 goto continue_matching;
1931 case Cdummy_failure_jump:
1933 unsigned char *failuredest;
1935 a = (unsigned char)*code++;
1936 a |= (unsigned char)*code++ << 8;
1938 SILC_ASSERT(*code == Cfailure_jump);
1939 b = (unsigned char)code[1];
1940 b |= (unsigned char)code[2] << 8;
1941 failuredest = code + (int)SHORT(b) + 3;
1942 if (failuredest<bufp->buffer || bufp->buffer+bufp->used < failuredest) {
1943 silc_set_errno(SILC_ERR_OVERFLOW);
1947 PUSH_FAILURE(state, failuredest, NULL, goto error);
1949 if (code<bufp->buffer || bufp->buffer+bufp->used < code) {
1950 silc_set_errno(SILC_ERR_OVERFLOW);
1954 goto continue_matching;
1958 a = (unsigned char)*code++;
1959 a |= (unsigned char)*code++ << 8;
1961 if (code+a<bufp->buffer || bufp->buffer+bufp->used < code+a) {
1962 silc_set_errno(SILC_ERR_OVERFLOW);
1966 PUSH_FAILURE(state, code + a, text, goto error);
1967 goto continue_matching;
1971 unsigned char *pinst;
1972 a = (unsigned char)*code++;
1973 a |= (unsigned char)*code++ << 8;
1976 if (pinst<bufp->buffer || bufp->buffer+bufp->used<pinst) {
1977 silc_set_errno(SILC_ERR_OVERFLOW);
1981 /* pinst is sole instruction in loop, and it matches a
1982 * single character. Since Crepeat1 was originally a
1983 * Cupdate_failure_jump, we also know that backtracking
1984 * is useless: so long as the single-character
1985 * expression matches, it must be used. Also, in the
1986 * case of +, we've already matched one character, so +
1987 * can't fail: nothing here can cause a failure. */
1994 while (text < textend)
1996 ch = translate[(unsigned char)*text];
1997 if (pinst[ch/8] & (1<<(ch & 7)))
2005 while (text < textend)
2007 ch = (unsigned char)*text;
2008 if (pinst[ch/8] & (1<<(ch & 7)))
2018 ch = (unsigned char)*pinst;
2021 while (text < textend &&
2022 translate[(unsigned char)*text] == ch)
2027 while (text < textend && (unsigned char)*text == ch)
2034 while (text < textend && (unsigned char)*text != '\n')
2040 a = (unsigned char)*pinst;
2043 while (text < textend &&
2044 (SYNTAX(translate[*text]) & a) )
2049 while (text < textend && (SYNTAX(*text) & a) )
2054 case Cnotsyntaxspec:
2056 a = (unsigned char)*pinst;
2059 while (text < textend &&
2060 !(SYNTAX(translate[*text]) & a) )
2065 while (text < textend && !(SYNTAX(*text) & a) )
2073 silc_set_errno(SILC_ERR_REGEX_OPCODE);
2078 /* due to the funky way + and * are compiled, the top
2079 * failure- stack entry at this point is actually a
2080 * success entry -- update it & pop it */
2081 UPDATE_FAILURE(state, text, goto error);
2082 goto fail; /* i.e., succeed <wink/sigh> */
2086 if (text == textstart)
2087 goto continue_matching;
2092 if (text == textend)
2093 goto continue_matching;
2098 if (text == textend)
2100 if (!(SYNTAX(*text) & Sword))
2102 if (text == textstart)
2103 goto continue_matching;
2104 if (!(SYNTAX(text[-1]) & Sword))
2105 goto continue_matching;
2110 if (text == textstart)
2112 if (!(SYNTAX(text[-1]) & Sword))
2114 if (text == textend)
2115 goto continue_matching;
2116 if (!(SYNTAX(*text) & Sword))
2117 goto continue_matching;
2122 /* Note: as in gnu regexp, this also matches at the
2123 * beginning and end of buffer. */
2125 if (text == textstart || text == textend)
2126 goto continue_matching;
2127 if ((SYNTAX(text[-1]) & Sword) ^ (SYNTAX(*text) & Sword))
2128 goto continue_matching;
2133 /* Note: as in gnu regexp, this never matches at the
2134 * beginning and end of buffer. */
2135 if (text == textstart || text == textend)
2137 if (!((SYNTAX(text[-1]) & Sword) ^ (SYNTAX(*text) & Sword)))
2138 goto continue_matching;
2144 if (!(SYNTAX(ch) & (unsigned char)*code++))
2146 goto continue_matching;
2148 case Cnotsyntaxspec:
2151 if (SYNTAX(ch) & (unsigned char)*code++)
2153 goto continue_matching;
2158 silc_set_errno(SILC_ERR_REGEX_OPCODE);
2164 /* Using "break;" in the above switch statement is equivalent to
2167 POP_FAILURE(state, code, text, goto done_matching, goto error);
2168 goto continue_matching;
2171 /* if(translated != NULL) */
2172 /* free(translated); */
2177 /* if (translated != NULL) */
2178 /* free(translated); */
2186 int silc_re_search(SilcRegex bufp, unsigned char *string, int size, int pos,
2187 int range, regexp_registers_t regs, unsigned int flags)
2189 unsigned char *fastmap;
2190 unsigned char *translate;
2191 unsigned char *text;
2192 unsigned char *partstart;
2193 unsigned char *partend;
2196 unsigned char anchor;
2198 SILC_ASSERT(size >= 0 && pos >= 0);
2199 SILC_ASSERT(pos + range >= 0 && pos + range <= size); /* Bugfix by ylo */
2201 fastmap = bufp->fastmap;
2202 translate = bufp->translate;
2203 if (fastmap && !bufp->fastmap_accurate) {
2204 if (silc_re_compile_fastmap(bufp))
2208 anchor = bufp->anchor;
2209 if (bufp->can_be_null == 1) /* can_be_null == 2: can match null at eob */
2227 for (; range >= 0; range--, pos += dir)
2232 { /* searching forwards */
2234 text = string + pos;
2235 partend = string + size;
2238 while (text != partend &&
2239 !fastmap[(unsigned char) translate[(unsigned char)*text]])
2242 while (text != partend && !fastmap[(unsigned char)*text])
2244 pos += text - partstart;
2245 range -= text - partstart;
2246 if (pos == size && bufp->can_be_null == 0)
2250 { /* searching backwards */
2251 text = string + pos;
2252 partstart = string + pos - range;
2255 while (text != partstart &&
2256 !fastmap[(unsigned char)
2257 translate[(unsigned char)*text]])
2260 while (text != partstart &&
2261 !fastmap[(unsigned char)*text])
2263 pos -= partend - text;
2264 range -= partend - text;
2268 { /* anchored to begline */
2269 if (pos > 0 && (string[pos - 1] != '\n'))
2272 SILC_ASSERT(pos >= 0 && pos <= size);
2273 ret = silc_re_match(bufp, string, size, pos, regs, flags);
2282 /****************************** SILC Regex API ******************************/
2284 /* Compile regular expression */
2286 SilcBool silc_regex_compile(SilcRegex regexp, const char *regex,
2287 SilcRegexFlags flags)
2291 if (!regexp || !regex) {
2292 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
2296 memset(regexp, 0, sizeof(*regexp));
2298 /* Get global stack, if set, and create child stack. */
2299 regexp->rstack = silc_stack_get_global();
2301 regexp->rstack = silc_stack_alloc(512, regexp->rstack);
2304 ret = silc_re_compile_pattern((char *)regex, strlen(regex), regexp);
2306 silc_set_errno(ret);
2308 if (ret != SILC_OK) {
2309 silc_regex_free(regexp);
2310 regexp->rstack = NULL;
2311 regexp->buffer = NULL;
2314 return ret == SILC_OK;
2317 /* Match compiled regular expression */
2319 SilcBool silc_regex_match(SilcRegex regexp, const char *string,
2320 SilcUInt32 string_len, SilcUInt32 num_match,
2321 SilcRegexMatch match, SilcRegexFlags flags)
2323 struct re_registers regs;
2327 if (!regexp || !string) {
2328 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
2332 if (num_match && !match) {
2333 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
2337 /* Internal limit for maximum number of registers */
2338 if (num_match > RE_NREGS)
2339 num_match = RE_NREGS;
2342 if (flags & SILC_REGEX_NOTBOL)
2344 if (flags & SILC_REGEX_NOTEOL)
2348 ret = silc_re_search(regexp, (char *)string, string_len, 0, string_len,
2349 num_match ? ®s : NULL, f);
2352 silc_set_errno(SILC_ERR_NOT_FOUND);
2356 /* Return matches */
2357 for (i = 0; i < num_match; i++) {
2358 match[i].start = regs.start[i];
2359 match[i].end = regs.end[i];
2368 void silc_regex_free(SilcRegex regexp)
2370 silc_sfree(regexp->rstack, regexp->buffer);
2371 silc_stack_free(regexp->rstack);
2376 SilcBool silc_regex_va(const char *string, SilcUInt32 string_len,
2377 const char *regex, SilcBuffer match, va_list va)
2379 SilcRegexStruct reg;
2380 SilcRegexMatch m = NULL;
2381 SilcBuffer buf, *rets = NULL;
2386 if (!silc_regex_compile(®, regex, 0))
2390 silc_stack_push(stack, NULL);
2392 /* Get match pointers */
2394 rets = silc_smalloc(stack, sizeof(*rets));
2396 silc_stack_pop(stack);
2397 silc_regex_free(®);
2402 while ((buf = va_arg(va, SilcBuffer))) {
2403 rets = silc_srealloc(stack, c * sizeof(*rets),
2404 rets, (c + 1) * sizeof(*rets));
2406 silc_stack_pop(stack);
2407 silc_regex_free(®);
2413 m = silc_smalloc(stack, c * sizeof(*m));
2415 silc_sfree(stack, rets);
2416 silc_stack_pop(stack);
2417 silc_regex_free(®);
2423 if (!silc_regex_match(®, string, string_len, c, m, 0)) {
2424 silc_sfree(stack, m);
2425 silc_sfree(stack, rets);
2426 silc_stack_pop(stack);
2427 silc_regex_free(®);
2431 /* Return matches */
2432 for (i = 0; i < c; i++) {
2433 if (m[i].start == -1)
2435 silc_buffer_set(rets[i], (unsigned char *)string + m[i].start,
2436 m[i].end - m[i].start);
2439 silc_sfree(stack, m);
2440 silc_sfree(stack, rets);
2441 silc_stack_pop(stack);
2442 silc_regex_free(®);
2449 SilcBool silc_regex(const char *string, const char *regex,
2450 SilcBuffer match, ...)
2455 if (!string || !regex) {
2456 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
2461 va_start(va, match);
2463 ret = silc_regex_va(string, strlen(string), regex, match, va);
2473 SilcBool silc_regex_buffer(SilcBuffer buffer, const char *regex,
2474 SilcBuffer match, ...)
2479 if (!buffer || !regex) {
2480 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
2485 va_start(va, match);
2487 ret = silc_regex_va((const char *)silc_buffer_data(buffer),
2488 silc_buffer_len(buffer), regex, match, va);