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 following features:
32 - RE_NOTBOL - bol fails to match (conforming POSIX)
33 - RE_NOTEOL - eol fails to match (conforming POSIX)
34 - RE_REPEAT a{n,m} - bounded repeat (conforming POSIX)
35 - SilStack support - compile without real memory allocations
40 #define RE_NREGS 128 /* number of registers available */
42 /* bit definitions for syntax */
43 #define RE_NO_BK_PARENS 1 /* no quoting for parentheses */
44 #define RE_NO_BK_VBAR 2 /* no quoting for vertical bar */
45 #define RE_BK_PLUS_QM 4 /* quoting needed for + and ? */
46 #define RE_TIGHT_VBAR 8 /* | binds tighter than ^ and $ */
47 #define RE_NEWLINE_OR 16 /* treat newline as or */
48 #define RE_CONTEXT_INDEP_OPS 32 /* ^$?*+ are special in all contexts */
49 #define RE_ANSI_HEX 64 /* ansi sequences (\n etc) and \xhh */
50 #define RE_NO_GNU_EXTENSIONS 128 /* no gnu extensions */
51 #define RE_NOTBOL 256 /* bol fails to match */
52 #define RE_NOTEOL 512 /* eol fails to match */
53 #define RE_REPEAT 1024 /* bounded repeat, must be quoted without
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_EMACS 0
69 typedef struct re_registers {
70 int start[RE_NREGS]; /* start offset of region */
71 int end[RE_NREGS]; /* end offset of region */
72 } *regexp_registers_t;
74 /* The original code blithely assumed that sizeof(short) == 2. Not
75 * always true. Original instances of "(short)x" were replaced by
76 * SHORT(x), where SHORT is #defined below. */
78 #define SHORT(x) ((x) & 0x8000 ? (x) - 0x10000 : (x))
80 /* The stack implementation is taken from an idea by Andrew Kuchling.
81 * It's a doubly linked list of arrays. The advantages of this over a
82 * simple linked list are that the number of mallocs required are
83 * reduced. It also makes it possible to statically allocate enough
84 * space so that small patterns don't ever need to call malloc.
86 * The advantages over a single array is that is periodically
87 * realloced when more space is needed is that we avoid ever copying
90 /* item_t is the basic stack element. Defined as a union of
91 * structures so that both registers, failure points, and counters can
92 * be pushed/popped from the stack. There's nothing built into the
93 * item to keep track of whether a certain stack item is a register, a
94 * failure point, or a counter. */
102 unsigned char *start;
121 #define STACK_PAGE_SIZE 256
122 #define NUM_REGISTERS 256
124 /* A 'page' of stack items. */
126 typedef struct item_page_t
128 item_t items[STACK_PAGE_SIZE];
129 struct item_page_t *prev;
130 struct item_page_t *next;
133 typedef struct match_state
135 /* The number of registers that have been pushed onto the stack
136 * since the last failure point. */
140 /* Used to control when registers need to be pushed onto the
145 /* The number of failure points on the stack. */
149 /* Storage for the registers. Each register consists of two
150 * pointers to characters. So register N is represented as
151 * start[N] and end[N]. The pointers must be converted to
152 * offsets from the beginning of the string before returning the
153 * registers to the calling program. */
155 unsigned char *start[NUM_REGISTERS];
156 unsigned char *end[NUM_REGISTERS];
158 /* Keeps track of whether a register has changed recently. */
160 int changed[NUM_REGISTERS];
162 /* Structure to encapsulate the stack. */
165 /* index into the current page. If index == 0 and you need
166 * to pop an item, move to the previous page and set index
167 * = STACK_PAGE_SIZE - 1. Otherwise decrement index to
168 * push a page. If index == STACK_PAGE_SIZE and you need
169 * to push a page move to the next page and set index =
170 * 0. If there is no new next page, allocate a new page
171 * and link it in. Otherwise, increment index to push a
175 item_page_t *current; /* Pointer to the current page. */
176 item_page_t first; /* First page is statically allocated. */
180 /* Initialize a state object */
182 /* #define NEW_STATE(state) \ */
183 /* memset(&state, 0, (void *)(&state.stack) - (void *)(&state)); \ */
184 /* state.stack.current = &state.stack.first; \ */
185 /* state.stack.first.prev = NULL; \ */
186 /* state.stack.first.next = NULL; \ */
187 /* state.stack.index = 0; \ */
188 /* state.level = 1 */
190 #define NEW_STATE(state, nregs) \
193 for (i = 0; i < nregs; i++) \
195 state.start[i] = NULL; \
196 state.end[i] = NULL; \
197 state.changed[i] = 0; \
199 state.stack.current = &state.stack.first; \
200 state.stack.first.prev = NULL; \
201 state.stack.first.next = NULL; \
202 state.stack.index = 0; \
209 /* Free any memory that might have been malloc'd */
211 #define FREE_STATE(state) \
212 while(state.stack.first.next != NULL) \
214 state.stack.current = state.stack.first.next; \
215 state.stack.first.next = state.stack.current->next; \
216 silc_sfree(bufp->rstack, state.stack.current); \
219 /* Discard the top 'count' stack items. */
221 #define STACK_DISCARD(stack, count, on_error) \
222 stack.index -= count; \
223 while (stack.index < 0) \
225 if (stack.current->prev == NULL) \
227 stack.current = stack.current->prev; \
228 stack.index += STACK_PAGE_SIZE; \
231 /* Store a pointer to the previous item on the stack. Used to pop an
232 * item off of the stack. */
234 #define STACK_PREV(stack, top, on_error) \
235 if (stack.index == 0) \
237 if (stack.current->prev == NULL) \
239 stack.current = stack.current->prev; \
240 stack.index = STACK_PAGE_SIZE - 1; \
246 top = &(stack.current->items[stack.index])
248 /* Store a pointer to the next item on the stack. Used to push an item
249 * on to the stack. */
251 #define STACK_NEXT(stack, top, on_error) \
252 if (stack.index == STACK_PAGE_SIZE) \
254 if (stack.current->next == NULL) \
256 stack.current->next = \
257 (item_page_t *)silc_smalloc(bufp->rstack, sizeof(item_page_t)); \
258 if (stack.current->next == NULL) \
260 stack.current->next->prev = stack.current; \
261 stack.current->next->next = NULL; \
263 stack.current = stack.current->next; \
266 top = &(stack.current->items[stack.index++])
268 /* Store a pointer to the item that is 'count' items back in the
269 * stack. STACK_BACK(stack, top, 1, on_error) is equivalent to
270 * STACK_TOP(stack, top, on_error). */
272 #define STACK_BACK(stack, top, count, on_error) \
275 item_page_t *current; \
276 current = stack.current; \
277 index = stack.index - (count); \
280 if (current->prev == NULL) \
282 current = current->prev; \
283 index += STACK_PAGE_SIZE; \
285 top = &(current->items[index]); \
288 /* Store a pointer to the top item on the stack. Execute the
289 * 'on_error' code if there are no items on the stack. */
291 #define STACK_TOP(stack, top, on_error) \
292 if (stack.index == 0) \
294 if (stack.current->prev == NULL) \
296 top = &(stack.current->prev->items[STACK_PAGE_SIZE - 1]); \
300 top = &(stack.current->items[stack.index - 1]); \
303 /* Test to see if the stack is empty */
305 #define STACK_EMPTY(stack) ((stack.index == 0) && \
306 (stack.current->prev == NULL))
308 /* Return the start of register 'reg' */
310 #define GET_REG_START(state, reg) (state.start[reg])
312 /* Return the end of register 'reg' */
314 #define GET_REG_END(state, reg) (state.end[reg])
316 /* Set the start of register 'reg'. If the state of the register needs
317 * saving, push it on the stack. */
319 #define SET_REG_START(state, reg, text, on_error) \
320 if(state.changed[reg] < state.level) \
323 STACK_NEXT(state.stack, item, on_error); \
324 item->reg.num = reg; \
325 item->reg.start = state.start[reg]; \
326 item->reg.end = state.end[reg]; \
327 item->reg.level = state.changed[reg]; \
328 state.changed[reg] = state.level; \
331 state.start[reg] = text
333 /* Set the end of register 'reg'. If the state of the register needs
334 * saving, push it on the stack. */
336 #define SET_REG_END(state, reg, text, on_error) \
337 if(state.changed[reg] < state.level) \
340 STACK_NEXT(state.stack, item, on_error); \
341 item->reg.num = reg; \
342 item->reg.start = state.start[reg]; \
343 item->reg.end = state.end[reg]; \
344 item->reg.level = state.changed[reg]; \
345 state.changed[reg] = state.level; \
348 state.end[reg] = text
350 #define PUSH_FAILURE(state, xcode, xtext, on_error) \
353 STACK_NEXT(state.stack, item, on_error); \
354 item->fail.code = xcode; \
355 item->fail.text = xtext; \
356 item->fail.count = state.count; \
357 item->fail.level = state.level; \
358 item->fail.phantom = 0; \
364 /* Update the last failure point with a new position in the text. */
366 #define UPDATE_FAILURE(state, xtext, on_error) \
369 STACK_BACK(state.stack, item, state.count + 1, on_error); \
370 if (!item->fail.phantom) \
373 STACK_NEXT(state.stack, item2, on_error); \
374 item2->fail.code = item->fail.code; \
375 item2->fail.text = xtext; \
376 item2->fail.count = state.count; \
377 item2->fail.level = state.level; \
378 item2->fail.phantom = 1; \
385 STACK_DISCARD(state.stack, state.count, on_error); \
386 STACK_TOP(state.stack, item, on_error); \
387 item->fail.text = xtext; \
393 #define POP_FAILURE(state, xcode, xtext, on_empty, on_error) \
398 while(state.count > 0) \
400 STACK_PREV(state.stack, item, on_error); \
401 state.start[item->reg.num] = item->reg.start; \
402 state.end[item->reg.num] = item->reg.end; \
403 state.changed[item->reg.num] = item->reg.level; \
406 STACK_PREV(state.stack, item, on_empty); \
407 xcode = item->fail.code; \
408 xtext = item->fail.text; \
409 state.count = item->fail.count; \
410 state.level = item->fail.level; \
413 while (item->fail.text == NULL); \
416 enum regexp_compiled_ops /* opcodes for compiled regexp */
418 Cend, /* end of pattern reached */
419 Cbol, /* beginning of line */
420 Ceol, /* end of line */
421 Cset, /* character set. Followed by 32 bytes of set. */
422 Cexact, /* followed by a byte to match */
423 Canychar, /* matches any character except newline */
424 Cstart_memory, /* set register start addr (followed by reg number) */
425 Cend_memory, /* set register end addr (followed by reg number) */
426 Cmatch_memory, /* match a duplicate of reg contents (regnum follows)*/
427 Cjump, /* followed by two bytes (lsb,msb) of displacement. */
428 Cstar_jump, /* will change to jump/update_failure_jump at runtime */
429 Cfailure_jump, /* jump to addr on failure */
430 Cupdate_failure_jump, /* update topmost failure point and jump */
431 Cdummy_failure_jump, /* push a dummy failure point and jump */
432 Cbegbuf, /* match at beginning of buffer */
433 Cendbuf, /* match at end of buffer */
434 Cwordbeg, /* match at beginning of word */
435 Cwordend, /* match at end of word */
436 Cwordbound, /* match if at word boundary */
437 Cnotwordbound, /* match if not at word boundary */
438 Csyntaxspec, /* matches syntax code (1 byte follows) */
439 Cnotsyntaxspec, /* matches if syntax code does not match (1 byte foll)*/
443 enum regexp_syntax_op /* syntax codes for plain and quoted characters */
445 Rend, /* special code for end of regexp */
446 Rnormal, /* normal character */
447 Ranychar, /* any character except newline */
448 Rquote, /* the quote character */
449 Rbol, /* match beginning of line */
450 Reol, /* match end of line */
451 Roptional, /* match preceding expression optionally */
452 Rstar, /* match preceding expr zero or more times */
453 Rplus, /* match preceding expr one or more times */
454 Ror, /* match either of alternatives */
455 Ropenpar, /* opening parenthesis */
456 Rclosepar, /* closing parenthesis */
457 Rmemory, /* match memory register */
458 Rextended_memory, /* \vnn to match registers 10-99 */
459 Ropenset, /* open set. Internal syntax hard-coded below. */
460 /* the following are gnu extensions to "normal" regexp syntax */
461 Rbegbuf, /* beginning of buffer */
462 Rendbuf, /* end of buffer */
463 Rwordchar, /* word character */
464 Rnotwordchar, /* not word character */
465 Rwordbeg, /* beginning of word */
466 Rwordend, /* end of word */
467 Rwordbound, /* word bound */
468 Rnotwordbound, /* not word bound */
470 Ropenrep, /* opening bounded repeat */
473 static int re_compile_initialized = 0;
474 static int regexp_syntax = 0;
475 static unsigned char regexp_plain_ops[256];
476 static unsigned char regexp_quoted_ops[256];
477 static unsigned char regexp_precedences[Rnum_ops];
478 static int regexp_context_indep_ops;
479 static int regexp_ansi_sequences;
481 #define NUM_LEVELS 5 /* number of precedence levels in use */
482 #define MAX_NESTING 100 /* max nesting level of operators */
484 #define SYNTAX(ch) re_syntax_table[(unsigned char)(ch)]
486 unsigned char re_syntax_table[256];
488 void re_compile_initialize(void)
492 static int syntax_table_inited = 0;
494 if (!syntax_table_inited)
496 syntax_table_inited = 1;
497 memset(re_syntax_table, 0, 256);
498 for (a = 'a'; a <= 'z'; a++)
499 re_syntax_table[a] = Sword;
500 for (a = 'A'; a <= 'Z'; a++)
501 re_syntax_table[a] = Sword;
502 for (a = '0'; a <= '9'; a++)
503 re_syntax_table[a] = Sword | Sdigit | Shexdigit;
504 for (a = '0'; a <= '7'; a++)
505 re_syntax_table[a] |= Soctaldigit;
506 for (a = 'A'; a <= 'F'; a++)
507 re_syntax_table[a] |= Shexdigit;
508 for (a = 'a'; a <= 'f'; a++)
509 re_syntax_table[a] |= Shexdigit;
510 re_syntax_table['_'] = Sword;
511 for (a = 9; a <= 13; a++)
512 re_syntax_table[a] = Swhitespace;
513 re_syntax_table[' '] = Swhitespace;
515 re_compile_initialized = 1;
516 for (a = 0; a < 256; a++)
518 regexp_plain_ops[a] = Rnormal;
519 regexp_quoted_ops[a] = Rnormal;
521 for (a = '0'; a <= '9'; a++)
522 regexp_quoted_ops[a] = Rmemory;
523 regexp_plain_ops['\134'] = Rquote;
524 if (regexp_syntax & RE_NO_BK_PARENS)
526 regexp_plain_ops['('] = Ropenpar;
527 regexp_plain_ops[')'] = Rclosepar;
531 regexp_quoted_ops['('] = Ropenpar;
532 regexp_quoted_ops[')'] = Rclosepar;
534 if (regexp_syntax & RE_NO_BK_VBAR)
535 regexp_plain_ops['\174'] = Ror;
537 regexp_quoted_ops['\174'] = Ror;
538 regexp_plain_ops['*'] = Rstar;
539 if (regexp_syntax & RE_BK_PLUS_QM)
541 regexp_quoted_ops['+'] = Rplus;
542 regexp_quoted_ops['?'] = Roptional;
546 regexp_plain_ops['+'] = Rplus;
547 regexp_plain_ops['?'] = Roptional;
549 if (regexp_syntax & RE_NEWLINE_OR)
550 regexp_plain_ops['\n'] = Ror;
551 regexp_plain_ops['\133'] = Ropenset;
552 regexp_plain_ops['\136'] = Rbol;
553 regexp_plain_ops['$'] = Reol;
554 regexp_plain_ops['.'] = Ranychar;
555 if (!(regexp_syntax & RE_NO_GNU_EXTENSIONS))
557 regexp_quoted_ops['w'] = Rwordchar;
558 regexp_quoted_ops['W'] = Rnotwordchar;
559 regexp_quoted_ops['<'] = Rwordbeg;
560 regexp_quoted_ops['>'] = Rwordend;
561 regexp_quoted_ops['b'] = Rwordbound;
562 regexp_quoted_ops['B'] = Rnotwordbound;
563 regexp_quoted_ops['`'] = Rbegbuf;
564 regexp_quoted_ops['\''] = Rendbuf;
566 if (regexp_syntax & RE_ANSI_HEX)
567 regexp_quoted_ops['v'] = Rextended_memory;
568 for (a = 0; a < Rnum_ops; a++)
569 regexp_precedences[a] = 4;
570 if (regexp_syntax & RE_TIGHT_VBAR)
572 regexp_precedences[Ror] = 3;
573 regexp_precedences[Rbol] = 2;
574 regexp_precedences[Reol] = 2;
578 regexp_precedences[Ror] = 2;
579 regexp_precedences[Rbol] = 3;
580 regexp_precedences[Reol] = 3;
582 if (regexp_syntax & RE_REPEAT)
584 if (regexp_syntax & RE_NO_BK_PARENS)
586 regexp_plain_ops['{'] = Ropenrep;
590 regexp_quoted_ops['{'] = Ropenrep;
593 regexp_precedences[Rclosepar] = 1;
594 regexp_precedences[Rend] = 0;
595 regexp_context_indep_ops = (regexp_syntax & RE_CONTEXT_INDEP_OPS) != 0;
596 regexp_ansi_sequences = (regexp_syntax & RE_ANSI_HEX) != 0;
599 int re_set_syntax(int syntax)
604 regexp_syntax = syntax;
605 re_compile_initialize();
609 static int hex_char_to_decimal(int ch)
611 if (ch >= '0' && ch <= '9')
613 if (ch >= 'a' && ch <= 'f')
614 return ch - 'a' + 10;
615 if (ch >= 'A' && ch <= 'F')
616 return ch - 'A' + 10;
620 static int re_compile_fastmap_aux(unsigned char *code, int pos,
621 unsigned char *visited,
622 unsigned char *can_be_null,
623 unsigned char *fastmap)
630 return 0; /* we have already been here */
633 switch (code[pos++]) {
647 for (a = 0; a < 256; a++)
653 syntaxcode = code[pos++];
654 for (a = 0; a < 256; a++)
655 if (SYNTAX(a) & syntaxcode)
661 syntaxcode = code[pos++];
662 for (a = 0; a < 256; a++)
663 if (!(SYNTAX(a) & syntaxcode) )
670 if (*can_be_null == 0)
671 *can_be_null = 2; /* can match null, but only at end of buffer*/
676 for (a = 0; a < 256/8; a++)
677 if (code[pos + a] != 0)
678 for (b = 0; b < 8; b++)
679 if (code[pos + a] & (1 << b))
680 fastmap[(a << 3) + b] = 1;
686 fastmap[(unsigned char)code[pos]] = 1;
691 for (a = 0; a < 256; a++)
704 for (a = 0; a < 256; a++)
710 case Cdummy_failure_jump:
711 case Cupdate_failure_jump:
714 a = (unsigned char)code[pos++];
715 a |= (unsigned char)code[pos++] << 8;
716 pos += (int)SHORT(a);
719 /* argh... the regexp contains empty loops. This is not
720 good, as this may cause a failure stack overflow when
721 matching. Oh well. */
722 /* this path leads nowhere; pursue other paths. */
730 a = (unsigned char)code[pos++];
731 a |= (unsigned char)code[pos++] << 8;
732 a = pos + (int)SHORT(a);
733 return re_compile_fastmap_aux(code, a, visited, can_be_null, fastmap);
742 silc_set_errno(SILC_ERR_REGEX_OPCODE);
749 static int 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 = re_compile_fastmap_aux(buffer, pos, visited, can_be_null, fastmap);
771 if (visited != small_visited) {
772 silc_sfree(bufp->rstack, visited);
773 silc_stack_pop(bufp->rstack);
778 int re_compile_fastmap(SilcRegex bufp)
780 if (!bufp->fastmap || bufp->fastmap_accurate)
782 SILC_ASSERT(bufp->used > 0);
783 if (!re_do_compile_fastmap(bufp->buffer,
787 bufp->fastmap, bufp))
789 if (bufp->buffer[0] == Cbol)
790 bufp->anchor = 1; /* begline */
792 if (bufp->buffer[0] == Cbegbuf)
793 bufp->anchor = 2; /* begbuf */
795 bufp->anchor = 0; /* none */
797 bufp->fastmap_accurate = 1;
804 * ... code for operand of star
806 * 2: ... code after star
808 * We change the star_jump to update_failure_jump if we can determine
809 * that it is safe to do so; otherwise we change it to an ordinary
816 * 2: ... code for operand of plus
818 * 3: ... code after plus
820 * For star_jump considerations this is processed identically to star.
824 static int re_optimize_star_jump(SilcRegex bufp, unsigned char *code)
826 unsigned char map[256];
827 unsigned char can_be_null;
833 int num_instructions = 0;
835 a = (unsigned char)*code++;
836 a |= (unsigned char)*code++ << 8;
839 p1 = code + a + 3; /* skip the failure_jump */
840 /* Check that the jump is within the pattern */
841 if (p1<bufp->buffer || bufp->buffer+bufp->used<p1)
843 silc_set_errno(SILC_ERR_OVERFLOW);
847 SILC_ASSERT(p1[-3] == Cfailure_jump);
849 /* p1 points inside loop, p2 points to after loop */
850 if (!re_do_compile_fastmap(bufp->buffer, bufp->used,
851 (int)(p2 - bufp->buffer),
852 &can_be_null, map, bufp))
853 goto make_normal_jump;
855 /* If we might introduce a new update point inside the
856 * loop, we can't optimize because then update_jump would
857 * update a wrong failure point. Thus we have to be
858 * quite careful here.
861 /* loop until we find something that consumes a character */
885 ch = (unsigned char)*p1++;
887 goto make_normal_jump;
892 for (b = 0; b < 256; b++)
893 if (b != '\n' && map[b])
894 goto make_normal_jump;
899 for (b = 0; b < 256; b++)
900 if ((p1[b >> 3] & (1 << (b & 7))) && map[b])
901 goto make_normal_jump;
907 goto make_normal_jump;
910 /* now we know that we can't backtrack. */
950 case Cupdate_failure_jump:
951 case Cdummy_failure_jump:
953 goto make_normal_jump;
962 /* make_update_jump: */
964 a += 3; /* jump to after the Cfailure_jump */
965 code[0] = Cupdate_failure_jump;
968 if (num_instructions > 1)
970 SILC_ASSERT(num_instructions == 1);
971 /* if the only instruction matches a single character, we can do
973 p1 = code + 3 + a; /* start of sole instruction */
974 if (*p1 == Cset || *p1 == Cexact || *p1 == Canychar ||
975 *p1 == Csyntaxspec || *p1 == Cnotsyntaxspec)
985 static int re_optimize(SilcRegex bufp)
1021 case Cnotsyntaxspec:
1028 if (!re_optimize_star_jump(bufp, code))
1034 case Cupdate_failure_jump:
1036 case Cdummy_failure_jump:
1051 #define NEXTCHAR(var) \
1054 goto ends_prematurely; \
1055 (var) = regex[pos]; \
1059 #define ALLOC(amount) \
1061 if (pattern_offset+(amount) > alloc) \
1063 pattern = silc_srealloc(bufp->rstack, alloc, pattern, \
1064 alloc + 256 + (amount)); \
1065 alloc += 256 + (amount); \
1067 goto out_of_memory; \
1071 #define STORE(ch) pattern[pattern_offset++] = (ch)
1073 #define CURRENT_LEVEL_START (starts[starts_base + current_level])
1075 #define SET_LEVEL_START starts[starts_base + current_level] = pattern_offset
1077 #define PUSH_LEVEL_STARTS \
1078 if (starts_base < (MAX_NESTING-1)*NUM_LEVELS) \
1079 starts_base += NUM_LEVELS; \
1083 #define POP_LEVEL_STARTS starts_base -= NUM_LEVELS
1085 #define PUT_ADDR(offset,addr) \
1087 int disp = (addr) - (offset) - 2; \
1088 pattern[(offset)] = disp & 0xff; \
1089 pattern[(offset)+1] = (disp>>8) & 0xff; \
1092 #define INSERT_JUMP(pos,type,addr) \
1094 int a, p = (pos), t = (type), ad = (addr); \
1095 for (a = pattern_offset - 1; a >= p; a--) \
1096 pattern[a + 3] = pattern[a]; \
1099 pattern_offset += 3; \
1102 #define SETBIT(buf,offset,bit) (buf)[(offset)+(bit)/8] |= (1<<((bit) & 7))
1104 #define SET_FIELDS \
1106 bufp->allocated = alloc; \
1107 bufp->buffer = pattern; \
1108 bufp->used = pattern_offset; \
1111 #define GETHEX(var) \
1113 unsigned char gethex_ch, gethex_value; \
1114 NEXTCHAR(gethex_ch); \
1115 gethex_value = hex_char_to_decimal(gethex_ch); \
1116 if (gethex_value == 16) \
1118 NEXTCHAR(gethex_ch); \
1119 gethex_ch = hex_char_to_decimal(gethex_ch); \
1120 if (gethex_ch == 16) \
1122 (var) = gethex_value * 16 + gethex_ch; \
1125 #define ANSI_TRANSLATE(ch) \
1132 ch = 7; /* audible bell */ \
1138 ch = 8; /* backspace */ \
1144 ch = 12; /* form feed */ \
1150 ch = 10; /* line feed */ \
1156 ch = 13; /* carriage return */ \
1168 ch = 11; /* vertical tab */ \
1171 case 'x': /* hex code */ \
1179 /* other characters passed through */ \
1181 ch = translate[(unsigned char)ch]; \
1187 SilcResult re_compile_pattern(unsigned char *regex, int size, SilcRegex bufp)
1195 int pattern_offset = 0, alloc;
1196 int starts[NUM_LEVELS * MAX_NESTING];
1198 int future_jumps[MAX_NESTING];
1200 unsigned char ch = '\0';
1201 unsigned char *pattern;
1202 unsigned char *translate;
1205 int num_open_registers;
1206 int open_registers[RE_NREGS];
1207 int beginning_context;
1209 if (!re_compile_initialized)
1210 re_compile_initialize();
1212 bufp->fastmap_accurate = 0;
1213 bufp->uses_registers = 1;
1214 bufp->num_registers = 1;
1215 translate = bufp->translate;
1216 pattern = bufp->buffer;
1217 alloc = bufp->allocated;
1218 if (alloc == 0 || pattern == NULL)
1221 pattern = silc_smalloc(bufp->rstack, alloc);
1230 num_open_registers = 0;
1233 beginning_context = 1;
1235 /* we use Rend dummy to ensure that pending jumps are updated
1236 (due to low priority of Rend) before exiting the loop. */
1246 ch = translate[(unsigned char)ch];
1247 op = regexp_plain_ops[(unsigned char)ch];
1251 op = regexp_quoted_ops[(unsigned char)ch];
1252 if (op == Rnormal && regexp_ansi_sequences)
1256 level = regexp_precedences[op];
1257 /* printf("ch='%c' op=%d level=%d current_level=%d
1258 curlevstart=%d\n", ch, op, level, current_level,
1259 CURRENT_LEVEL_START); */
1260 if (level > current_level)
1262 for (current_level++; current_level < level; current_level++)
1267 if (level < current_level)
1269 current_level = level;
1270 for (;num_jumps > 0 &&
1271 future_jumps[num_jumps-1] >= CURRENT_LEVEL_START;
1273 PUT_ADDR(future_jumps[num_jumps-1], pattern_offset);
1285 store_opcode_and_arg: /* opcode & ch must be set */
1303 SILC_VERIFY(op != Rquote);
1308 if (!beginning_context) {
1309 if (regexp_context_indep_ops)
1319 if (!((pos >= size) ||
1320 ((regexp_syntax & RE_NO_BK_VBAR) ?
1321 (regex[pos] == '\174') :
1322 (pos+1 < size && regex[pos] == '\134' &&
1323 regex[pos+1] == '\174')) ||
1324 ((regexp_syntax & RE_NO_BK_PARENS)?
1325 (regex[pos] == ')'):
1326 (pos+1 < size && regex[pos] == '\134' &&
1327 regex[pos+1] == ')')))) {
1328 if (regexp_context_indep_ops)
1340 if (beginning_context) {
1341 if (regexp_context_indep_ops)
1346 if (CURRENT_LEVEL_START == pattern_offset)
1347 break; /* ignore empty patterns for ? */
1349 INSERT_JUMP(CURRENT_LEVEL_START, Cfailure_jump,
1350 pattern_offset + 3);
1357 if (beginning_context) {
1358 if (regexp_context_indep_ops)
1363 if (CURRENT_LEVEL_START == pattern_offset)
1364 break; /* ignore empty patterns for + and * */
1366 INSERT_JUMP(CURRENT_LEVEL_START, Cfailure_jump,
1367 pattern_offset + 6);
1368 INSERT_JUMP(pattern_offset, Cstar_jump, CURRENT_LEVEL_START);
1369 if (op == Rplus) /* jump over initial failure_jump */
1370 INSERT_JUMP(CURRENT_LEVEL_START, Cdummy_failure_jump,
1371 CURRENT_LEVEL_START + 6);
1377 INSERT_JUMP(CURRENT_LEVEL_START, Cfailure_jump,
1378 pattern_offset + 6);
1379 if (num_jumps >= MAX_NESTING)
1382 future_jumps[num_jumps++] = pattern_offset;
1391 if (next_register < RE_NREGS)
1393 bufp->uses_registers = 1;
1395 STORE(Cstart_memory);
1396 STORE(next_register);
1397 open_registers[num_open_registers++] = next_register;
1398 bufp->num_registers++;
1409 if (paren_depth <= 0)
1410 goto parenthesis_error;
1412 current_level = regexp_precedences[Ropenpar];
1414 if (paren_depth < num_open_registers)
1416 bufp->uses_registers = 1;
1419 num_open_registers--;
1420 STORE(open_registers[num_open_registers]);
1427 goto bad_match_register;
1428 SILC_ASSERT(ch >= '0' && ch <= '9');
1429 bufp->uses_registers = 1;
1430 opcode = Cmatch_memory;
1432 goto store_opcode_and_arg;
1434 case Rextended_memory:
1437 if (ch < '0' || ch > '9')
1438 goto bad_match_register;
1440 if (a < '0' || a > '9')
1441 goto bad_match_register;
1442 ch = 10 * (a - '0') + ch - '0';
1443 if (ch == 0 || ch >= RE_NREGS)
1444 goto bad_match_register;
1445 bufp->uses_registers = 1;
1446 opcode = Cmatch_memory;
1447 goto store_opcode_and_arg;
1460 offset = pattern_offset;
1461 for (a = 0; a < 256/8; a++)
1465 ch = translate[(unsigned char)ch];
1471 ch = translate[(unsigned char)ch];
1478 while (ch != '\135' || firstchar)
1481 if (regexp_ansi_sequences && ch == '\134')
1488 for (a = prev; a <= (int)ch; a++)
1489 SETBIT(pattern, offset, a);
1494 if (prev != -1 && ch == '-')
1498 SETBIT(pattern, offset, ch);
1503 ch = translate[(unsigned char)ch];
1506 SETBIT(pattern, offset, '-');
1509 for (a = 0; a < 256/8; a++)
1510 pattern[offset+a] ^= 0xff;
1516 /* The bounded repeat syntax: a{n}, a{n,} and a{n,m}. The first
1517 is compiled as n-1 Rnormals. The second is compiled as n-1
1518 Rnormals and one Rplus. The third is compiled as n-1 Rnormals
1519 and m-n Rnormals with Roptionals. 0 values have special
1526 /* Get the preceding atom */
1536 goto repeat_value_error;
1539 while (isdigit(ch)) {
1546 goto repeat_value_error;
1552 /* Will not do any matching with a{0} */
1553 pattern_offset -= 2;
1557 /* Store min - 1 many Cexacts. */
1558 for (i = 0; i < min - 1; i++) {
1562 STORE((unsigned char)a);
1571 /* The a{n,} case */
1574 /* Store Rstar with a{0,} */
1579 /* Store min - 1 many Cexacts. */
1580 for (i = 0; i < min - 1; i++) {
1584 STORE((unsigned char)a);
1592 /* The a{n,m} case */
1596 goto repeat_value_error;
1599 while (isdigit(ch)) {
1606 goto repeat_value_error;
1608 goto repeat_value_error;
1611 /* Will not do any matching with a{0,0} */
1612 pattern_offset -= 2;
1620 /* Only optional matching with a{0,m}. */
1621 pattern_offset -= 2;
1623 /* Store min - 1 many Cexacts. */
1624 for (i = 0; min && i < min - 1; i++) {
1628 STORE((unsigned char)a);
1631 /* Store max - min Cexacts and Roptionals. */
1632 for (i = 0; i < max - min; i++) {
1636 STORE((unsigned char)a);
1638 INSERT_JUMP(CURRENT_LEVEL_START, Cfailure_jump,
1639 pattern_offset + 3);
1658 opcode = Csyntaxspec;
1660 goto store_opcode_and_arg;
1664 opcode = Cnotsyntaxspec;
1666 goto store_opcode_and_arg;
1680 opcode = Cwordbound;
1685 opcode = Cnotwordbound;
1693 beginning_context = (op == Ropenpar || op == Ror);
1695 if (starts_base != 0)
1696 goto parenthesis_error;
1697 SILC_ASSERT(num_jumps == 0);
1701 if (!re_optimize(bufp))
1707 return SILC_ERR_REGEX_SPECIAL;
1711 return SILC_ERR_REGEX_REG;
1715 return SILC_ERR_REGEX_HEX;
1719 return SILC_ERR_REGEX_PAREN;
1723 return SILC_ERR_OUT_OF_MEMORY;
1727 return SILC_ERR_OVERFLOW;
1731 return SILC_ERR_REGEX_TOO_COMPLEX;
1735 return SILC_ERR_REGEX_REPEAT;
1743 #undef CURRENT_LEVEL_START
1744 #undef SET_LEVEL_START
1745 #undef PUSH_LEVEL_STARTS
1746 #undef POP_LEVEL_STARTS
1752 #define PREFETCH if (text == textend) goto fail
1754 #define NEXTCHAR(var) \
1756 var = (unsigned char)*text++; \
1758 var = translate[var]
1760 int re_match(SilcRegex bufp, unsigned char *string, int size, int pos,
1761 regexp_registers_t old_regs, unsigned int flags)
1763 unsigned char *code;
1764 unsigned char *translate;
1765 unsigned char *text;
1766 unsigned char *textstart;
1767 unsigned char *textend;
1773 unsigned char *regstart;
1774 unsigned char *regend;
1778 SILC_ASSERT(pos >= 0 && size >= 0);
1779 SILC_ASSERT(pos <= size);
1781 text = string + pos;
1783 textend = string + size;
1785 code = bufp->buffer;
1787 translate = bufp->translate;
1789 NEW_STATE(state, bufp->num_registers);
1796 match_end = text - textstart;
1799 old_regs->start[0] = pos;
1800 old_regs->end[0] = match_end;
1801 if (!bufp->uses_registers)
1803 for (a = 1; a < RE_NREGS; a++)
1805 old_regs->start[a] = -1;
1806 old_regs->end[a] = -1;
1811 for (a = 1; a < bufp->num_registers; a++)
1813 if ((GET_REG_START(state, a) == NULL) ||
1814 (GET_REG_END(state, a) == NULL))
1816 old_regs->start[a] = -1;
1817 old_regs->end[a] = -1;
1820 old_regs->start[a] = GET_REG_START(state, a) - textstart;
1821 old_regs->end[a] = GET_REG_END(state, a) - textstart;
1823 for (; a < RE_NREGS; a++)
1825 old_regs->start[a] = -1;
1826 old_regs->end[a] = -1;
1831 return match_end - pos;
1835 if (text == textstart || text[-1] == '\n') {
1836 if (flags & RE_NOTBOL)
1838 goto continue_matching;
1844 if (text == textend || *text == '\n') {
1845 if (flags & RE_NOTEOL)
1847 goto continue_matching;
1854 if (code[ch/8] & (1<<(ch & 7)))
1857 goto continue_matching;
1864 if (ch != (unsigned char)*code++)
1866 goto continue_matching;
1873 goto continue_matching;
1878 SET_REG_START(state, reg, text, goto error);
1879 goto continue_matching;
1884 SET_REG_END(state, reg, text, goto error);
1885 goto continue_matching;
1890 regstart = GET_REG_START(state, reg);
1891 regend = GET_REG_END(state, reg);
1892 if ((regstart == NULL) || (regend == NULL))
1893 goto fail; /* or should we just match nothing? */
1894 regsize = regend - regstart;
1896 if (regsize > (textend - text))
1900 for (; regstart < regend; regstart++, text++)
1901 if (translate[*regstart] != translate[*text])
1905 for (; regstart < regend; regstart++, text++)
1906 if (*regstart != *text)
1908 goto continue_matching;
1910 case Cupdate_failure_jump:
1912 UPDATE_FAILURE(state, text, goto error);
1913 /* fall to next case */
1915 /* treat Cstar_jump just like Cjump if it hasn't been optimized */
1919 a = (unsigned char)*code++;
1920 a |= (unsigned char)*code++ << 8;
1921 code += (int)SHORT(a);
1922 if (code<bufp->buffer || bufp->buffer+bufp->used<code) {
1923 silc_set_errno(SILC_ERR_OVERFLOW);
1927 goto continue_matching;
1929 case Cdummy_failure_jump:
1931 unsigned char *failuredest;
1933 a = (unsigned char)*code++;
1934 a |= (unsigned char)*code++ << 8;
1936 SILC_ASSERT(*code == Cfailure_jump);
1937 b = (unsigned char)code[1];
1938 b |= (unsigned char)code[2] << 8;
1939 failuredest = code + (int)SHORT(b) + 3;
1940 if (failuredest<bufp->buffer || bufp->buffer+bufp->used < failuredest) {
1941 silc_set_errno(SILC_ERR_OVERFLOW);
1945 PUSH_FAILURE(state, failuredest, NULL, goto error);
1947 if (code<bufp->buffer || bufp->buffer+bufp->used < code) {
1948 silc_set_errno(SILC_ERR_OVERFLOW);
1952 goto continue_matching;
1956 a = (unsigned char)*code++;
1957 a |= (unsigned char)*code++ << 8;
1959 if (code+a<bufp->buffer || bufp->buffer+bufp->used < code+a) {
1960 silc_set_errno(SILC_ERR_OVERFLOW);
1964 PUSH_FAILURE(state, code + a, text, goto error);
1965 goto continue_matching;
1969 unsigned char *pinst;
1970 a = (unsigned char)*code++;
1971 a |= (unsigned char)*code++ << 8;
1974 if (pinst<bufp->buffer || bufp->buffer+bufp->used<pinst) {
1975 silc_set_errno(SILC_ERR_OVERFLOW);
1979 /* pinst is sole instruction in loop, and it matches a
1980 * single character. Since Crepeat1 was originally a
1981 * Cupdate_failure_jump, we also know that backtracking
1982 * is useless: so long as the single-character
1983 * expression matches, it must be used. Also, in the
1984 * case of +, we've already matched one character, so +
1985 * can't fail: nothing here can cause a failure. */
1992 while (text < textend)
1994 ch = translate[(unsigned char)*text];
1995 if (pinst[ch/8] & (1<<(ch & 7)))
2003 while (text < textend)
2005 ch = (unsigned char)*text;
2006 if (pinst[ch/8] & (1<<(ch & 7)))
2016 ch = (unsigned char)*pinst;
2019 while (text < textend &&
2020 translate[(unsigned char)*text] == ch)
2025 while (text < textend && (unsigned char)*text == ch)
2032 while (text < textend && (unsigned char)*text != '\n')
2038 a = (unsigned char)*pinst;
2041 while (text < textend &&
2042 (SYNTAX(translate[*text]) & a) )
2047 while (text < textend && (SYNTAX(*text) & a) )
2052 case Cnotsyntaxspec:
2054 a = (unsigned char)*pinst;
2057 while (text < textend &&
2058 !(SYNTAX(translate[*text]) & a) )
2063 while (text < textend && !(SYNTAX(*text) & a) )
2071 silc_set_errno(SILC_ERR_REGEX_OPCODE);
2076 /* due to the funky way + and * are compiled, the top
2077 * failure- stack entry at this point is actually a
2078 * success entry -- update it & pop it */
2079 UPDATE_FAILURE(state, text, goto error);
2080 goto fail; /* i.e., succeed <wink/sigh> */
2084 if (text == textstart)
2085 goto continue_matching;
2090 if (text == textend)
2091 goto continue_matching;
2096 if (text == textend)
2098 if (!(SYNTAX(*text) & Sword))
2100 if (text == textstart)
2101 goto continue_matching;
2102 if (!(SYNTAX(text[-1]) & Sword))
2103 goto continue_matching;
2108 if (text == textstart)
2110 if (!(SYNTAX(text[-1]) & Sword))
2112 if (text == textend)
2113 goto continue_matching;
2114 if (!(SYNTAX(*text) & Sword))
2115 goto continue_matching;
2120 /* Note: as in gnu regexp, this also matches at the
2121 * beginning and end of buffer. */
2123 if (text == textstart || text == textend)
2124 goto continue_matching;
2125 if ((SYNTAX(text[-1]) & Sword) ^ (SYNTAX(*text) & Sword))
2126 goto continue_matching;
2131 /* Note: as in gnu regexp, this never matches at the
2132 * beginning and end of buffer. */
2133 if (text == textstart || text == textend)
2135 if (!((SYNTAX(text[-1]) & Sword) ^ (SYNTAX(*text) & Sword)))
2136 goto continue_matching;
2142 if (!(SYNTAX(ch) & (unsigned char)*code++))
2144 goto continue_matching;
2146 case Cnotsyntaxspec:
2149 if (SYNTAX(ch) & (unsigned char)*code++)
2151 goto continue_matching;
2156 silc_set_errno(SILC_ERR_REGEX_OPCODE);
2162 /* Using "break;" in the above switch statement is equivalent to
2165 POP_FAILURE(state, code, text, goto done_matching, goto error);
2166 goto continue_matching;
2169 /* if(translated != NULL) */
2170 /* free(translated); */
2175 /* if (translated != NULL) */
2176 /* free(translated); */
2184 int re_search(SilcRegex bufp, unsigned char *string, int size, int pos,
2185 int range, regexp_registers_t regs, unsigned int flags)
2187 unsigned char *fastmap;
2188 unsigned char *translate;
2189 unsigned char *text;
2190 unsigned char *partstart;
2191 unsigned char *partend;
2194 unsigned char anchor;
2196 SILC_ASSERT(size >= 0 && pos >= 0);
2197 SILC_ASSERT(pos + range >= 0 && pos + range <= size); /* Bugfix by ylo */
2199 fastmap = bufp->fastmap;
2200 translate = bufp->translate;
2201 if (fastmap && !bufp->fastmap_accurate) {
2202 if (re_compile_fastmap(bufp))
2206 anchor = bufp->anchor;
2207 if (bufp->can_be_null == 1) /* can_be_null == 2: can match null at eob */
2225 for (; range >= 0; range--, pos += dir)
2230 { /* searching forwards */
2232 text = string + pos;
2233 partend = string + size;
2236 while (text != partend &&
2237 !fastmap[(unsigned char) translate[(unsigned char)*text]])
2240 while (text != partend && !fastmap[(unsigned char)*text])
2242 pos += text - partstart;
2243 range -= text - partstart;
2244 if (pos == size && bufp->can_be_null == 0)
2248 { /* searching backwards */
2249 text = string + pos;
2250 partstart = string + pos - range;
2253 while (text != partstart &&
2254 !fastmap[(unsigned char)
2255 translate[(unsigned char)*text]])
2258 while (text != partstart &&
2259 !fastmap[(unsigned char)*text])
2261 pos -= partend - text;
2262 range -= partend - text;
2266 { /* anchored to begline */
2267 if (pos > 0 && (string[pos - 1] != '\n'))
2270 SILC_ASSERT(pos >= 0 && pos <= size);
2271 ret = re_match(bufp, string, size, pos, regs, flags);
2280 /****************************** SILC Regex API ******************************/
2282 /* Compile regular expression */
2284 SilcBool silc_regex_compile(SilcRegex regexp, const char *regex,
2285 SilcRegexFlags flags)
2290 if (!regexp || !regex) {
2291 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
2295 memset(regexp, 0, sizeof(*regexp));
2297 /* Get global stack, if set, and create child stack. */
2298 regexp->rstack = silc_stack_get_global();
2300 regexp->rstack = silc_stack_alloc(512, regexp->rstack);
2303 syntax |= (RE_CONTEXT_INDEP_OPS | RE_NO_BK_PARENS |
2304 RE_NO_BK_VBAR | RE_REPEAT);
2305 re_set_syntax(syntax);
2308 ret = re_compile_pattern((char *)regex, strlen(regex), regexp);
2310 silc_set_errno(ret);
2312 return ret == SILC_OK;
2315 /* Match compiled regular expression */
2317 SilcBool silc_regex_match(SilcRegex regexp, const char *string,
2318 SilcUInt32 string_len, SilcUInt32 num_match,
2319 SilcRegexMatch match, SilcRegexFlags flags)
2321 struct re_registers regs;
2325 if (!regexp || !string) {
2326 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
2330 if (num_match && !match) {
2331 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
2335 /* Internal limit for maximum number of registers */
2336 if (num_match > RE_NREGS)
2337 num_match = RE_NREGS;
2340 if (flags & SILC_REGEX_NOTBOL)
2342 if (flags & SILC_REGEX_NOTEOL)
2346 ret = re_search(regexp, (char *)string, string_len, 0, string_len,
2347 num_match ? ®s : NULL, f);
2350 silc_set_errno(SILC_ERR_NOT_FOUND);
2354 /* Return matches */
2355 for (i = 0; i < num_match; i++) {
2356 match[i].start = regs.start[i];
2357 match[i].end = regs.end[i];
2366 void silc_regex_free(SilcRegex regexp)
2368 silc_sfree(regexp->rstack, regexp->buffer);
2369 silc_stack_free(regexp->rstack);
2374 SilcBool silc_regex_va(const char *string, SilcUInt32 string_len,
2375 const char *regex, SilcBuffer match, va_list va)
2377 SilcRegexStruct reg;
2378 SilcRegexMatch m = NULL;
2379 SilcBuffer buf, *rets = NULL;
2383 if (!silc_regex_compile(®, regex, 0))
2386 /* Get match pointers */
2388 rets = silc_malloc(sizeof(*rets));
2393 while ((buf = va_arg(va, SilcBuffer))) {
2394 rets = silc_realloc(rets, (c + 1) * sizeof(*rets));
2400 m = silc_malloc(c * sizeof(*m));
2408 if (!silc_regex_match(®, string, string_len, c, m, 0)) {
2414 /* Return matches */
2415 for (i = 0; i < c; i++) {
2416 if (m[i].start == -1)
2418 silc_buffer_set(rets[i], (unsigned char *)string + m[i].start,
2419 m[i].end - m[i].start);
2430 SilcBool silc_regex(const char *string, const char *regex,
2431 SilcBuffer match, ...)
2436 if (!string || !regex) {
2437 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
2442 va_start(va, match);
2444 ret = silc_regex_va(string, strlen(string), regex, match, va);
2454 SilcBool silc_regex_buffer(SilcBuffer buffer, const char *regex,
2455 SilcBuffer match, ...)
2460 if (!buffer || !regex) {
2461 silc_set_errno(SILC_ERR_INVALID_ARGUMENT);
2466 va_start(va, match);
2468 ret = silc_regex_va((const char *)silc_buffer_data(buffer),
2469 silc_buffer_len(buffer), regex, match, va);