From 54ec1c4fe81672ca66f327ef6ae170f458cd79e5 Mon Sep 17 00:00:00 2001 From: shyouhei Date: Wed, 15 Aug 2007 20:57:30 +0000 Subject: sorry. I made wrong tags. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_8_5_54@13009 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ruby_1_8_5/regex.c | 4648 ---------------------------------------------------- 1 file changed, 4648 deletions(-) delete mode 100644 ruby_1_8_5/regex.c (limited to 'ruby_1_8_5/regex.c') diff --git a/ruby_1_8_5/regex.c b/ruby_1_8_5/regex.c deleted file mode 100644 index ae0694b764..0000000000 --- a/ruby_1_8_5/regex.c +++ /dev/null @@ -1,4648 +0,0 @@ -/* Extended regular expression matching and search library. - Copyright (C) 1993, 94, 95, 96, 97, 98 Free Software Foundation, Inc. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file LGPL. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ -/* Multi-byte extension added May, 1993 by t^2 (Takahiro Tanimoto) - Last change: May 21, 1993 by t^2 */ -/* removed gapped buffer support, multiple syntax support by matz */ -/* Perl5 extension added by matz */ -/* UTF-8 extension added Jan 16 1999 by Yoshida Masato */ - -#include "config.h" - -#ifdef HAVE_STRING_H -# include -#else -# include -#endif - -/* We write fatal error messages on standard error. */ -#include - -/* isalpha(3) etc. are used for the character classes. */ -#include -#include - -#ifndef PARAMS -# if defined __GNUC__ || (defined __STDC__ && __STDC__) -# define PARAMS(args) args -# else -# define PARAMS(args) () -# endif /* GCC. */ -#endif /* Not PARAMS. */ - -#if defined(STDC_HEADERS) -# include -#else -/* We need this for `regex.h', and perhaps for the Emacs include files. */ -# include -#endif - -#if !defined(__STDC__) && !defined(_MSC_VER) -# define volatile -#endif - -#ifdef HAVE_PROTOTYPES -# define _(args) args -#else -# define _(args) () -#endif - -#ifdef RUBY_PLATFORM -#include "defines.h" - -# define RUBY -extern int rb_prohibit_interrupt; -extern int rb_trap_pending; -void rb_trap_exec _((void)); - -# define CHECK_INTS do {\ - if (!rb_prohibit_interrupt) {\ - if (rb_trap_pending) rb_trap_exec();\ - }\ -} while (0) -#endif - -/* Make alloca work the best possible way. */ -#ifdef __GNUC__ -# ifndef atarist -# ifndef alloca -# define alloca __builtin_alloca -# endif -# endif /* atarist */ -#else -# ifdef HAVE_ALLOCA_H -# include -# else -# ifdef _AIX - #pragma alloca -# else -# ifndef alloca /* predefined by HP cc +Olibcalls */ -void *alloca (); -# endif -# endif /* AIX */ -# endif /* HAVE_ALLOCA_H */ - -#endif /* __GNUC__ */ - -#ifdef HAVE_STRING_H -# include -#else -# include -#endif - -#ifdef C_ALLOCA -#define FREE_VARIABLES() alloca(0) -#else -#define FREE_VARIABLES() -#endif - -#define FREE_AND_RETURN_VOID(stackb) do { \ - FREE_VARIABLES(); \ - if (stackb != stacka) xfree(stackb); \ - return; \ -} while(0) - -#define FREE_AND_RETURN(stackb,val) do { \ - FREE_VARIABLES(); \ - if (stackb != stacka) xfree(stackb); \ - return(val); \ -} while(0) - -#define DOUBLE_STACK(type) do { \ - type *stackx; \ - unsigned int xlen = stacke - stackb; \ - if (stackb == stacka) { \ - stackx = (type*)xmalloc(2 * xlen * sizeof(type)); \ - memcpy(stackx, stackb, xlen * sizeof (type)); \ - } \ - else { \ - stackx = (type*)xrealloc(stackb, 2 * xlen * sizeof(type)); \ - } \ - /* Rearrange the pointers. */ \ - stackp = stackx + (stackp - stackb); \ - stackb = stackx; \ - stacke = stackb + 2 * xlen; \ -} while (0) - -#define RE_TALLOC(n,t) ((t*)alloca((n)*sizeof(t))) -#define TMALLOC(n,t) ((t*)xmalloc((n)*sizeof(t))) -#define TREALLOC(s,n,t) (s=((t*)xrealloc(s,(n)*sizeof(t)))) - -#define EXPAND_FAIL_STACK() DOUBLE_STACK(unsigned char*) -#define ENSURE_FAIL_STACK(n) \ - do { \ - if (stacke - stackp <= (n)) { \ - /* if (len > re_max_failures * MAX_NUM_FAILURE_ITEMS) \ - { \ - FREE_AND_RETURN(stackb,(-2)); \ - }*/ \ - \ - /* Roughly double the size of the stack. */ \ - EXPAND_FAIL_STACK(); \ - } \ - } while (0) - -/* Get the interface, including the syntax bits. */ -#include "regex.h" - -/* Subroutines for re_compile_pattern. */ -static void store_jump _((char*, int, char*)); -static void insert_jump _((int, char*, char*, char*)); -static void store_jump_n _((char*, int, char*, unsigned)); -static void insert_jump_n _((int, char*, char*, char*, unsigned)); -static void insert_op _((int, char*, char*)); -static void insert_op_2 _((int, char*, char*, int, int)); -static int memcmp_translate _((unsigned char*, unsigned char*, int)); - -/* Define the syntax stuff, so we can do the \<, \>, etc. */ - -/* This must be nonzero for the wordchar and notwordchar pattern - commands in re_match. */ -#define Sword 1 -#define Sword2 2 - -#define SYNTAX(c) re_syntax_table[c] - -static char re_syntax_table[256]; -static void init_syntax_once _((void)); -static const unsigned char *translate = 0; -static void init_regs _((struct re_registers*, unsigned int)); -static void bm_init_skip _((int *, unsigned char*, int, const unsigned char*)); -static int current_mbctype = MBCTYPE_ASCII; - -#undef P - -#ifdef RUBY -#include "util.h" -void rb_warn _((const char*, ...)); -# define re_warning(x) rb_warn(x) -#endif - -#ifndef re_warning -# define re_warning(x) -#endif - -static void -init_syntax_once() -{ - register int c; - static int done = 0; - - if (done) - return; - - memset(re_syntax_table, 0, sizeof re_syntax_table); - - for (c=0; c<=0x7f; c++) - if (isalnum(c)) - re_syntax_table[c] = Sword; - re_syntax_table['_'] = Sword; - - for (c=0x80; c<=0xff; c++) - if (isalnum(c)) - re_syntax_table[c] = Sword2; - done = 1; -} - -void -re_set_casetable(table) - const char *table; -{ - translate = (const unsigned char*)table; -} - -/* Jim Meyering writes: - - "... Some ctype macros are valid only for character codes that - isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when - using /bin/cc or gcc but without giving an ansi option). So, all - ctype uses should be through macros like ISPRINT... If - STDC_HEADERS is defined, then autoconf has verified that the ctype - macros don't need to be guarded with references to isascii. ... - Defining isascii to 1 should let any compiler worth its salt - eliminate the && through constant folding." - Solaris defines some of these symbols so we must undefine them first. */ - -#undef ISASCII -#if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII) -# define ISASCII(c) 1 -#else -# define ISASCII(c) isascii(c) -#endif - -#ifdef isblank -# define ISBLANK(c) (ISASCII(c) && isblank(c)) -#else -# define ISBLANK(c) ((c) == ' ' || (c) == '\t') -#endif -#ifdef isgraph -# define ISGRAPH(c) (ISASCII(c) && isgraph(c)) -#else -# define ISGRAPH(c) (ISASCII(c) && isprint(c) && !isspace(c)) -#endif - -#undef ISPRINT -#define ISPRINT(c) (ISASCII(c) && isprint(c)) -#define ISDIGIT(c) (ISASCII(c) && isdigit(c)) -#define ISALNUM(c) (ISASCII(c) && isalnum(c)) -#define ISALPHA(c) (ISASCII(c) && isalpha(c)) -#define ISCNTRL(c) (ISASCII(c) && iscntrl(c)) -#define ISLOWER(c) (ISASCII(c) && islower(c)) -#define ISPUNCT(c) (ISASCII(c) && ispunct(c)) -#define ISSPACE(c) (ISASCII(c) && isspace(c)) -#define ISUPPER(c) (ISASCII(c) && isupper(c)) -#define ISXDIGIT(c) (ISASCII(c) && isxdigit(c)) - -#ifndef NULL -# define NULL (void *)0 -#endif - -/* We remove any previous definition of `SIGN_EXTEND_CHAR', - since ours (we hope) works properly with all combinations of - machines, compilers, `char' and `unsigned char' argument types. - (Per Bothner suggested the basic approach.) */ -#undef SIGN_EXTEND_CHAR -#if __STDC__ -# define SIGN_EXTEND_CHAR(c) ((signed char)(c)) -#else /* not __STDC__ */ -/* As in Harbison and Steele. */ -# define SIGN_EXTEND_CHAR(c) ((((unsigned char)(c)) ^ 128) - 128) -#endif - -/* These are the command codes that appear in compiled regular - expressions, one per byte. Some command codes are followed by - argument bytes. A command code can specify any interpretation - whatsoever for its arguments. Zero-bytes may appear in the compiled - regular expression. - - The value of `exactn' is needed in search.c (search_buffer) in emacs. - So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of - `exactn' we use here must also be 1. */ - -enum regexpcode - { - unused=0, - exactn=1, /* Followed by one byte giving n, then by n literal bytes. */ - begline, /* Fail unless at beginning of line. */ - endline, /* Fail unless at end of line. */ - begbuf, /* Succeeds if at beginning of buffer (if emacs) or at beginning - of string to be matched (if not). */ - endbuf, /* Analogously, for end of buffer/string. */ - endbuf2, /* End of buffer/string, or newline just before it. */ - begpos, /* Matches where last scan//gsub left off. */ - jump, /* Followed by two bytes giving relative address to jump to. */ - jump_past_alt,/* Same as jump, but marks the end of an alternative. */ - on_failure_jump, /* Followed by two bytes giving relative address of - place to resume at in case of failure. */ - finalize_jump, /* Throw away latest failure point and then jump to - address. */ - maybe_finalize_jump, /* Like jump but finalize if safe to do so. - This is used to jump back to the beginning - of a repeat. If the command that follows - this jump is clearly incompatible with the - one at the beginning of the repeat, such that - we can be sure that there is no use backtracking - out of repetitions already completed, - then we finalize. */ - dummy_failure_jump, /* Jump, and push a dummy failure point. This - failure point will be thrown away if an attempt - is made to use it for a failure. A + construct - makes this before the first repeat. Also - use it as an intermediary kind of jump when - compiling an or construct. */ - push_dummy_failure, /* Push a dummy failure point and continue. Used at the end of - alternatives. */ - succeed_n, /* Used like on_failure_jump except has to succeed n times; - then gets turned into an on_failure_jump. The relative - address following it is useless until then. The - address is followed by two bytes containing n. */ - jump_n, /* Similar to jump, but jump n times only; also the relative - address following is in turn followed by yet two more bytes - containing n. */ - try_next, /* Jump to next pattern for the first time, - leaving this pattern on the failure stack. */ - finalize_push, /* Finalize stack and push the beginning of the pattern - on the stack to retry (used for non-greedy match) */ - finalize_push_n, /* Similar to finalize_push, buf finalize n time only */ - set_number_at, /* Set the following relative location to the - subsequent number. */ - anychar, /* Matches any (more or less) one character excluding newlines. */ - anychar_repeat, /* Matches sequence of characters excluding newlines. */ - charset, /* Matches any one char belonging to specified set. - First following byte is number of bitmap bytes. - Then come bytes for a bitmap saying which chars are in. - Bits in each byte are ordered low-bit-first. - A character is in the set if its bit is 1. - A character too large to have a bit in the map - is automatically not in the set. */ - charset_not, /* Same parameters as charset, but match any character - that is not one of those specified. */ - start_memory, /* Start remembering the text that is matched, for - storing in a memory register. Followed by one - byte containing the register number. Register numbers - must be in the range 0 through RE_NREGS. */ - stop_memory, /* Stop remembering the text that is matched - and store it in a memory register. Followed by - one byte containing the register number. Register - numbers must be in the range 0 through RE_NREGS. */ - start_paren, /* Place holder at the start of (?:..). */ - stop_paren, /* Place holder at the end of (?:..). */ - casefold_on, /* Turn on casefold flag. */ - casefold_off, /* Turn off casefold flag. */ - option_set, /* Turn on multi line match (match with newlines). */ - start_nowidth, /* Save string point to the stack. */ - stop_nowidth, /* Restore string place at the point start_nowidth. */ - pop_and_fail, /* Fail after popping nowidth entry from stack. */ - stop_backtrack, /* Restore backtrack stack at the point start_nowidth. */ - duplicate, /* Match a duplicate of something remembered. - Followed by one byte containing the index of the memory - register. */ - wordchar, /* Matches any word-constituent character. */ - notwordchar, /* Matches any char that is not a word-constituent. */ - wordbeg, /* Succeeds if at word beginning. */ - wordend, /* Succeeds if at word end. */ - wordbound, /* Succeeds if at a word boundary. */ - notwordbound /* Succeeds if not at a word boundary. */ - }; - - -/* Number of failure points to allocate space for initially, - when matching. If this number is exceeded, more space is allocated, - so it is not a hard limit. */ - -#ifndef NFAILURES -#define NFAILURES 160 -#endif - -/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ -#define STORE_NUMBER(destination, number) \ - do { (destination)[0] = (number) & 0377; \ - (destination)[1] = (number) >> 8; } while (0) - -/* Same as STORE_NUMBER, except increment the destination pointer to - the byte after where the number is stored. Watch out that values for - DESTINATION such as p + 1 won't work, whereas p will. */ -#define STORE_NUMBER_AND_INCR(destination, number) \ - do { STORE_NUMBER(destination, number); \ - (destination) += 2; } while (0) - - -/* Put into DESTINATION a number stored in two contingous bytes starting - at SOURCE. */ -#define EXTRACT_NUMBER(destination, source) \ - do { (destination) = *(source) & 0377; \ - (destination) += SIGN_EXTEND_CHAR(*(char*)((source) + 1)) << 8; } while (0) - -/* Same as EXTRACT_NUMBER, except increment the pointer for source to - point to second byte of SOURCE. Note that SOURCE has to be a value - such as p, not, e.g., p + 1. */ -#define EXTRACT_NUMBER_AND_INCR(destination, source) \ - do { EXTRACT_NUMBER(destination, source); \ - (source) += 2; } while (0) - - -/* Specify the precise syntax of regexps for compilation. This provides - for compatibility for various utilities which historically have - different, incompatible syntaxes. - - The argument SYNTAX is a bit-mask comprised of the various bits - defined in regex.h. */ - -long -re_set_syntax(syntax) - long syntax; -{ - /* obsolete */ - return 0; -} - -/* Macros for re_compile_pattern, which is found below these definitions. */ - -#define TRANSLATE_P() ((options&RE_OPTION_IGNORECASE) && translate) -#define MAY_TRANSLATE() ((bufp->options&(RE_OPTION_IGNORECASE|RE_MAY_IGNORECASE)) && translate) -/* Fetch the next character in the uncompiled pattern---translating it - if necessary. Also cast from a signed character in the constant - string passed to us by the user to an unsigned char that we can use - as an array index (in, e.g., `translate'). */ -#define PATFETCH(c) \ - do {if (p == pend) goto end_of_pattern; \ - c = (unsigned char) *p++; \ - if (TRANSLATE_P()) c = (unsigned char)translate[c]; \ - } while (0) - -/* Fetch the next character in the uncompiled pattern, with no - translation. */ -#define PATFETCH_RAW(c) \ - do {if (p == pend) goto end_of_pattern; \ - c = (unsigned char)*p++; \ - } while (0) - -/* Go backwards one character in the pattern. */ -#define PATUNFETCH p-- - -#define MBC2WC(c, p) \ - do { \ - if (current_mbctype == MBCTYPE_UTF8) { \ - int n = mbclen(c) - 1; \ - c &= (1<<(BYTEWIDTH-2-n)) - 1; \ - while (n--) { \ - c = c << 6 | (*p++ & ((1<<6)-1)); \ - } \ - } \ - else { \ - c <<= 8; \ - c |= (unsigned char)*(p)++; \ - } \ - } while (0) - -#define PATFETCH_MBC(c) \ - do { \ - if (p + mbclen(c) - 1 >= pend) goto end_of_pattern; \ - MBC2WC(c, p); \ - } while(0) - -#define WC2MBC1ST(c) \ - ((current_mbctype != MBCTYPE_UTF8) ? ((c<0x100) ? (c) : (((c)>>8)&0xff)) : utf8_firstbyte(c)) - -typedef unsigned int (*mbc_startpos_func_t) _((const char *string, unsigned int pos)); - -static unsigned int asc_startpos _((const char *string, unsigned int pos)); -static unsigned int euc_startpos _((const char *string, unsigned int pos)); -static unsigned int sjis_startpos _((const char *string, unsigned int pos)); -static unsigned int utf8_startpos _((const char *string, unsigned int pos)); - -static const mbc_startpos_func_t mbc_startpos_func[4] = { - asc_startpos, euc_startpos, sjis_startpos, utf8_startpos -}; - -#define mbc_startpos(start, pos) (*mbc_startpos_func[current_mbctype])((start), (pos)) - -static unsigned int -utf8_firstbyte(c) - unsigned long c; -{ - if (c < 0x80) return c; - if (c <= 0x7ff) return ((c>>6)&0xff)|0xc0; - if (c <= 0xffff) return ((c>>12)&0xff)|0xe0; - if (c <= 0x1fffff) return ((c>>18)&0xff)|0xf0; - if (c <= 0x3ffffff) return ((c>>24)&0xff)|0xf8; - if (c <= 0x7fffffff) return ((c>>30)&0xff)|0xfc; -#if SIZEOF_INT > 4 - if (c <= 0xfffffffff) return 0xfe; -#else - return 0xfe; -#endif -} - -static void -print_mbc(c) - unsigned int c; -{ - if (current_mbctype == MBCTYPE_UTF8) { - if (c < 0x80) - printf("%c", (int)c); - else if (c <= 0x7ff) - printf("%c%c", (int)utf8_firstbyte(c), (int)(c & 0x3f)); - else if (c <= 0xffff) - printf("%c%c%c", (int)utf8_firstbyte(c), (int)((c >> 6) & 0x3f), - (int)(c & 0x3f)); - else if (c <= 0x1fffff) - printf("%c%c%c%c", (int)utf8_firstbyte(c), (int)((c >> 12) & 0x3f), - (int)((c >> 6) & 0x3f), (int)(c & 0x3f)); - else if (c <= 0x3ffffff) - printf("%c%c%c%c%c", (int)utf8_firstbyte(c), (int)((c >> 18) & 0x3f), - (int)((c >> 12) & 0x3f), (int)((c >> 6) & 0x3f), (int)(c & 0x3f)); - else if (c <= 0x7fffffff) - printf("%c%c%c%c%c%c", (int)utf8_firstbyte(c), (int)((c >> 24) & 0x3f), - (int)((c >> 18) & 0x3f), (int)((c >> 12) & 0x3f), - (int)((c >> 6) & 0x3f), (int)(c & 0x3f)); - } - else if (c < 0xff) { - printf("\\%o", (int)c); - } - else { - printf("%c%c", (int)(c >> BYTEWIDTH), (int)(c &0xff)); - } -} - -/* If the buffer isn't allocated when it comes in, use this. */ -#define INIT_BUF_SIZE 28 - -/* Make sure we have at least N more bytes of space in buffer. */ -#define GET_BUFFER_SPACE(n) \ - do { \ - while (b - bufp->buffer + (n) >= bufp->allocated) \ - EXTEND_BUFFER; \ - } while (0) - -/* Make sure we have one more byte of buffer space and then add CH to it. */ -#define BUFPUSH(ch) \ - do { \ - GET_BUFFER_SPACE(1); \ - *b++ = (char)(ch); \ - } while (0) - -/* Extend the buffer by twice its current size via reallociation and - reset the pointers that pointed into the old allocation to point to - the correct places in the new allocation. If extending the buffer - results in it being larger than 1 << 16, then flag memory exhausted. */ -#define EXTEND_BUFFER \ - do { char *old_buffer = bufp->buffer; \ - if (bufp->allocated == (1L<<16)) goto too_big; \ - bufp->allocated *= 2; \ - if (bufp->allocated > (1L<<16)) bufp->allocated = (1L<<16); \ - bufp->buffer = (char*)xrealloc(bufp->buffer, bufp->allocated); \ - if (bufp->buffer == 0) \ - goto memory_exhausted; \ - b = (b - old_buffer) + bufp->buffer; \ - if (fixup_alt_jump) \ - fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer; \ - if (laststart) \ - laststart = (laststart - old_buffer) + bufp->buffer; \ - begalt = (begalt - old_buffer) + bufp->buffer; \ - if (pending_exact) \ - pending_exact = (pending_exact - old_buffer) + bufp->buffer; \ - } while (0) - - -/* Set the bit for character C in a character set list. */ -#define SET_LIST_BIT(c) \ - (b[(unsigned char)(c) / BYTEWIDTH] \ - |= 1 << ((unsigned char)(c) % BYTEWIDTH)) - -/* Get the next unsigned number in the uncompiled pattern. */ -#define GET_UNSIGNED_NUMBER(num) \ - do { if (p != pend) { \ - PATFETCH(c); \ - while (ISDIGIT(c)) { \ - if (num < 0) \ - num = 0; \ - num = num * 10 + c - '0'; \ - if (p == pend) \ - break; \ - PATFETCH(c); \ - } \ - } \ - } while (0) - -#define STREQ(s1, s2) ((strcmp(s1, s2) == 0)) - -#define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ - -#define IS_CHAR_CLASS(string) \ - (STREQ(string, "alpha") || STREQ(string, "upper") \ - || STREQ(string, "lower") || STREQ(string, "digit") \ - || STREQ(string, "alnum") || STREQ(string, "xdigit") \ - || STREQ(string, "space") || STREQ(string, "print") \ - || STREQ(string, "punct") || STREQ(string, "graph") \ - || STREQ(string, "cntrl") || STREQ(string, "blank")) - -#define STORE_MBC(p, c) \ - do { \ - (p)[0] = (unsigned char)(((c) >>24) & 0xff); \ - (p)[1] = (unsigned char)(((c) >>16) & 0xff); \ - (p)[2] = (unsigned char)(((c) >> 8) & 0xff); \ - (p)[3] = (unsigned char)(((c) >> 0) & 0xff); \ - } while (0) - -#define STORE_MBC_AND_INCR(p, c) \ - do { \ - *(p)++ = (unsigned char)(((c) >>24) & 0xff); \ - *(p)++ = (unsigned char)(((c) >>16) & 0xff); \ - *(p)++ = (unsigned char)(((c) >> 8) & 0xff); \ - *(p)++ = (unsigned char)(((c) >> 0) & 0xff); \ - } while (0) - -#define EXTRACT_MBC(p) \ - ((unsigned int)((unsigned char)(p)[0] << 24 | \ - (unsigned char)(p)[1] << 16 | \ - (unsigned char)(p)[2] << 8 | \ - (unsigned char)(p)[3])) - -#define EXTRACT_MBC_AND_INCR(p) \ - ((unsigned int)((p) += 4, \ - (unsigned char)(p)[-4] << 24 | \ - (unsigned char)(p)[-3] << 16 | \ - (unsigned char)(p)[-2] << 8 | \ - (unsigned char)(p)[-1])) - -#define EXTRACT_UNSIGNED(p) \ - ((unsigned char)(p)[0] | (unsigned char)(p)[1] << 8) -#define EXTRACT_UNSIGNED_AND_INCR(p) \ - ((p) += 2, (unsigned char)(p)[-2] | (unsigned char)(p)[-1] << 8) - -/* Handle (mb)?charset(_not)?. - - Structure of mbcharset(_not)? in compiled pattern. - - struct { - unsinged char id; mbcharset(_not)? - unsigned char sbc_size; - unsigned char sbc_map[sbc_size]; same as charset(_not)? up to here. - unsigned short mbc_size; number of intervals. - struct { - unsigned long beg; beginning of interval. - unsigned long end; end of interval. - } intervals[mbc_size]; - }; */ - -static void -set_list_bits(c1, c2, b) - unsigned long c1, c2; - unsigned char *b; -{ - unsigned char sbc_size = b[-1]; - unsigned short mbc_size = EXTRACT_UNSIGNED(&b[sbc_size]); - unsigned short beg, end, upb; - - if (c1 > c2) - return; - b = &b[sbc_size + 2]; - - for (beg = 0, upb = mbc_size; beg < upb; ) { - unsigned short mid = (unsigned short)(beg + upb) >> 1; - - if ((int)c1 - 1 > (int)EXTRACT_MBC(&b[mid*8+4])) - beg = mid + 1; - else - upb = mid; - } - - for (end = beg, upb = mbc_size; end < upb; ) { - unsigned short mid = (unsigned short)(end + upb) >> 1; - - if ((int)c2 >= (int)EXTRACT_MBC(&b[mid*8]) - 1) - end = mid + 1; - else - upb = mid; - } - - if (beg != end) { - if (c1 > EXTRACT_MBC(&b[beg*8])) - c1 = EXTRACT_MBC(&b[beg*8]); - if (c2 < EXTRACT_MBC(&b[(end - 1)*8+4])) - c2 = EXTRACT_MBC(&b[(end - 1)*8+4]); - } - if (end < mbc_size && end != beg + 1) - /* NOTE: memcpy() would not work here. */ - memmove(&b[(beg + 1)*8], &b[end*8], (mbc_size - end)*8); - STORE_MBC(&b[beg*8 + 0], c1); - STORE_MBC(&b[beg*8 + 4], c2); - mbc_size += beg - end + 1; - STORE_NUMBER(&b[-2], mbc_size); -} - -static int -is_in_list_sbc(c, b) - unsigned long c; - const unsigned char *b; -{ - unsigned short size; - - size = *b++; - return ((int)c / BYTEWIDTH < (int)size && b[c / BYTEWIDTH] & 1 << c % BYTEWIDTH); -} - -static int -is_in_list_mbc(c, b) - unsigned long c; - const unsigned char *b; -{ - unsigned short size; - unsigned short i, j; - - size = *b++; - b += size + 2; - size = EXTRACT_UNSIGNED(&b[-2]); - if (size == 0) return 0; - - for (i = 0, j = size; i < j; ) { - unsigned short k = (unsigned short)(i + j) >> 1; - - if (c > EXTRACT_MBC(&b[k*8+4])) - i = k + 1; - else - j = k; - } - if (i < size && EXTRACT_MBC(&b[i*8]) <= c) - return 1; - - return 0; -} - -static int -is_in_list(c, b) - unsigned long c; - const unsigned char *b; -{ - return is_in_list_sbc(c, b) || (current_mbctype ? is_in_list_mbc(c, b) : 0); -} - -static void -print_partial_compiled_pattern(start, end) - unsigned char *start; - unsigned char *end; -{ - int mcnt, mcnt2; - unsigned char *p = start; - unsigned char *pend = end; - - if (start == NULL) { - printf("(null)\n"); - return; - } - - /* Loop over pattern commands. */ - while (p < pend) { - switch ((enum regexpcode)*p++) { - case unused: - printf("/unused"); - break; - - case exactn: - mcnt = *p++; - printf("/exactn/%d", mcnt); - do { - putchar('/'); - printf("%c", *p++); - } - while (--mcnt); - break; - - case start_memory: - mcnt = *p++; - printf("/start_memory/%d/%d", mcnt, *p++); - break; - - case stop_memory: - mcnt = *p++; - printf("/stop_memory/%d/%d", mcnt, *p++); - break; - - case start_paren: - printf("/start_paren"); - break; - - case stop_paren: - printf("/stop_paren"); - break; - - case casefold_on: - printf("/casefold_on"); - break; - - case casefold_off: - printf("/casefold_off"); - break; - - case option_set: - printf("/option_set/%d", *p++); - break; - - case start_nowidth: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - printf("/start_nowidth//%d", mcnt); - break; - - case stop_nowidth: - printf("/stop_nowidth//"); - p += 2; - break; - - case pop_and_fail: - printf("/pop_and_fail"); - break; - - case stop_backtrack: - printf("/stop_backtrack//"); - p += 2; - break; - - case duplicate: - printf("/duplicate/%d", *p++); - break; - - case anychar: - printf("/anychar"); - break; - - case anychar_repeat: - printf("/anychar_repeat"); - break; - - case charset: - case charset_not: - { - register int c; - - printf("/charset%s", - (enum regexpcode)*(p - 1) == charset_not ? "_not" : ""); - - mcnt = *p++; - printf("/%d", mcnt); - for (c = 0; c < mcnt; c++) { - unsigned bit; - unsigned char map_byte = p[c]; - - putchar('/'); - - for (bit = 0; bit < BYTEWIDTH; bit++) - if (map_byte & (1 << bit)) - printf("%c", c * BYTEWIDTH + bit); - } - p += mcnt; - mcnt = EXTRACT_UNSIGNED_AND_INCR(p); - putchar('/'); - while (mcnt--) { - print_mbc(EXTRACT_MBC_AND_INCR(p)); - putchar('-'); - print_mbc(EXTRACT_MBC_AND_INCR(p)); - } - break; - } - - case begline: - printf("/begline"); - break; - - case endline: - printf("/endline"); - break; - - case on_failure_jump: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - printf("/on_failure_jump//%d", mcnt); - break; - - case dummy_failure_jump: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - printf("/dummy_failure_jump//%d", mcnt); - break; - - case push_dummy_failure: - printf("/push_dummy_failure"); - break; - - case finalize_jump: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - printf("/finalize_jump//%d", mcnt); - break; - - case maybe_finalize_jump: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - printf("/maybe_finalize_jump//%d", mcnt); - break; - - case jump_past_alt: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - printf("/jump_past_alt//%d", mcnt); - break; - - case jump: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - printf("/jump//%d", mcnt); - break; - - case succeed_n: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - EXTRACT_NUMBER_AND_INCR(mcnt2, p); - printf("/succeed_n//%d//%d", mcnt, mcnt2); - break; - - case jump_n: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - EXTRACT_NUMBER_AND_INCR(mcnt2, p); - printf("/jump_n//%d//%d", mcnt, mcnt2); - break; - - case set_number_at: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - EXTRACT_NUMBER_AND_INCR(mcnt2, p); - printf("/set_number_at//%d//%d", mcnt, mcnt2); - break; - - case try_next: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - printf("/try_next//%d", mcnt); - break; - - case finalize_push: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - printf("/finalize_push//%d", mcnt); - break; - - case finalize_push_n: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - EXTRACT_NUMBER_AND_INCR(mcnt2, p); - printf("/finalize_push_n//%d//%d", mcnt, mcnt2); - break; - - case wordbound: - printf("/wordbound"); - break; - - case notwordbound: - printf("/notwordbound"); - break; - - case wordbeg: - printf("/wordbeg"); - break; - - case wordend: - printf("/wordend"); - - case wordchar: - printf("/wordchar"); - break; - - case notwordchar: - printf("/notwordchar"); - break; - - case begbuf: - printf("/begbuf"); - break; - - case endbuf: - printf("/endbuf"); - break; - - case endbuf2: - printf("/endbuf2"); - break; - - case begpos: - printf("/begpos"); - break; - - default: - printf("?%d", *(p-1)); - } - } - printf("/\n"); -} - - -static void -print_compiled_pattern(bufp) - struct re_pattern_buffer *bufp; -{ - unsigned char *buffer = (unsigned char*)bufp->buffer; - - print_partial_compiled_pattern(buffer, buffer + bufp->used); -} - -static char* -calculate_must_string(start, end) - char *start; - char *end; -{ - int mcnt; - int max = 0; - unsigned char *p = start; - unsigned char *pend = end; - char *must = 0; - - if (start == NULL) return 0; - - /* Loop over pattern commands. */ - while (p < pend) { - switch ((enum regexpcode)*p++) { - case unused: - break; - - case exactn: - mcnt = *p; - if (mcnt > max) { - must = p; - max = mcnt; - } - p += mcnt+1; - break; - - case start_memory: - case stop_memory: - p += 2; - break; - - case duplicate: - case option_set: - p++; - break; - - case casefold_on: - case casefold_off: - return 0; /* should not check must_string */ - - case pop_and_fail: - case anychar: - case anychar_repeat: - case begline: - case endline: - case wordbound: - case notwordbound: - case wordbeg: - case wordend: - case wordchar: - case notwordchar: - case begbuf: - case endbuf: - case endbuf2: - case begpos: - case push_dummy_failure: - case start_paren: - case stop_paren: - break; - - case charset: - case charset_not: - mcnt = *p++; - p += mcnt; - mcnt = EXTRACT_UNSIGNED_AND_INCR(p); - while (mcnt--) { - p += 8; - } - break; - - case on_failure_jump: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - if (mcnt > 0) p += mcnt; - if ((enum regexpcode)p[-3] == jump) { - p -= 2; - EXTRACT_NUMBER_AND_INCR(mcnt, p); - if (mcnt > 0) p += mcnt; - } - break; - - case dummy_failure_jump: - case succeed_n: - case try_next: - case jump: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - if (mcnt > 0) p += mcnt; - break; - - case start_nowidth: - case stop_nowidth: - case stop_backtrack: - case finalize_jump: - case maybe_finalize_jump: - case finalize_push: - p += 2; - break; - - case jump_n: - case set_number_at: - case finalize_push_n: - p += 4; - break; - - default: - break; - } - } - return must; -} - -static unsigned int -read_backslash(c) - int c; -{ - switch (c) { - case 'n': - return '\n'; - - case 't': - return '\t'; - - case 'r': - return '\r'; - - case 'f': - return '\f'; - - case 'v': - return '\v'; - - case 'a': - return '\007'; - - case 'b': - return '\010'; - - case 'e': - return '\033'; - } - return c; -} - -static unsigned int -read_special(p, pend, pp) - const char *p, *pend, **pp; -{ - int c; - - PATFETCH_RAW(c); - switch (c) { - case 'M': - PATFETCH_RAW(c); - if (c != '-') return -1; - PATFETCH_RAW(c); - *pp = p; - if (c == '\\') { - return read_special(--p, pend, pp) | 0x80; - } - else if (c == -1) return ~0; - else { - return ((c & 0xff) | 0x80); - } - - case 'C': - PATFETCH_RAW(c); - if (c != '-') return ~0; - case 'c': - PATFETCH_RAW(c); - *pp = p; - if (c == '\\') { - c = read_special(--p, pend, pp); - } - else if (c == '?') return 0177; - else if (c == -1) return ~0; - return c & 0x9f; - default: - *pp = p + 1; - return read_backslash(c); - } - - end_of_pattern: - return ~0; -} - -/* re_compile_pattern takes a regular-expression string - and converts it into a buffer full of byte commands for matching. - - PATTERN is the address of the pattern string - SIZE is the length of it. - BUFP is a struct re_pattern_buffer * which points to the info - on where to store the byte commands. - This structure contains a char * which points to the - actual space, which should have been obtained with malloc. - re_compile_pattern may use realloc to grow the buffer space. - - The number of bytes of commands can be found out by looking in - the `struct re_pattern_buffer' that bufp pointed to, after - re_compile_pattern returns. */ - -char * -re_compile_pattern(pattern, size, bufp) - const char *pattern; - int size; - struct re_pattern_buffer *bufp; -{ - register char *b = bufp->buffer; - register const char *p = pattern; - const char *nextp; - const char *pend = pattern + size; - register unsigned int c, c1 = 0; - const char *p0; - int numlen; -#define ERROR_MSG_MAX_SIZE 200 - static char error_msg[ERROR_MSG_MAX_SIZE+1]; - - /* Address of the count-byte of the most recently inserted `exactn' - command. This makes it possible to tell whether a new exact-match - character can be added to that command or requires a new `exactn' - command. */ - - char *pending_exact = 0; - - /* Address of the place where a forward-jump should go to the end of - the containing expression. Each alternative of an `or', except the - last, ends with a forward-jump of this sort. */ - - char *fixup_alt_jump = 0; - - /* Address of start of the most recently finished expression. - This tells postfix * where to find the start of its operand. */ - - char *laststart = 0; - - /* In processing a repeat, 1 means zero matches is allowed. */ - - char zero_times_ok; - - /* In processing a repeat, 1 means many matches is allowed. */ - - char many_times_ok; - - /* In processing a repeat, 1 means non-greedy matches. */ - - char greedy; - - /* Address of beginning of regexp, or inside of last (. */ - - char *begalt = b; - - /* Place in the uncompiled pattern (i.e., the {) to - which to go back if the interval is invalid. */ - const char *beg_interval; - - /* In processing an interval, at least this many matches must be made. */ - int lower_bound; - - /* In processing an interval, at most this many matches can be made. */ - int upper_bound; - - /* Stack of information saved by ( and restored by ). - Five stack elements are pushed by each (: - First, the value of b. - Second, the value of fixup_alt_jump. - Third, the value of begalt. - Fourth, the value of regnum. - Fifth, the type of the paren. */ - - int stacka[40]; - int *stackb = stacka; - int *stackp = stackb; - int *stacke = stackb + 40; - - /* Counts ('s as they are encountered. Remembered for the matching ), - where it becomes the register number to put in the stop_memory - command. */ - - int regnum = 1; - - int range = 0; - int had_mbchar = 0; - int had_num_literal = 0; - int had_char_class = 0; - - int options = bufp->options; - - bufp->fastmap_accurate = 0; - bufp->must = 0; - bufp->must_skip = 0; - - /* Initialize the syntax table. */ - init_syntax_once(); - - if (bufp->allocated == 0) { - bufp->allocated = INIT_BUF_SIZE; - /* EXTEND_BUFFER loses when bufp->allocated is 0. */ - bufp->buffer = (char*)xrealloc(bufp->buffer, INIT_BUF_SIZE); - if (!bufp->buffer) goto memory_exhausted; /* this not happen */ - begalt = b = bufp->buffer; - } - - while (p != pend) { - PATFETCH(c); - - switch (c) { - case '$': - if (bufp->options & RE_OPTION_SINGLELINE) { - BUFPUSH(endbuf); - } - else { - p0 = p; - /* When testing what follows the $, - look past the \-constructs that don't consume anything. */ - - while (p0 != pend) { - if (*p0 == '\\' && p0 + 1 != pend - && (p0[1] == 'b' || p0[1] == 'B')) - p0 += 2; - else - break; - } - BUFPUSH(endline); - } - break; - - case '^': - if (bufp->options & RE_OPTION_SINGLELINE) - BUFPUSH(begbuf); - else - BUFPUSH(begline); - break; - - case '+': - case '?': - case '*': - /* If there is no previous pattern, char not special. */ - if (!laststart) { - snprintf(error_msg, ERROR_MSG_MAX_SIZE, - "invalid regular expression; there's no previous pattern, to which '%c' would define cardinality at %d", - c, p-pattern); - FREE_AND_RETURN(stackb, error_msg); - } - /* If there is a sequence of repetition chars, - collapse it down to just one. */ - zero_times_ok = c != '+'; - many_times_ok = c != '?'; - greedy = 1; - if (p != pend) { - PATFETCH(c); - switch (c) { - case '?': - greedy = 0; - break; - case '*': - case '+': - goto nested_meta; - default: - PATUNFETCH; - break; - } - } - - repeat: - /* Star, etc. applied to an empty pattern is equivalent - to an empty pattern. */ - if (!laststart) - break; - - if (greedy && many_times_ok && *laststart == anychar && b - laststart <= 2) { - if (b[-1] == stop_paren) - b--; - if (zero_times_ok) - *laststart = anychar_repeat; - else { - BUFPUSH(anychar_repeat); - } - break; - } - /* Now we know whether or not zero matches is allowed - and also whether or not two or more matches is allowed. */ - if (many_times_ok) { - /* If more than one repetition is allowed, put in at the - end a backward relative jump from b to before the next - jump we're going to put in below (which jumps from - laststart to after this jump). */ - GET_BUFFER_SPACE(3); - store_jump(b,greedy?maybe_finalize_jump:finalize_push,laststart-3); - b += 3; /* Because store_jump put stuff here. */ - } - - /* On failure, jump from laststart to next pattern, which will be the - end of the buffer after this jump is inserted. */ - GET_BUFFER_SPACE(3); - insert_jump(on_failure_jump, laststart, b + 3, b); - b += 3; - - if (zero_times_ok) { - if (greedy == 0) { - GET_BUFFER_SPACE(3); - insert_jump(try_next, laststart, b + 3, b); - b += 3; - } - } - else { - /* At least one repetition is required, so insert a - `dummy_failure_jump' before the initial - `on_failure_jump' instruction of the loop. This - effects a skip over that instruction the first time - we hit that loop. */ - GET_BUFFER_SPACE(3); - insert_jump(dummy_failure_jump, laststart, laststart + 6, b); - b += 3; - } - break; - - case '.': - laststart = b; - BUFPUSH(anychar); - break; - - case '[': - if (p == pend) - FREE_AND_RETURN(stackb, "invalid regular expression; '[' can't be the last character ie. can't start range at the end of pattern"); - while ((b - bufp->buffer + 9 + (1 << BYTEWIDTH) / BYTEWIDTH) - > bufp->allocated) - EXTEND_BUFFER; - - laststart = b; - if (*p == '^') { - BUFPUSH(charset_not); - p++; - } - else - BUFPUSH(charset); - p0 = p; - - BUFPUSH((1 << BYTEWIDTH) / BYTEWIDTH); - /* Clear the whole map */ - memset(b, 0, (1 << BYTEWIDTH) / BYTEWIDTH + 2); - - had_mbchar = 0; - had_num_literal = 0; - had_char_class = 0; - - /* Read in characters and ranges, setting map bits. */ - for (;;) { - int size; - unsigned last = (unsigned)-1; - - if ((size = EXTRACT_UNSIGNED(&b[(1 << BYTEWIDTH) / BYTEWIDTH])) || current_mbctype) { - /* Ensure the space is enough to hold another interval - of multi-byte chars in charset(_not)?. */ - size = (1 << BYTEWIDTH) / BYTEWIDTH + 2 + size*8 + 8; - while (b + size + 1 > bufp->buffer + bufp->allocated) - EXTEND_BUFFER; - } - range_retry: - if (range && had_char_class) { - FREE_AND_RETURN(stackb, "invalid regular expression; can't use character class as an end value of range"); - } - PATFETCH_RAW(c); - - if (c == ']') { - if (p == p0 + 1) { - if (p == pend) - FREE_AND_RETURN(stackb, "invalid regular expression; empty character class"); - re_warning("character class has `]' without escape"); - } - else - /* Stop if this isn't merely a ] inside a bracket - expression, but rather the end of a bracket - expression. */ - break; - } - /* Look ahead to see if it's a range when the last thing - was a character class. */ - if (had_char_class && c == '-' && *p != ']') - FREE_AND_RETURN(stackb, "invalid regular expression; can't use character class as a start value of range"); - if (ismbchar(c)) { - PATFETCH_MBC(c); - had_mbchar++; - } - had_char_class = 0; - - if (c == '-' && ((p != p0 + 1 && *p != ']') || - (p[0] == '-' && p[1] != ']') || - range)) - re_warning("character class has `-' without escape"); - if (c == '[' && *p != ':') - re_warning("character class has `[' without escape"); - - /* \ escapes characters when inside [...]. */ - if (c == '\\') { - PATFETCH_RAW(c); - switch (c) { - case 'w': - for (c = 0; c < (1 << BYTEWIDTH); c++) { - if (SYNTAX(c) == Sword || - (!current_mbctype && SYNTAX(c) == Sword2)) - SET_LIST_BIT(c); - } - if (current_mbctype) { - set_list_bits(0x80, 0xffffffff, b); - } - had_char_class = 1; - last = -1; - continue; - - case 'W': - for (c = 0; c < (1 << BYTEWIDTH); c++) { - if (SYNTAX(c) != Sword && - ((current_mbctype && !re_mbctab[c]) || - (!current_mbctype && SYNTAX(c) != Sword2))) - SET_LIST_BIT(c); - } - had_char_class = 1; - last = -1; - continue; - - case 's': - for (c = 0; c < 256; c++) - if (ISSPACE(c)) - SET_LIST_BIT(c); - had_char_class = 1; - last = -1; - continue; - - case 'S': - for (c = 0; c < 256; c++) - if (!ISSPACE(c)) - SET_LIST_BIT(c); - if (current_mbctype) - set_list_bits(0x80, 0xffffffff, b); - had_char_class = 1; - last = -1; - continue; - - case 'd': - for (c = '0'; c <= '9'; c++) - SET_LIST_BIT(c); - had_char_class = 1; - last = -1; - continue; - - case 'D': - for (c = 0; c < 256; c++) - if (!ISDIGIT(c)) - SET_LIST_BIT(c); - if (current_mbctype) - set_list_bits(0x80, 0xffffffff, b); - had_char_class = 1; - last = -1; - continue; - - case 'x': - c = scan_hex(p, 2, &numlen); - if (numlen == 0) goto invalid_escape; - p += numlen; - had_num_literal = 1; - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - PATUNFETCH; - c = scan_oct(p, 3, &numlen); - p += numlen; - had_num_literal = 1; - break; - - case 'M': - case 'C': - case 'c': - { - const char *pp; - - --p; - c = read_special(p, pend, &pp); - if (c > 255) goto invalid_escape; - p = pp; - had_num_literal = 1; - } - break; - - default: - c = read_backslash(c); - if (ismbchar(c)) { - PATFETCH_MBC(c); - had_mbchar++; - } - break; - } - } - else if (c == '[' && *p == ':') { /* [:...:] */ - /* Leave room for the null. */ - char str[CHAR_CLASS_MAX_LENGTH + 1]; - - PATFETCH_RAW(c); - c1 = 0; - - /* If pattern is `[[:'. */ - if (p == pend) - FREE_AND_RETURN(stackb, "invalid regular expression; re can't end '[[:'"); - - for (;;) { - PATFETCH_RAW(c); - if (c == ':' || c == ']' || p == pend - || c1 == CHAR_CLASS_MAX_LENGTH) - break; - str[c1++] = c; - } - str[c1] = '\0'; - - /* If isn't a word bracketed by `[:' and `:]': - undo the ending character, the letters, and - the leading `:' and `['. */ - if (c == ':' && *p == ']') { - int ch; - char is_alnum = STREQ(str, "alnum"); - char is_alpha = STREQ(str, "alpha"); - char is_blank = STREQ(str, "blank"); - char is_cntrl = STREQ(str, "cntrl"); - char is_digit = STREQ(str, "digit"); - char is_graph = STREQ(str, "graph"); - char is_lower = STREQ(str, "lower"); - char is_print = STREQ(str, "print"); - char is_punct = STREQ(str, "punct"); - char is_space = STREQ(str, "space"); - char is_upper = STREQ(str, "upper"); - char is_xdigit = STREQ(str, "xdigit"); - - if (!IS_CHAR_CLASS(str)){ - snprintf(error_msg, ERROR_MSG_MAX_SIZE, - "invalid regular expression; [:%s:] is not a character class", str); - FREE_AND_RETURN(stackb, error_msg); - } - - /* Throw away the ] at the end of the character class. */ - PATFETCH(c); - - if (p == pend) - FREE_AND_RETURN(stackb, "invalid regular expression; range doesn't have ending ']' after a character class"); - - for (ch = 0; ch < 1 << BYTEWIDTH; ch++) { - if ( (is_alnum && ISALNUM(ch)) - || (is_alpha && ISALPHA(ch)) - || (is_blank && ISBLANK(ch)) - || (is_cntrl && ISCNTRL(ch)) - || (is_digit && ISDIGIT(ch)) - || (is_graph && ISGRAPH(ch)) - || (is_lower && ISLOWER(ch)) - || (is_print && ISPRINT(ch)) - || (is_punct && ISPUNCT(ch)) - || (is_space && ISSPACE(ch)) - || (is_upper && ISUPPER(ch)) - || (is_xdigit && ISXDIGIT(ch))) - SET_LIST_BIT(ch); - } - had_char_class = 1; - continue; - } - else { - c1 += 2; - while (c1--) - PATUNFETCH; - re_warning("character class has `[' without escape"); - c = '['; - } - } - - /* Get a range. */ - if (range) { - if (last > c) - goto invalid_pattern; - - range = 0; - if (had_mbchar == 0) { - if (TRANSLATE_P()) { - for (;last<=c;last++) - SET_LIST_BIT(translate[last]); - } - else { - for (;last<=c;last++) - SET_LIST_BIT(last); - } - } - else if (had_mbchar == 2) { - set_list_bits(last, c, b); - } - else { - /* restriction: range between sbc and mbc */ - goto invalid_pattern; - } - } - else if (p[0] == '-' && p[1] != ']') { - last = c; - PATFETCH_RAW(c1); - range = 1; - goto range_retry; - } - else { - if (TRANSLATE_P() && c < 0x100) c = (unsigned char)translate[c]; - if (had_mbchar == 0 && (!current_mbctype || !had_num_literal)) { - SET_LIST_BIT(c); - had_num_literal = 0; - } - else { - set_list_bits(c, c, b); - } - } - had_mbchar = 0; - } - - /* Discard any character set/class bitmap bytes that are all - 0 at the end of the map. Decrement the map-length byte too. */ - while ((int)b[-1] > 0 && b[b[-1] - 1] == 0) - b[-1]--; - if (b[-1] != (1 << BYTEWIDTH) / BYTEWIDTH) - memmove(&b[(unsigned char)b[-1]], &b[(1 << BYTEWIDTH) / BYTEWIDTH], - 2 + EXTRACT_UNSIGNED(&b[(1 << BYTEWIDTH) / BYTEWIDTH])*8); - b += b[-1] + 2 + EXTRACT_UNSIGNED(&b[(unsigned char)b[-1]])*8; - had_num_literal = 0; - break; - - case '(': - { - int old_options = options; - int push_option = 0; - int casefold = 0; - - PATFETCH(c); - if (c == '?') { - int negative = 0; - - PATFETCH_RAW(c); - switch (c) { - case 'x': case 'm': case 'i': case '-': - for (;;) { - switch (c) { - case '-': - negative = 1; - break; - - case ':': - case ')': - break; - - case 'x': - if (negative) - options &= ~RE_OPTION_EXTENDED; - else - options |= RE_OPTION_EXTENDED; - break; - - case 'm': - if (negative) { - if (options&RE_OPTION_MULTILINE) { - options &= ~RE_OPTION_MULTILINE; - } - } - else if (!(options&RE_OPTION_MULTILINE)) { - options |= RE_OPTION_MULTILINE; - } - push_option = 1; - break; - - case 'i': - if (negative) { - if (options&RE_OPTION_IGNORECASE) { - options &= ~RE_OPTION_IGNORECASE; - } - } - else if (!(options&RE_OPTION_IGNORECASE)) { - options |= RE_OPTION_IGNORECASE; - } - casefold = 1; - break; - - default: - FREE_AND_RETURN(stackb, "undefined (?...) inline option"); - } - if (c == ')') { - c = '#'; /* read whole in-line options */ - break; - } - if (c == ':') break; - PATFETCH_RAW(c); - } - break; - - case '#': - for (;;) { - PATFETCH(c); - if (c == ')') break; - } - c = '#'; - break; - - case ':': - case '=': - case '!': - case '>': - break; - - default: - FREE_AND_RETURN(stackb, "undefined (?...) sequence"); - } - } - else { - PATUNFETCH; - c = '('; - } - if (c == '#') { - if (push_option) { - BUFPUSH(option_set); - BUFPUSH(options); - } - if (casefold) { - if (options & RE_OPTION_IGNORECASE) - BUFPUSH(casefold_on); - else - BUFPUSH(casefold_off); - } - break; - } - if (stackp+8 >= stacke) { - DOUBLE_STACK(int); - } - - /* Laststart should point to the start_memory that we are about - to push (unless the pattern has RE_NREGS or more ('s). */ - /* obsolete: now RE_NREGS is just a default register size. */ - *stackp++ = b - bufp->buffer; - *stackp++ = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0; - *stackp++ = begalt - bufp->buffer; - switch (c) { - case '(': - BUFPUSH(start_memory); - BUFPUSH(regnum); - *stackp++ = regnum++; - *stackp++ = b - bufp->buffer; - BUFPUSH(0); - /* too many ()'s to fit in a byte. (max 254) */ - if (regnum >= RE_REG_MAX) goto too_big; - break; - - case '=': - case '!': - case '>': - BUFPUSH(start_nowidth); - *stackp++ = b - bufp->buffer; - BUFPUSH(0); /* temporary value */ - BUFPUSH(0); - if (c != '!') break; - - BUFPUSH(on_failure_jump); - *stackp++ = b - bufp->buffer; - BUFPUSH(0); /* temporary value */ - BUFPUSH(0); - break; - - case ':': - BUFPUSH(start_paren); - pending_exact = 0; - default: - break; - } - if (push_option) { - BUFPUSH(option_set); - BUFPUSH(options); - } - if (casefold) { - if (options & RE_OPTION_IGNORECASE) - BUFPUSH(casefold_on); - else - BUFPUSH(casefold_off); - } - *stackp++ = c; - *stackp++ = old_options; - fixup_alt_jump = 0; - laststart = 0; - begalt = b; - } - break; - - case ')': - if (stackp == stackb) - FREE_AND_RETURN(stackb, "unmatched )"); - - pending_exact = 0; - if (fixup_alt_jump) { - /* Push a dummy failure point at the end of the - alternative for a possible future - `finalize_jump' to pop. See comments at - `push_dummy_failure' in `re_match'. */ - BUFPUSH(push_dummy_failure); - - /* We allocated space for this jump when we assigned - to `fixup_alt_jump', in the `handle_alt' case below. */ - store_jump(fixup_alt_jump, jump, b); - } - if (options != stackp[-1]) { - if ((options ^ stackp[-1]) & RE_OPTION_IGNORECASE) { - BUFPUSH((options&RE_OPTION_IGNORECASE)?casefold_off:casefold_on); - } - if ((options ^ stackp[-1]) != RE_OPTION_IGNORECASE) { - BUFPUSH(option_set); - BUFPUSH(stackp[-1]); - } - } - p0 = b; - options = *--stackp; - switch (c = *--stackp) { - case '(': - { - char *loc = bufp->buffer + *--stackp; - *loc = regnum - stackp[-1]; - BUFPUSH(stop_memory); - BUFPUSH(stackp[-1]); - BUFPUSH(regnum - stackp[-1]); - stackp--; - } - break; - - case '!': - BUFPUSH(pop_and_fail); - /* back patch */ - STORE_NUMBER(bufp->buffer+stackp[-1], b - bufp->buffer - stackp[-1] - 2); - stackp--; - /* fall through */ - case '=': - BUFPUSH(stop_nowidth); - /* tell stack-pos place to start_nowidth */ - STORE_NUMBER(bufp->buffer+stackp[-1], b - bufp->buffer - stackp[-1] - 2); - BUFPUSH(0); /* space to hold stack pos */ - BUFPUSH(0); - stackp--; - break; - - case '>': - BUFPUSH(stop_backtrack); - /* tell stack-pos place to start_nowidth */ - STORE_NUMBER(bufp->buffer+stackp[-1], b - bufp->buffer - stackp[-1] - 2); - BUFPUSH(0); /* space to hold stack pos */ - BUFPUSH(0); - stackp--; - break; - - case ':': - BUFPUSH(stop_paren); - break; - - default: - break; - } - begalt = *--stackp + bufp->buffer; - stackp--; - fixup_alt_jump = *stackp ? *stackp + bufp->buffer - 1 : 0; - laststart = *--stackp + bufp->buffer; - if (c == '!' || c == '=') laststart = b; - break; - - case '|': - /* Insert before the previous alternative a jump which - jumps to this alternative if the former fails. */ - GET_BUFFER_SPACE(3); - insert_jump(on_failure_jump, begalt, b + 6, b); - pending_exact = 0; - b += 3; - /* The alternative before this one has a jump after it - which gets executed if it gets matched. Adjust that - jump so it will jump to this alternative's analogous - jump (put in below, which in turn will jump to the next - (if any) alternative's such jump, etc.). The last such - jump jumps to the correct final destination. A picture: - _____ _____ - | | | | - | v | v - a | b | c - - If we are at `b', then fixup_alt_jump right now points to a - three-byte space after `a'. We'll put in the jump, set - fixup_alt_jump to right after `b', and leave behind three - bytes which we'll fill in when we get to after `c'. */ - - if (fixup_alt_jump) - store_jump(fixup_alt_jump, jump_past_alt, b); - - /* Mark and leave space for a jump after this alternative, - to be filled in later either by next alternative or - when know we're at the end of a series of alternatives. */ - fixup_alt_jump = b; - GET_BUFFER_SPACE(3); - b += 3; - - laststart = 0; - begalt = b; - break; - - case '{': - /* If there is no previous pattern, this is an invalid pattern. */ - if (!laststart) { - snprintf(error_msg, ERROR_MSG_MAX_SIZE, - "invalid regular expression; there's no previous pattern, to which '{' would define cardinality at %d", - p-pattern); - FREE_AND_RETURN(stackb, error_msg); - } - if( p == pend) - FREE_AND_RETURN(stackb, "invalid regular expression; '{' can't be last character" ); - - beg_interval = p - 1; - - lower_bound = -1; /* So can see if are set. */ - upper_bound = -1; - GET_UNSIGNED_NUMBER(lower_bound); - if (c == ',') { - GET_UNSIGNED_NUMBER(upper_bound); - } - else - /* Interval such as `{1}' => match exactly once. */ - upper_bound = lower_bound; - - if (lower_bound < 0 || c != '}') - goto unfetch_interval; - - if (lower_bound >= RE_DUP_MAX || upper_bound >= RE_DUP_MAX) - FREE_AND_RETURN(stackb, "too big quantifier in {,}"); - if (upper_bound < 0) upper_bound = RE_DUP_MAX; - if (lower_bound > upper_bound) - FREE_AND_RETURN(stackb, "can't do {n,m} with n > m"); - - beg_interval = 0; - pending_exact = 0; - - greedy = 1; - if (p != pend) { - PATFETCH(c); - if (c == '?') greedy = 0; - else PATUNFETCH; - } - - if (lower_bound == 0) { - zero_times_ok = 1; - if (upper_bound == RE_DUP_MAX) { - many_times_ok = 1; - goto repeat; - } - if (upper_bound == 1) { - many_times_ok = 0; - goto repeat; - } - } - if (lower_bound == 1) { - if (upper_bound == 1) { - /* No need to repeat */ - break; - } - if (upper_bound == RE_DUP_MAX) { - many_times_ok = 1; - zero_times_ok = 0; - goto repeat; - } - } - - /* If upper_bound is zero, don't want to succeed at all; - jump from laststart to b + 3, which will be the end of - the buffer after this jump is inserted. */ - - if (upper_bound == 0) { - GET_BUFFER_SPACE(3); - insert_jump(jump, laststart, b + 3, b); - b += 3; - break; - } - - /* If lower_bound == upper_bound, repeat count can be removed */ - if (lower_bound == upper_bound) { - int mcnt; - int skip_stop_paren = 0; - - if (b[-1] == stop_paren) { - skip_stop_paren = 1; - b--; - } - - if (*laststart == exactn && laststart[1]+2 == b - laststart - && laststart[1]*lower_bound < 256) { - mcnt = laststart[1]; - GET_BUFFER_SPACE((lower_bound-1)*mcnt); - laststart[1] = lower_bound*mcnt; - while (--lower_bound) { - memcpy(b, laststart+2, mcnt); - b += mcnt; - } - if (skip_stop_paren) BUFPUSH(stop_paren); - break; - } - - if (lower_bound < 5 && b - laststart < 10) { - /* 5 and 10 are the magic numbers */ - - mcnt = b - laststart; - GET_BUFFER_SPACE((lower_bound-1)*mcnt); - while (--lower_bound) { - memcpy(b, laststart, mcnt); - b += mcnt; - } - if (skip_stop_paren) BUFPUSH(stop_paren); - break; - } - if (skip_stop_paren) b++; /* push back stop_paren */ - } - - /* Otherwise, we have a nontrivial interval. When - we're all done, the pattern will look like: - set_number_at - set_number_at - succeed_n - - jump_n - (The upper bound and `jump_n' are omitted if - `upper_bound' is 1, though.) */ - { /* If the upper bound is > 1, we need to insert - more at the end of the loop. */ - unsigned nbytes = upper_bound == 1 ? 10 : 20; - - GET_BUFFER_SPACE(nbytes); - /* Initialize lower bound of the `succeed_n', even - though it will be set during matching by its - attendant `set_number_at' (inserted next), - because `re_compile_fastmap' needs to know. - Jump to the `jump_n' we might insert below. */ - insert_jump_n(succeed_n, laststart, b + (nbytes/2), - b, lower_bound); - b += 5; /* Just increment for the succeed_n here. */ - - /* Code to initialize the lower bound. Insert - before the `succeed_n'. The `5' is the last two - bytes of this `set_number_at', plus 3 bytes of - the following `succeed_n'. */ - insert_op_2(set_number_at, laststart, b, 5, lower_bound); - b += 5; - - if (upper_bound > 1) { - /* More than one repetition is allowed, so - append a backward jump to the `succeed_n' - that starts this interval. - - When we've reached this during matching, - we'll have matched the interval once, so - jump back only `upper_bound - 1' times. */ - GET_BUFFER_SPACE(5); - store_jump_n(b, greedy?jump_n:finalize_push_n, laststart + 5, - upper_bound - 1); - b += 5; - - /* The location we want to set is the second - parameter of the `jump_n'; that is `b-2' as - an absolute address. `laststart' will be - the `set_number_at' we're about to insert; - `laststart+3' the number to set, the source - for the relative address. But we are - inserting into the middle of the pattern -- - so everything is getting moved up by 5. - Conclusion: (b - 2) - (laststart + 3) + 5, - i.e., b - laststart. - - We insert this at the beginning of the loop - so that if we fail during matching, we'll - reinitialize the bounds. */ - insert_op_2(set_number_at, laststart, b, b - laststart, - upper_bound - 1); - b += 5; - } - } - break; - - unfetch_interval: - /* If an invalid interval, match the characters as literals. */ - re_warning("regexp has invalid interval"); - p = beg_interval; - beg_interval = 0; - - /* normal_char and normal_backslash need `c'. */ - PATFETCH(c); - goto normal_char; - - case '\\': - if (p == pend) - FREE_AND_RETURN(stackb, "invalid regular expression; '\\' can't be last character"); - /* Do not translate the character after the \, so that we can - distinguish, e.g., \B from \b, even if we normally would - translate, e.g., B to b. */ - PATFETCH_RAW(c); - switch (c) { - case 's': - case 'S': - case 'd': - case 'D': - while (b - bufp->buffer + 9 + (1 << BYTEWIDTH) / BYTEWIDTH - > bufp->allocated) - EXTEND_BUFFER; - - laststart = b; - if (c == 's' || c == 'd') { - BUFPUSH(charset); - } - else { - BUFPUSH(charset_not); - } - - BUFPUSH((1 << BYTEWIDTH) / BYTEWIDTH); - memset(b, 0, (1 << BYTEWIDTH) / BYTEWIDTH + 2); - if (c == 's' || c == 'S') { - SET_LIST_BIT(' '); - SET_LIST_BIT('\t'); - SET_LIST_BIT('\n'); - SET_LIST_BIT('\r'); - SET_LIST_BIT('\f'); - } - else { - char cc; - - for (cc = '0'; cc <= '9'; cc++) { - SET_LIST_BIT(cc); - } - } - - while ((int)b[-1] > 0 && b[b[-1] - 1] == 0) - b[-1]--; - if (b[-1] != (1 << BYTEWIDTH) / BYTEWIDTH) - memmove(&b[(unsigned char)b[-1]], &b[(1 << BYTEWIDTH) / BYTEWIDTH], - 2 + EXTRACT_UNSIGNED(&b[(1 << BYTEWIDTH) / BYTEWIDTH])*8); - b += b[-1] + 2 + EXTRACT_UNSIGNED(&b[(unsigned char)b[-1]])*8; - break; - - case 'w': - laststart = b; - BUFPUSH(wordchar); - break; - - case 'W': - laststart = b; - BUFPUSH(notwordchar); - break; - -#ifndef RUBY - case '<': - BUFPUSH(wordbeg); - break; - - case '>': - BUFPUSH(wordend); - break; -#endif - - case 'b': - BUFPUSH(wordbound); - break; - - case 'B': - BUFPUSH(notwordbound); - break; - - case 'A': - BUFPUSH(begbuf); - break; - - case 'Z': - if ((bufp->options & RE_OPTION_SINGLELINE) == 0) { - BUFPUSH(endbuf2); - break; - } - /* fall through */ - case 'z': - BUFPUSH(endbuf); - break; - - case 'G': - BUFPUSH(begpos); - break; - - /* hex */ - case 'x': - had_mbchar = 0; - c = scan_hex(p, 2, &numlen); - if (numlen == 0) goto invalid_escape; - p += numlen; - had_num_literal = 1; - goto numeric_char; - - /* octal */ - case '0': - had_mbchar = 0; - c = scan_oct(p, 2, &numlen); - p += numlen; - had_num_literal = 1; - goto numeric_char; - - /* back-ref or octal */ - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - PATUNFETCH; - p0 = p; - - had_mbchar = 0; - c1 = 0; - GET_UNSIGNED_NUMBER(c1); - if (!ISDIGIT(c)) PATUNFETCH; - - if (9 < c1 && c1 >= regnum) { - /* need to get octal */ - c = scan_oct(p0, 3, &numlen) & 0xff; - p = p0 + numlen; - c1 = 0; - had_num_literal = 1; - goto numeric_char; - } - - laststart = b; - BUFPUSH(duplicate); - BUFPUSH(c1); - break; - - case 'M': - case 'C': - case 'c': - p0 = --p; - c = read_special(p, pend, &p0); - if (c > 255) goto invalid_escape; - p = p0; - had_num_literal = 1; - goto numeric_char; - - default: - c = read_backslash(c); - goto normal_char; - } - break; - - case '#': - if (options & RE_OPTION_EXTENDED) { - while (p != pend) { - PATFETCH(c); - if (c == '\n') break; - } - break; - } - goto normal_char; - - case ' ': - case '\t': - case '\f': - case '\r': - case '\n': - if (options & RE_OPTION_EXTENDED) - break; - - default: - if (c == ']') - re_warning("regexp has `]' without escape"); - else if (c == '}') - re_warning("regexp has `}' without escape"); - normal_char: /* Expects the character in `c'. */ - had_mbchar = 0; - if (ismbchar(c)) { - had_mbchar = 1; - c1 = p - pattern; - } - numeric_char: - nextp = p + mbclen(c) - 1; - if (!pending_exact || pending_exact + *pending_exact + 1 != b - || *pending_exact >= (c1 ? 0176 : 0177) - || (nextp < pend && - ( *nextp == '+' || *nextp == '?' - || *nextp == '*' || *nextp == '^' - || *nextp == '{'))) { - laststart = b; - BUFPUSH(exactn); - pending_exact = b; - BUFPUSH(0); - } - if (had_num_literal || c == 0xff) { - BUFPUSH(0xff); - (*pending_exact)++; - had_num_literal = 0; - } - BUFPUSH(c); - (*pending_exact)++; - if (had_mbchar) { - int len = mbclen(c) - 1; - while (len--) { - PATFETCH_RAW(c); - BUFPUSH(c); - (*pending_exact)++; - } - } - } - } - - if (fixup_alt_jump) - store_jump(fixup_alt_jump, jump, b); - - if (stackp != stackb) - FREE_AND_RETURN(stackb, "unmatched ("); - - /* set optimize flags */ - laststart = bufp->buffer; - if (laststart != b) { - if (*laststart == dummy_failure_jump) laststart += 3; - else if (*laststart == try_next) laststart += 3; - if (*laststart == anychar_repeat) { - bufp->options |= RE_OPTIMIZE_ANCHOR; - } - } - - bufp->used = b - bufp->buffer; - bufp->re_nsub = regnum; - laststart = bufp->buffer; - if (laststart != b) { - if (*laststart == start_memory) laststart += 3; - if (*laststart == exactn) { - bufp->options |= RE_OPTIMIZE_EXACTN; - bufp->must = laststart+1; - } - } - if (!bufp->must) { - bufp->must = calculate_must_string(bufp->buffer, b); - } - if (current_mbctype == MBCTYPE_SJIS) bufp->options |= RE_OPTIMIZE_NO_BM; - else if (bufp->must) { - int i; - int len = (unsigned char)bufp->must[0]; - - for (i=1; imust[i] == 0xff || - (current_mbctype && ismbchar(bufp->must[i]))) { - bufp->options |= RE_OPTIMIZE_NO_BM; - break; - } - } - if (!(bufp->options & RE_OPTIMIZE_NO_BM)) { - bufp->must_skip = (int *) xmalloc((1 << BYTEWIDTH)*sizeof(int)); - bm_init_skip(bufp->must_skip, (unsigned char*)bufp->must+1, - (unsigned char)bufp->must[0], - (unsigned char*)(MAY_TRANSLATE()?translate:0)); - } - } - - bufp->regstart = TMALLOC(regnum, unsigned char*); - bufp->regend = TMALLOC(regnum, unsigned char*); - bufp->old_regstart = TMALLOC(regnum, unsigned char*); - bufp->old_regend = TMALLOC(regnum, unsigned char*); - bufp->reg_info = TMALLOC(regnum, register_info_type); - bufp->best_regstart = TMALLOC(regnum, unsigned char*); - bufp->best_regend = TMALLOC(regnum, unsigned char*); - FREE_AND_RETURN(stackb, 0); - - invalid_pattern: - FREE_AND_RETURN(stackb, "invalid regular expression"); - - end_of_pattern: - FREE_AND_RETURN(stackb, "premature end of regular expression"); - - too_big: - FREE_AND_RETURN(stackb, "regular expression too big"); - - memory_exhausted: - FREE_AND_RETURN(stackb, "memory exhausted"); - - nested_meta: - FREE_AND_RETURN(stackb, "nested *?+ in regexp"); - - invalid_escape: - FREE_AND_RETURN(stackb, "Invalid escape character syntax"); -} - -void -re_free_pattern(bufp) - struct re_pattern_buffer *bufp; -{ - xfree(bufp->buffer); - xfree(bufp->fastmap); - if (bufp->must_skip) xfree(bufp->must_skip); - - xfree(bufp->regstart); - xfree(bufp->regend); - xfree(bufp->old_regstart); - xfree(bufp->old_regend); - xfree(bufp->best_regstart); - xfree(bufp->best_regend); - xfree(bufp->reg_info); - xfree(bufp); -} - -/* Store a jump of the form . - Store in the location FROM a jump operation to jump to relative - address FROM - TO. OPCODE is the opcode to store. */ - -static void -store_jump(from, opcode, to) - char *from, *to; - int opcode; -{ - from[0] = (char)opcode; - STORE_NUMBER(from + 1, to - (from + 3)); -} - - -/* Open up space before char FROM, and insert there a jump to TO. - CURRENT_END gives the end of the storage not in use, so we know - how much data to copy up. OP is the opcode of the jump to insert. - - If you call this function, you must zero out pending_exact. */ - -static void -insert_jump(op, from, to, current_end) - int op; - char *from, *to, *current_end; -{ - register char *pfrom = current_end; /* Copy from here... */ - register char *pto = current_end + 3; /* ...to here. */ - - while (pfrom != from) - *--pto = *--pfrom; - store_jump(from, op, to); -} - - -/* Store a jump of the form . - - Store in the location FROM a jump operation to jump to relative - address FROM - TO. OPCODE is the opcode to store, N is a number the - jump uses, say, to decide how many times to jump. - - If you call this function, you must zero out pending_exact. */ - -static void -store_jump_n(from, opcode, to, n) - char *from, *to; - int opcode; - unsigned n; -{ - from[0] = (char)opcode; - STORE_NUMBER(from + 1, to - (from + 3)); - STORE_NUMBER(from + 3, n); -} - - -/* Similar to insert_jump, but handles a jump which needs an extra - number to handle minimum and maximum cases. Open up space at - location FROM, and insert there a jump to TO. CURRENT_END gives the - end of the storage in use, so we know how much data to copy up. OP is - the opcode of the jump to insert. - - If you call this function, you must zero out pending_exact. */ - -static void -insert_jump_n(op, from, to, current_end, n) - int op; - char *from, *to, *current_end; - unsigned n; -{ - register char *pfrom = current_end; /* Copy from here... */ - register char *pto = current_end + 5; /* ...to here. */ - - while (pfrom != from) - *--pto = *--pfrom; - store_jump_n(from, op, to, n); -} - - -/* Open up space at location THERE, and insert operation OP. - CURRENT_END gives the end of the storage in use, so - we know how much data to copy up. - - If you call this function, you must zero out pending_exact. */ - -static void -insert_op(op, there, current_end) - int op; - char *there, *current_end; -{ - register char *pfrom = current_end; /* Copy from here... */ - register char *pto = current_end + 1; /* ...to here. */ - - while (pfrom != there) - *--pto = *--pfrom; - - there[0] = (char)op; -} - - -/* Open up space at location THERE, and insert operation OP followed by - NUM_1 and NUM_2. CURRENT_END gives the end of the storage in use, so - we know how much data to copy up. - - If you call this function, you must zero out pending_exact. */ - -static void -insert_op_2(op, there, current_end, num_1, num_2) - int op; - char *there, *current_end; - int num_1, num_2; -{ - register char *pfrom = current_end; /* Copy from here... */ - register char *pto = current_end + 5; /* ...to here. */ - - while (pfrom != there) - *--pto = *--pfrom; - - there[0] = (char)op; - STORE_NUMBER(there + 1, num_1); - STORE_NUMBER(there + 3, num_2); -} - - -#define trans_eq(c1, c2, translate) (translate?(translate[c1]==translate[c2]):((c1)==(c2))) -static int -slow_match(little, lend, big, bend, translate) - const unsigned char *little, *lend; - const unsigned char *big, *bend; - const unsigned char *translate; -{ - int c; - - while (little < lend && big < bend) { - c = *little++; - if (c == 0xff) - c = *little++; - if (!trans_eq(*big++, c, translate)) break; - } - if (little == lend) return 1; - return 0; -} - -static int -slow_search(little, llen, big, blen, translate) - const unsigned char *little; - int llen; - const unsigned char *big; - int blen; - const char *translate; -{ - const unsigned char *bsave = big; - const unsigned char *bend = big + blen; - register int c; - int fescape = 0; - - c = *little; - if (c == 0xff) { - c = little[1]; - fescape = 1; - } - else if (translate && !ismbchar(c)) { - c = translate[c]; - } - - while (big < bend) { - /* look for first character */ - if (fescape) { - while (big < bend) { - if (*big == c) break; - big++; - } - } - else if (translate && !ismbchar(c)) { - while (big < bend) { - if (ismbchar(*big)) big+=mbclen(*big)-1; - else if (translate[*big] == c) break; - big++; - } - } - else { - while (big < bend) { - if (*big == c) break; - if (ismbchar(*big)) big+=mbclen(*big)-1; - big++; - } - } - - if (slow_match(little, little+llen, big, bend, translate)) - return big - bsave; - - big+=mbclen(*big); - } - return -1; -} - -static void -bm_init_skip(skip, pat, m, translate) - int *skip; - unsigned char *pat; - int m; - const unsigned char *translate; -{ - int j, c; - - for (c=0; c<256; c++) { - skip[c] = m; - } - if (translate) { - for (j=0; j= 0 && translate[big[k]] == translate[little[j]]) { - k--; - j--; - } - if (j < 0) return k+1; - - i += skip[translate[big[i]]]; - } - return -1; - } - while (i < blen) { - k = i; - j = llen-1; - while (j >= 0 && big[k] == little[j]) { - k--; - j--; - } - if (j < 0) return k+1; - - i += skip[big[i]]; - } - return -1; -} - -/* Given a pattern, compute a fastmap from it. The fastmap records - which of the (1 << BYTEWIDTH) possible characters can start a string - that matches the pattern. This fastmap is used by re_search to skip - quickly over totally implausible text. - - The caller must supply the address of a (1 << BYTEWIDTH)-byte data - area as bufp->fastmap. - The other components of bufp describe the pattern to be used. */ -void -re_compile_fastmap(bufp) - struct re_pattern_buffer *bufp; -{ - unsigned char *pattern = (unsigned char*)bufp->buffer; - int size = bufp->used; - register char *fastmap = bufp->fastmap; - register unsigned char *p = pattern; - register unsigned char *pend = pattern + size; - register int j, k; - unsigned is_a_succeed_n; - - - unsigned char *stacka[NFAILURES]; - unsigned char **stackb = stacka; - unsigned char **stackp = stackb; - unsigned char **stacke = stackb + NFAILURES; - int options = bufp->options; - - memset(fastmap, 0, (1 << BYTEWIDTH)); - bufp->fastmap_accurate = 1; - bufp->can_be_null = 0; - - while (p) { - is_a_succeed_n = 0; - if (p == pend) { - bufp->can_be_null = 1; - break; - } -#ifdef SWITCH_ENUM_BUG - switch ((int)((enum regexpcode)*p++)) -#else - switch ((enum regexpcode)*p++) -#endif - { - case exactn: - if (p[1] == 0xff) { - if (TRANSLATE_P()) - fastmap[translate[p[2]]] = 2; - else - fastmap[p[2]] = 2; - bufp->options |= RE_OPTIMIZE_BMATCH; - } - else if (TRANSLATE_P()) - fastmap[translate[p[1]]] = 1; - else - fastmap[p[1]] = 1; - break; - - case begline: - case begbuf: - case begpos: - case endbuf: - case endbuf2: - case wordbound: - case notwordbound: - case wordbeg: - case wordend: - case pop_and_fail: - case push_dummy_failure: - case start_paren: - case stop_paren: - continue; - - case casefold_on: - bufp->options |= RE_MAY_IGNORECASE; - options |= RE_OPTION_IGNORECASE; - continue; - - case casefold_off: - options &= ~RE_OPTION_IGNORECASE; - continue; - - case option_set: - options = *p++; - continue; - - case endline: - if (TRANSLATE_P()) - fastmap[translate['\n']] = 1; - else - fastmap['\n'] = 1; - if ((options & RE_OPTION_SINGLELINE) == 0 && bufp->can_be_null == 0) - bufp->can_be_null = 2; - break; - - case jump_n: - case finalize_jump: - case maybe_finalize_jump: - case jump: - case jump_past_alt: - case dummy_failure_jump: - case finalize_push: - case finalize_push_n: - EXTRACT_NUMBER_AND_INCR(j, p); - p += j; - if (j > 0) - continue; - /* Jump backward reached implies we just went through - the body of a loop and matched nothing. - Opcode jumped to should be an on_failure_jump. - Just treat it like an ordinary jump. - For a * loop, it has pushed its failure point already; - If so, discard that as redundant. */ - - if ((enum regexpcode)*p != on_failure_jump - && (enum regexpcode)*p != try_next - && (enum regexpcode)*p != succeed_n) - continue; - p++; - EXTRACT_NUMBER_AND_INCR(j, p); - p += j; - if (stackp != stackb && *stackp == p) - stackp--; /* pop */ - continue; - - case try_next: - case start_nowidth: - case stop_nowidth: - case stop_backtrack: - p += 2; - continue; - - case succeed_n: - is_a_succeed_n = 1; - /* Get to the number of times to succeed. */ - EXTRACT_NUMBER(k, p + 2); - /* Increment p past the n for when k != 0. */ - if (k != 0) { - p += 4; - continue; - } - /* fall through */ - - case on_failure_jump: - EXTRACT_NUMBER_AND_INCR(j, p); - if (p + j < pend) { - if (stackp == stacke) { - EXPAND_FAIL_STACK(); - } - *++stackp = p + j; /* push */ - } - else { - bufp->can_be_null = 1; - } - if (is_a_succeed_n) - EXTRACT_NUMBER_AND_INCR(k, p); /* Skip the n. */ - continue; - - case set_number_at: - p += 4; - continue; - - case start_memory: - case stop_memory: - p += 2; - continue; - - case duplicate: - bufp->can_be_null = 1; - if (*p >= bufp->re_nsub) break; - fastmap['\n'] = 1; - case anychar_repeat: - case anychar: - for (j = 0; j < (1 << BYTEWIDTH); j++) { - if (j != '\n' || (options & RE_OPTION_MULTILINE)) - fastmap[j] = 1; - } - if (bufp->can_be_null) { - FREE_AND_RETURN_VOID(stackb); - } - /* Don't return; check the alternative paths - so we can set can_be_null if appropriate. */ - if ((enum regexpcode)p[-1] == anychar_repeat) { - continue; - } - break; - - case wordchar: - for (j = 0; j < 0x80; j++) { - if (SYNTAX(j) == Sword) - fastmap[j] = 1; - } - switch (current_mbctype) { - case MBCTYPE_ASCII: - for (j = 0x80; j < (1 << BYTEWIDTH); j++) { - if (SYNTAX(j) == Sword2) - fastmap[j] = 1; - } - break; - case MBCTYPE_EUC: - case MBCTYPE_SJIS: - case MBCTYPE_UTF8: - for (j = 0x80; j < (1 << BYTEWIDTH); j++) { - if (re_mbctab[j]) - fastmap[j] = 1; - } - break; - } - break; - - case notwordchar: - for (j = 0; j < 0x80; j++) - if (SYNTAX(j) != Sword) - fastmap[j] = 1; - switch (current_mbctype) { - case MBCTYPE_ASCII: - for (j = 0x80; j < (1 << BYTEWIDTH); j++) { - if (SYNTAX(j) != Sword2) - fastmap[j] = 1; - } - break; - case MBCTYPE_EUC: - case MBCTYPE_SJIS: - case MBCTYPE_UTF8: - for (j = 0x80; j < (1 << BYTEWIDTH); j++) { - if (!re_mbctab[j]) - fastmap[j] = 1; - } - break; - } - break; - - case charset: - /* NOTE: Charset for single-byte chars never contain - multi-byte char. See set_list_bits(). */ - for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) - if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) { - int tmp = TRANSLATE_P()?translate[j]:j; - fastmap[tmp] = 1; - } - { - unsigned short size; - unsigned long c, beg, end; - - p += p[-1] + 2; - size = EXTRACT_UNSIGNED(&p[-2]); - for (j = 0; j < (int)size; j++) { - c = EXTRACT_MBC(&p[j*8]); - beg = WC2MBC1ST(c); - c = EXTRACT_MBC(&p[j*8+4]); - end = WC2MBC1ST(c); - /* set bits for 1st bytes of multi-byte chars. */ - while (beg <= end) { - /* NOTE: Charset for multi-byte chars might contain - single-byte chars. We must reject them. */ - if (c < 0x100) { - fastmap[beg] = 2; - bufp->options |= RE_OPTIMIZE_BMATCH; - } - else if (ismbchar(beg)) - fastmap[beg] = 1; - beg++; - } - } - } - break; - - case charset_not: - /* S: set of all single-byte chars. - M: set of all first bytes that can start multi-byte chars. - s: any set of single-byte chars. - m: any set of first bytes that can start multi-byte chars. - - We assume S+M = U. - ___ _ _ - s+m = (S*s+M*m). */ - /* Chars beyond end of map must be allowed */ - /* NOTE: Charset_not for single-byte chars might contain - multi-byte chars. See set_list_bits(). */ - for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) - if (!ismbchar(j)) - fastmap[j] = 1; - - for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) - if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) { - if (!ismbchar(j)) - fastmap[j] = 1; - } - { - unsigned short size; - unsigned long c, beg; - int num_literal = 0; - - p += p[-1] + 2; - size = EXTRACT_UNSIGNED(&p[-2]); - if (size == 0) { - for (j = 0x80; j < (1 << BYTEWIDTH); j++) - if (ismbchar(j)) - fastmap[j] = 1; - break; - } - for (j = 0,c = 0;j < (int)size; j++) { - unsigned int cc = EXTRACT_MBC(&p[j*8]); - beg = WC2MBC1ST(cc); - while (c <= beg) { - if (ismbchar(c)) - fastmap[c] = 1; - c++; - } - - cc = EXTRACT_MBC(&p[j*8+4]); - if (cc < 0xff) { - num_literal = 1; - while (c <= cc) { - if (ismbchar(c)) - fastmap[c] = 1; - c++; - } - } - c = WC2MBC1ST(cc); - } - - for (j = c; j < (1 << BYTEWIDTH); j++) { - if (num_literal) - fastmap[j] = 1; - if (ismbchar(j)) - fastmap[j] = 1; - } - } - break; - - case unused: /* pacify gcc -Wall */ - break; - } - - /* Get here means we have successfully found the possible starting - characters of one path of the pattern. We need not follow this - path any farther. Instead, look at the next alternative - remembered in the stack. */ - if (stackp != stackb) - p = *stackp--; /* pop */ - else - break; - } - FREE_AND_RETURN_VOID(stackb); -} - -/* adjust startpos value to the position between characters. */ -int -re_adjust_startpos(bufp, string, size, startpos, range) - struct re_pattern_buffer *bufp; - const char *string; - int size, startpos, range; -{ - /* Update the fastmap now if not correct already. */ - if (!bufp->fastmap_accurate) { - re_compile_fastmap(bufp); - } - - /* Adjust startpos for mbc string */ - if (current_mbctype && startpos>0 && !(bufp->options&RE_OPTIMIZE_BMATCH)) { - int i = mbc_startpos(string, startpos); - - if (i < startpos) { - if (range > 0) { - startpos = i + mbclen(string[i]); - } - else { - int len = mbclen(string[i]); - if (i + len <= startpos) - startpos = i + len; - else - startpos = i; - } - } - } - return startpos; -} - - -static int re_match_exec _((struct re_pattern_buffer *, const char *, int, int, int, - struct re_registers *)); - -/* Using the compiled pattern in BUFP->buffer, first tries to match - STRING, starting first at index STARTPOS, then at STARTPOS + 1, and - so on. RANGE is the number of places to try before giving up. If - RANGE is negative, it searches backwards, i.e., the starting - positions tried are STARTPOS, STARTPOS - 1, etc. STRING is of SIZE. - In REGS, return the indices of STRING that matched the entire - BUFP->buffer and its contained subexpressions. - - The value returned is the position in the strings at which the match - was found, or -1 if no match was found, or -2 if error (such as - failure stack overflow). */ - -int -re_search(bufp, string, size, startpos, range, regs) - struct re_pattern_buffer *bufp; - const char *string; - int size, startpos, range; - struct re_registers *regs; -{ - register char *fastmap = bufp->fastmap; - int val, anchor = 0, initpos = startpos; - - /* Check for out-of-range starting position. */ - if (startpos < 0 || startpos > size) - return -1; - - /* Update the fastmap now if not correct already. */ - if (fastmap && !bufp->fastmap_accurate) { - re_compile_fastmap(bufp); - } - - - /* If the search isn't to be a backwards one, don't waste time in a - search for a pattern that must be anchored. */ - if (bufp->used > 0) { - switch ((enum regexpcode)bufp->buffer[0]) { - case begbuf: - begbuf_match: - if (range > 0) { - if (startpos > 0) return -1; - else { - val = re_match(bufp, string, size, 0, regs); - if (val >= 0) return 0; - return val; - } - } - break; - - case begline: - anchor = 1; - break; - - case begpos: - val = re_match(bufp, string, size, startpos, regs); - if (val >= 0) return startpos; - return val; - - default: - break; - } - } - if (bufp->options & RE_OPTIMIZE_ANCHOR) { - if (bufp->options&RE_OPTION_MULTILINE && range > 0) { - goto begbuf_match; - } - anchor = 1; - } - - if (bufp->must) { - int len = ((unsigned char*)bufp->must)[0]; - int pos, pbeg, pend; - - pbeg = startpos; - pend = startpos + range; - if (pbeg > pend) { /* swap pbeg,pend */ - pos = pend; pend = pbeg; pbeg = pos; - } - pend = size; - if (bufp->options & RE_OPTIMIZE_NO_BM) { - pos = slow_search(bufp->must+1, len, - string+pbeg, pend-pbeg, - MAY_TRANSLATE()?translate:0); - } - else { - pos = bm_search(bufp->must+1, len, - string+pbeg, pend-pbeg, - bufp->must_skip, - MAY_TRANSLATE()?translate:0); - } - if (pos == -1) return -1; - if (range > 0 && (bufp->options & RE_OPTIMIZE_EXACTN)) { - startpos += pos; - range -= pos; - if (range < 0) return -1; - } - } - - for (;;) { - /* If a fastmap is supplied, skip quickly over characters that - cannot possibly be the start of a match. Note, however, that - if the pattern can possibly match the null string, we must - test it at each starting point so that we take the first null - string we get. */ - - if (fastmap && startpos < size - && bufp->can_be_null != 1 && !(anchor && startpos == 0)) { - if (range > 0) { /* Searching forwards. */ - register unsigned char *p, c; - int irange = range; - - p = (unsigned char*)string+startpos; - - while (range > 0) { - c = *p++; - if (ismbchar(c)) { - int len; - - if (fastmap[c]) - break; - len = mbclen(c) - 1; - while (len--) { - c = *p++; - range--; - if (fastmap[c] == 2) - goto startpos_adjust; - } - } - else { - if (fastmap[MAY_TRANSLATE() ? translate[c] : c]) - break; - } - range--; - } - startpos_adjust: - startpos += irange - range; - } - else { /* Searching backwards. */ - register unsigned char c; - - c = string[startpos]; - c &= 0xff; - if (MAY_TRANSLATE() ? !fastmap[translate[c]] : !fastmap[c]) - goto advance; - } - } - - if (startpos > size) return -1; - if ((anchor || !bufp->can_be_null) && range > 0 && size > 0 && startpos == size) - return -1; - val = re_match_exec(bufp, string, size, startpos, initpos, regs); - if (val >= 0) return startpos; - if (val == -2) return -2; - -#ifndef NO_ALLOCA -#ifdef C_ALLOCA - alloca(0); -#endif /* C_ALLOCA */ -#endif /* NO_ALLOCA */ - - if (range > 0) { - if (anchor && startpos < size && - (startpos < 1 || string[startpos-1] != '\n')) { - while (range > 0 && string[startpos] != '\n') { - range--; - startpos++; - } - } - } - - advance: - if (!range) - break; - else if (range > 0) { - const char *d = string + startpos; - - if (ismbchar(*d)) { - int len = mbclen(*d) - 1; - range-=len, startpos+=len; - if (!range) - break; - } - range--, startpos++; - } - else { - range++, startpos--; - { - const char *s, *d, *p; - - s = string; d = string + startpos; - for (p = d; p-- > s && ismbchar(*p); ) - /* --p >= s would not work on 80[12]?86. - (when the offset of s equals 0 other than huge model.) */ - ; - if (!((d - p) & 1)) { - if (!range) - break; - range++, startpos--; - } - } - } - } - return -1; -} - - - - -/* The following are used for re_match, defined below: */ - -/* Accessing macros used in re_match: */ - -#define IS_ACTIVE(R) ((R).bits.is_active) -#define MATCHED_SOMETHING(R) ((R).bits.matched_something) - - -/* Macros used by re_match: */ - -/* I.e., regstart, regend, and reg_info. */ -#define NUM_REG_ITEMS 3 - -/* I.e., ptr and count. */ -#define NUM_COUNT_ITEMS 2 - -/* Individual items aside from the registers. */ -#define NUM_NONREG_ITEMS 4 - -/* We push at most this many things on the stack whenever we - fail. The `+ 2' refers to PATTERN_PLACE and STRING_PLACE, which are - arguments to the PUSH_FAILURE_POINT macro. */ -#define MAX_NUM_FAILURE_ITEMS (num_regs * NUM_REG_ITEMS + NUM_NONREG_ITEMS) - -/* We push this many things on the stack whenever we fail. */ -#define NUM_FAILURE_ITEMS (last_used_reg * NUM_REG_ITEMS + NUM_NONREG_ITEMS + 1) - -/* This pushes counter information for succeed_n and jump_n */ -#define PUSH_FAILURE_COUNT(ptr) \ - do { \ - int c; \ - EXTRACT_NUMBER(c, ptr); \ - ENSURE_FAIL_STACK(NUM_COUNT_ITEMS); \ - *stackp++ = (unsigned char*)(long)c; \ - *stackp++ = (ptr); \ - num_failure_counts++; \ - } while (0) - -/* This pushes most of the information about the current state we will want - if we ever fail back to it. */ - -#define PUSH_FAILURE_POINT(pattern_place, string_place) \ - do { \ - long last_used_reg, this_reg; \ - \ - /* Find out how many registers are active or have been matched. \ - (Aside from register zero, which is only set at the end.) */ \ - for (last_used_reg = num_regs-1; last_used_reg > 0; last_used_reg--)\ - if (!REG_UNSET(regstart[last_used_reg])) \ - break; \ - \ - ENSURE_FAIL_STACK(NUM_FAILURE_ITEMS); \ - *stackp++ = (unsigned char*)(long)num_failure_counts; \ - num_failure_counts = 0; \ - \ - /* Now push the info for each of those registers. */ \ - for (this_reg = 1; this_reg <= last_used_reg; this_reg++) { \ - *stackp++ = regstart[this_reg]; \ - *stackp++ = regend[this_reg]; \ - *stackp++ = reg_info[this_reg].word; \ - } \ - \ - /* Push how many registers we saved. */ \ - *stackp++ = (unsigned char*)last_used_reg; \ - \ - *stackp++ = pattern_place; \ - *stackp++ = string_place; \ - *stackp++ = (unsigned char*)(long)options; /* current option status */ \ - *stackp++ = (unsigned char*)0; /* non-greedy flag */ \ - } while(0) - -#define NON_GREEDY ((unsigned char*)1) - -#define POP_FAILURE_COUNT() \ - do { \ - unsigned char *ptr = *--stackp; \ - int count = (long)*--stackp; \ - STORE_NUMBER(ptr, count); \ - } while (0) - -/* This pops what PUSH_FAILURE_POINT pushes. */ - -#define POP_FAILURE_POINT() \ - do { \ - long temp; \ - stackp -= NUM_NONREG_ITEMS; /* Remove failure points (and flag). */ \ - temp = (long)*--stackp; /* How many regs pushed. */ \ - temp *= NUM_REG_ITEMS; /* How much to take off the stack. */ \ - stackp -= temp; /* Remove the register info. */ \ - temp = (long)*--stackp; /* How many counters pushed. */ \ - while (temp--) { \ - POP_FAILURE_COUNT(); /* Remove the counter info. */ \ - } \ - num_failure_counts = 0; /* Reset num_failure_counts. */ \ - } while(0) - - /* Registers are set to a sentinel when they haven't yet matched. */ -#define REG_UNSET_VALUE ((unsigned char*)-1) -#define REG_UNSET(e) ((e) == REG_UNSET_VALUE) - -#define PREFETCH if (d == dend) goto fail - - /* Call this when have matched something; it sets `matched' flags for the - registers corresponding to the subexpressions of which we currently - are inside. */ -#define SET_REGS_MATCHED \ - do { unsigned this_reg; \ - for (this_reg = 0; this_reg < num_regs; this_reg++) { \ - if (IS_ACTIVE(reg_info[this_reg])) \ - MATCHED_SOMETHING(reg_info[this_reg]) = 1; \ - else \ - MATCHED_SOMETHING(reg_info[this_reg]) = 0; \ - } \ - } while(0) - -#define AT_STRINGS_BEG(d) ((d) == string) -#define AT_STRINGS_END(d) ((d) == dend) - -#define IS_A_LETTER(d) (SYNTAX(*(d)) == Sword || \ - (current_mbctype ? \ - (re_mbctab[*(d)] && ((d)+mbclen(*(d)))<=dend): \ - SYNTAX(*(d)) == Sword2)) - -#define PREV_IS_A_LETTER(d) ((current_mbctype == MBCTYPE_SJIS)? \ - IS_A_LETTER((d)-(!AT_STRINGS_BEG((d)-1)&& \ - ismbchar((d)[-2])?2:1)): \ - ((current_mbctype && ((d)[-1] >= 0x80)) || \ - IS_A_LETTER((d)-1))) - -static void -init_regs(regs, num_regs) - struct re_registers *regs; - unsigned int num_regs; -{ - int i; - - regs->num_regs = num_regs; - if (num_regs < RE_NREGS) - num_regs = RE_NREGS; - - if (regs->allocated == 0) { - regs->beg = TMALLOC(num_regs, int); - regs->end = TMALLOC(num_regs, int); - regs->allocated = num_regs; - } - else if (regs->allocated < num_regs) { - TREALLOC(regs->beg, num_regs, int); - TREALLOC(regs->end, num_regs, int); - regs->allocated = num_regs; - } - for (i=0; ibeg[i] = regs->end[i] = -1; - } -} - -/* Match the pattern described by BUFP against STRING, which is of - SIZE. Start the match at index POS in STRING. In REGS, return the - indices of STRING that matched the entire BUFP->buffer and its - contained subexpressions. - - If bufp->fastmap is nonzero, then it had better be up to date. - - The reason that the data to match are specified as two components - which are to be regarded as concatenated is so this function can be - used directly on the contents of an Emacs buffer. - - -1 is returned if there is no match. -2 is returned if there is an - error (such as match stack overflow). Otherwise the value is the - length of the substring which was matched. */ - -int -re_match(bufp, string_arg, size, pos, regs) - struct re_pattern_buffer *bufp; - const char *string_arg; - int size, pos; - struct re_registers *regs; -{ - return re_match_exec(bufp, string_arg, size, pos, pos, regs); -} - -static int -re_match_exec(bufp, string_arg, size, pos, beg, regs) - struct re_pattern_buffer *bufp; - const char *string_arg; - int size, pos, beg; - struct re_registers *regs; -{ - register unsigned char *p = (unsigned char*)bufp->buffer; - unsigned char *p1; - - /* Pointer to beyond end of buffer. */ - register unsigned char *pend = p + bufp->used; - - unsigned num_regs = bufp->re_nsub; - - unsigned char *string = (unsigned char*)string_arg; - - register unsigned char *d, *dend; - register int mcnt; /* Multipurpose. */ - int options = bufp->options; - - /* Failure point stack. Each place that can handle a failure further - down the line pushes a failure point on this stack. It consists of - restart, regend, and reg_info for all registers corresponding to the - subexpressions we're currently inside, plus the number of such - registers, and, finally, two char *'s. The first char * is where to - resume scanning the pattern; the second one is where to resume - scanning the strings. If the latter is zero, the failure point is a - ``dummy''; if a failure happens and the failure point is a dummy, it - gets discarded and the next next one is tried. */ - - unsigned char **stacka; - unsigned char **stackb; - unsigned char **stackp; - unsigned char **stacke; - - /* Information on the contents of registers. These are pointers into - the input strings; they record just what was matched (on this - attempt) by a subexpression part of the pattern, that is, the - regnum-th regstart pointer points to where in the pattern we began - matching and the regnum-th regend points to right after where we - stopped matching the regnum-th subexpression. (The zeroth register - keeps track of what the whole pattern matches.) */ - - unsigned char **regstart = bufp->regstart; - unsigned char **regend = bufp->regend; - - /* If a group that's operated upon by a repetition operator fails to - match anything, then the register for its start will need to be - restored because it will have been set to wherever in the string we - are when we last see its open-group operator. Similarly for a - register's end. */ - unsigned char **old_regstart = bufp->old_regstart; - unsigned char **old_regend = bufp->old_regend; - - /* The is_active field of reg_info helps us keep track of which (possibly - nested) subexpressions we are currently in. The matched_something - field of reg_info[reg_num] helps us tell whether or not we have - matched any of the pattern so far this time through the reg_num-th - subexpression. These two fields get reset each time through any - loop their register is in. */ - - register_info_type *reg_info = bufp->reg_info; - - /* The following record the register info as found in the above - variables when we find a match better than any we've seen before. - This happens as we backtrack through the failure points, which in - turn happens only if we have not yet matched the entire string. */ - - unsigned best_regs_set = 0; - unsigned char **best_regstart = bufp->best_regstart; - unsigned char **best_regend = bufp->best_regend; - - int num_failure_counts = 0; - - if (regs) { - init_regs(regs, num_regs); - } - - /* Initialize the stack. */ - stacka = RE_TALLOC(MAX_NUM_FAILURE_ITEMS * NFAILURES, unsigned char*); - stackb = stacka; - stackp = stackb; - stacke = &stackb[MAX_NUM_FAILURE_ITEMS * NFAILURES]; - -#ifdef DEBUG_REGEX - fprintf(stderr, "Entering re_match(%s)\n", string_arg); -#endif - - /* Initialize subexpression text positions to -1 to mark ones that no - ( or ( and ) or ) has been seen for. Also set all registers to - inactive and mark them as not having matched anything or ever - failed. */ - for (mcnt = 0; mcnt < num_regs; mcnt++) { - regstart[mcnt] = regend[mcnt] - = old_regstart[mcnt] = old_regend[mcnt] - = best_regstart[mcnt] = best_regend[mcnt] = REG_UNSET_VALUE; -#ifdef __CHECKER__ - reg_info[mcnt].word = 0; -#endif - IS_ACTIVE (reg_info[mcnt]) = 0; - MATCHED_SOMETHING (reg_info[mcnt]) = 0; - } - - /* Set up pointers to ends of strings. - Don't allow the second string to be empty unless both are empty. */ - - - /* `p' scans through the pattern as `d' scans through the data. `dend' - is the end of the input string that `d' points within. `d' is - advanced into the following input string whenever necessary, but - this happens before fetching; therefore, at the beginning of the - loop, `d' can be pointing at the end of a string, but it cannot - equal string2. */ - - d = string + pos, dend = string + size; - - /* This loops over pattern commands. It exits by returning from the - function if match is complete, or it drops through if match fails - at this starting point in the input data. */ - - for (;;) { -#ifdef DEBUG_REGEX - fprintf(stderr, - "regex loop(%d): matching 0x%02d\n", - p - (unsigned char*)bufp->buffer, - *p); -#endif - /* End of pattern means we might have succeeded. */ - if (p == pend) { - /* If not end of string, try backtracking. Otherwise done. */ - if ((bufp->options & RE_OPTION_LONGEST) && d != dend) { - if (best_regs_set) /* non-greedy, no need to backtrack */ - goto restore_best_regs; - while (stackp != stackb && stackp[-1] == NON_GREEDY) { - if (best_regs_set) /* non-greedy, no need to backtrack */ - goto restore_best_regs; - POP_FAILURE_POINT(); - } - if (stackp != stackb) { - /* More failure points to try. */ - - /* If exceeds best match so far, save it. */ - if (! best_regs_set || (d > best_regend[0])) { - best_regs_set = 1; - best_regend[0] = d; /* Never use regstart[0]. */ - - for (mcnt = 1; mcnt < num_regs; mcnt++) { - best_regstart[mcnt] = regstart[mcnt]; - best_regend[mcnt] = regend[mcnt]; - } - } - goto fail; - } - /* If no failure points, don't restore garbage. */ - else if (best_regs_set) { - restore_best_regs: - /* Restore best match. */ - d = best_regend[0]; - - for (mcnt = 0; mcnt < num_regs; mcnt++) { - regstart[mcnt] = best_regstart[mcnt]; - regend[mcnt] = best_regend[mcnt]; - } - } - } - - /* If caller wants register contents data back, convert it - to indices. */ - if (regs) { - regs->beg[0] = pos; - regs->end[0] = d - string; - for (mcnt = 1; mcnt < num_regs; mcnt++) { - if (REG_UNSET(regend[mcnt])) { - regs->beg[mcnt] = -1; - regs->end[mcnt] = -1; - continue; - } - regs->beg[mcnt] = regstart[mcnt] - string; - regs->end[mcnt] = regend[mcnt] - string; - } - } - FREE_AND_RETURN(stackb, (d - pos - string)); - } - - /* Otherwise match next pattern command. */ -#ifdef SWITCH_ENUM_BUG - switch ((int)((enum regexpcode)*p++)) -#else - switch ((enum regexpcode)*p++) -#endif - { - /* ( [or `(', as appropriate] is represented by start_memory, - ) by stop_memory. Both of those commands are followed by - a register number in the next byte. The text matched - within the ( and ) is recorded under that number. */ - case start_memory: - old_regstart[*p] = regstart[*p]; - regstart[*p] = d; - IS_ACTIVE(reg_info[*p]) = 1; - MATCHED_SOMETHING(reg_info[*p]) = 0; - p += 2; - continue; - - case stop_memory: - old_regend[*p] = regend[*p]; - regend[*p] = d; - IS_ACTIVE(reg_info[*p]) = 0; - p += 2; - continue; - - case start_paren: - case stop_paren: - break; - - /* \ has been turned into a `duplicate' command which is - followed by the numeric value of as the register number. */ - case duplicate: - { - int regno = *p++; /* Get which register to match against */ - register unsigned char *d2, *dend2; - - /* Check if there's corresponding group */ - if (regno >= num_regs) goto fail; - /* Check if corresponding group is still open */ - if (IS_ACTIVE(reg_info[regno])) goto fail; - - /* Where in input to try to start matching. */ - d2 = regstart[regno]; - if (REG_UNSET(d2)) goto fail; - - /* Where to stop matching; if both the place to start and - the place to stop matching are in the same string, then - set to the place to stop, otherwise, for now have to use - the end of the first string. */ - - dend2 = regend[regno]; - if (REG_UNSET(dend2)) goto fail; - for (;;) { - /* At end of register contents => success */ - if (d2 == dend2) break; - - /* If necessary, advance to next segment in data. */ - PREFETCH; - - /* How many characters left in this segment to match. */ - mcnt = dend - d; - - /* Want how many consecutive characters we can match in - one shot, so, if necessary, adjust the count. */ - if (mcnt > dend2 - d2) - mcnt = dend2 - d2; - - /* Compare that many; failure if mismatch, else move - past them. */ - if ((options & RE_OPTION_IGNORECASE) - ? memcmp_translate(d, d2, mcnt) - : memcmp((char*)d, (char*)d2, mcnt)) - goto fail; - d += mcnt, d2 += mcnt; - } - } - break; - - case start_nowidth: - PUSH_FAILURE_POINT(0, d); - if (stackp - stackb > RE_DUP_MAX) { - FREE_AND_RETURN(stackb,(-2)); - } - EXTRACT_NUMBER_AND_INCR(mcnt, p); - STORE_NUMBER(p+mcnt, stackp - stackb); - continue; - - case stop_nowidth: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - stackp = stackb + mcnt; - d = stackp[-3]; - POP_FAILURE_POINT(); - continue; - - case stop_backtrack: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - stackp = stackb + mcnt; - POP_FAILURE_POINT(); - continue; - - case pop_and_fail: - EXTRACT_NUMBER(mcnt, p+1); - stackp = stackb + mcnt; - POP_FAILURE_POINT(); - goto fail; - - case anychar: - PREFETCH; - if (ismbchar(*d)) { - if (d + mbclen(*d) > dend) - goto fail; - SET_REGS_MATCHED; - d += mbclen(*d); - break; - } - if (!(options&RE_OPTION_MULTILINE) - && (TRANSLATE_P() ? translate[*d] : *d) == '\n') - goto fail; - SET_REGS_MATCHED; - d++; - break; - - case anychar_repeat: - for (;;) { - PUSH_FAILURE_POINT(p, d); - PREFETCH; - if (ismbchar(*d)) { - if (d + mbclen(*d) > dend) - goto fail; - SET_REGS_MATCHED; - d += mbclen(*d); - continue; - } - if (!(options&RE_OPTION_MULTILINE) && - (TRANSLATE_P() ? translate[*d] : *d) == '\n') - goto fail; - SET_REGS_MATCHED; - d++; - } - break; - - case charset: - case charset_not: - { - int not; /* Nonzero for charset_not. */ - int part = 0; /* true if matched part of mbc */ - unsigned char *dsave = d + 1; - int cc, c; - - PREFETCH; - c = (unsigned char)*d++; - if (ismbchar(c)) { - if (d + mbclen(c) - 1 <= dend) { - cc = c; - MBC2WC(c, d); - not = is_in_list_mbc(c, p); - if (!not) { - part = not = is_in_list_sbc(cc, p); - } - } else { - not = is_in_list(c, p); - } - } - else { - if (TRANSLATE_P()) - c = (unsigned char)translate[c]; - not = is_in_list(c, p); - } - - if (*(p - 1) == (unsigned char)charset_not) { - not = !not; - } - if (!not) goto fail; - - p += 1 + *p + 2 + EXTRACT_UNSIGNED(&p[1 + *p])*8; - SET_REGS_MATCHED; - - if (part) d = dsave; - break; - } - - case begline: - if (size == 0 || AT_STRINGS_BEG(d)) - break; - if (d[-1] == '\n' && !AT_STRINGS_END(d)) - break; - goto fail; - - case endline: - if (AT_STRINGS_END(d)) { - break; - } - else if (*d == '\n') - break; - goto fail; - - /* Match at the very beginning of the string. */ - case begbuf: - if (AT_STRINGS_BEG(d)) - break; - goto fail; - - /* Match at the very end of the data. */ - case endbuf: - if (AT_STRINGS_END(d)) - break; - goto fail; - - /* Match at the very end of the data. */ - case endbuf2: - if (AT_STRINGS_END(d)) { - break; - } - /* .. or newline just before the end of the data. */ - if (*d == '\n' && AT_STRINGS_END(d+1)) - break; - goto fail; - - /* `or' constructs are handled by starting each alternative with - an on_failure_jump that points to the start of the next - alternative. Each alternative except the last ends with a - jump to the joining point. (Actually, each jump except for - the last one really jumps to the following jump, because - tensioning the jumps is a hassle.) */ - - /* The start of a stupid repeat has an on_failure_jump that points - past the end of the repeat text. This makes a failure point so - that on failure to match a repetition, matching restarts past - as many repetitions have been found with no way to fail and - look for another one. */ - - /* A smart repeat is similar but loops back to the on_failure_jump - so that each repetition makes another failure point. */ - - /* Match at the starting position. */ - case begpos: - if (d - string == beg) - break; - goto fail; - - case on_failure_jump: - on_failure: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - PUSH_FAILURE_POINT(p + mcnt, d); - continue; - - /* The end of a smart repeat has a maybe_finalize_jump back. - Change it either to a finalize_jump or an ordinary jump. */ - case maybe_finalize_jump: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - p1 = p; - - /* Compare the beginning of the repeat with what in the - pattern follows its end. If we can establish that there - is nothing that they would both match, i.e., that we - would have to backtrack because of (as in, e.g., `a*a') - then we can change to finalize_jump, because we'll - never have to backtrack. - - This is not true in the case of alternatives: in - `(a|ab)*' we do need to backtrack to the `ab' alternative - (e.g., if the string was `ab'). But instead of trying to - detect that here, the alternative has put on a dummy - failure point which is what we will end up popping. */ - - /* Skip over open/close-group commands. */ - while (p1 + 2 < pend) { - if ((enum regexpcode)*p1 == stop_memory || - (enum regexpcode)*p1 == start_memory) - p1 += 3; /* Skip over args, too. */ - else if (/*(enum regexpcode)*p1 == start_paren ||*/ - (enum regexpcode)*p1 == stop_paren) - p1 += 1; - else - break; - } - - if (p1 == pend) - p[-3] = (unsigned char)finalize_jump; - else if (*p1 == (unsigned char)exactn || - *p1 == (unsigned char)endline) { - register int c = *p1 == (unsigned char)endline ? '\n' : p1[2]; - register unsigned char *p2 = p + mcnt; - /* p2[0] ... p2[2] are an on_failure_jump. - Examine what follows that. */ - if (p2[3] == (unsigned char)exactn && p2[5] != c) - p[-3] = (unsigned char)finalize_jump; - else if (p2[3] == (unsigned char)charset || - p2[3] == (unsigned char)charset_not) { - int not; - if (ismbchar(c)) { - unsigned char *pp = p1+3; - MBC2WC(c, pp); - } - /* `is_in_list()' is TRUE if c would match */ - /* That means it is not safe to finalize. */ - not = is_in_list(c, p2 + 4); - if (p2[3] == (unsigned char)charset_not) - not = !not; - if (!not) - p[-3] = (unsigned char)finalize_jump; - } - } - p -= 2; /* Point at relative address again. */ - if (p[-1] != (unsigned char)finalize_jump) { - p[-1] = (unsigned char)jump; - goto nofinalize; - } - /* Note fall through. */ - - /* The end of a stupid repeat has a finalize_jump back to the - start, where another failure point will be made which will - point to after all the repetitions found so far. */ - - /* Take off failure points put on by matching on_failure_jump - because didn't fail. Also remove the register information - put on by the on_failure_jump. */ - case finalize_jump: - if (stackp > stackb && stackp[-3] == d) { - p = stackp[-4]; - POP_FAILURE_POINT(); - continue; - } - POP_FAILURE_POINT(); - /* Note fall through. */ - - /* We need this opcode so we can detect where alternatives end - in `group_match_null_string_p' et al. */ - case jump_past_alt: - /* fall through */ - - /* Jump without taking off any failure points. */ - case jump: - nofinalize: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - if (mcnt < 0 && stackp > stackb && stackp[-3] == d) /* avoid infinite loop */ - goto fail; - p += mcnt; - continue; - - case dummy_failure_jump: - /* Normally, the on_failure_jump pushes a failure point, which - then gets popped at finalize_jump. We will end up at - finalize_jump, also, and with a pattern of, say, `a+', we - are skipping over the on_failure_jump, so we have to push - something meaningless for finalize_jump to pop. */ - PUSH_FAILURE_POINT(0, 0); - goto nofinalize; - - /* At the end of an alternative, we need to push a dummy failure - point in case we are followed by a `finalize_jump', because - we don't want the failure point for the alternative to be - popped. For example, matching `(a|ab)*' against `aab' - requires that we match the `ab' alternative. */ - case push_dummy_failure: - /* See comments just above at `dummy_failure_jump' about the - two zeroes. */ - p1 = p; - /* Skip over open/close-group commands. */ - while (p1 + 2 < pend) { - if ((enum regexpcode)*p1 == stop_memory || - (enum regexpcode)*p1 == start_memory) - p1 += 3; /* Skip over args, too. */ - else if (/*(enum regexpcode)*p1 == start_paren ||*/ - (enum regexpcode)*p1 == stop_paren) - p1 += 1; - else - break; - } - if (p1 < pend && (enum regexpcode)*p1 == jump) - p[-1] = unused; - else - PUSH_FAILURE_POINT(0, 0); - break; - - /* Have to succeed matching what follows at least n times. Then - just handle like an on_failure_jump. */ - case succeed_n: - EXTRACT_NUMBER(mcnt, p + 2); - /* Originally, this is how many times we HAVE to succeed. */ - if (mcnt != 0) { - mcnt--; - p += 2; - PUSH_FAILURE_COUNT(p); - STORE_NUMBER_AND_INCR(p, mcnt); - PUSH_FAILURE_POINT(0, 0); - } - else { - goto on_failure; - } - continue; - - case jump_n: - EXTRACT_NUMBER(mcnt, p + 2); - /* Originally, this is how many times we CAN jump. */ - if (mcnt) { - mcnt--; - PUSH_FAILURE_COUNT(p + 2); - STORE_NUMBER(p + 2, mcnt); - goto nofinalize; /* Do the jump without taking off - any failure points. */ - } - /* If don't have to jump any more, skip over the rest of command. */ - else - p += 4; - continue; - - case set_number_at: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - p1 = p + mcnt; - EXTRACT_NUMBER_AND_INCR(mcnt, p); - STORE_NUMBER(p1, mcnt); - continue; - - case try_next: - EXTRACT_NUMBER_AND_INCR(mcnt, p); - if (p + mcnt < pend) { - PUSH_FAILURE_POINT(p, d); - stackp[-1] = NON_GREEDY; - } - p += mcnt; - continue; - - case finalize_push: - POP_FAILURE_POINT(); - EXTRACT_NUMBER_AND_INCR(mcnt, p); - if (mcnt < 0 && stackp > stackb && stackp[-3] == d) /* avoid infinite loop */ - goto fail; - PUSH_FAILURE_POINT(p + mcnt, d); - stackp[-1] = NON_GREEDY; - continue; - - case finalize_push_n: - EXTRACT_NUMBER(mcnt, p + 2); - /* Originally, this is how many times we CAN jump. */ - if (mcnt) { - int pos, i; - - mcnt--; - STORE_NUMBER(p + 2, mcnt); - EXTRACT_NUMBER(pos, p); - EXTRACT_NUMBER(i, p+pos+5); - if (i > 0) goto nofinalize; - POP_FAILURE_POINT(); - EXTRACT_NUMBER_AND_INCR(mcnt, p); - PUSH_FAILURE_POINT(p + mcnt, d); - stackp[-1] = NON_GREEDY; - p += 2; /* skip n */ - } - /* If don't have to push any more, skip over the rest of command. */ - else - p += 4; - continue; - - /* Ignore these. Used to ignore the n of succeed_n's which - currently have n == 0. */ - case unused: - continue; - - case casefold_on: - options |= RE_OPTION_IGNORECASE; - continue; - - case casefold_off: - options &= ~RE_OPTION_IGNORECASE; - continue; - - case option_set: - options = *p++; - continue; - - case wordbound: - if (AT_STRINGS_BEG(d)) { - if (AT_STRINGS_END(d)) goto fail; - if (IS_A_LETTER(d)) break; - else goto fail; - } - if (AT_STRINGS_END(d)) { - if (PREV_IS_A_LETTER(d)) break; - else goto fail; - } - if (PREV_IS_A_LETTER(d) != IS_A_LETTER(d)) - break; - goto fail; - - case notwordbound: - if (AT_STRINGS_BEG(d)) { - if (IS_A_LETTER(d)) goto fail; - else break; - } - if (AT_STRINGS_END(d)) { - if (PREV_IS_A_LETTER(d)) goto fail; - else break; - } - if (PREV_IS_A_LETTER(d) != IS_A_LETTER(d)) - goto fail; - break; - - case wordbeg: - if (IS_A_LETTER(d) && (AT_STRINGS_BEG(d) || !PREV_IS_A_LETTER(d))) - break; - goto fail; - - case wordend: - if (!AT_STRINGS_BEG(d) && PREV_IS_A_LETTER(d) - && (!IS_A_LETTER(d) || AT_STRINGS_END(d))) - break; - goto fail; - - case wordchar: - PREFETCH; - if (!IS_A_LETTER(d)) - goto fail; - if (ismbchar(*d) && d + mbclen(*d) - 1 < dend) - d += mbclen(*d) - 1; - d++; - SET_REGS_MATCHED; - break; - - case notwordchar: - PREFETCH; - if (IS_A_LETTER(d)) - goto fail; - if (ismbchar(*d) && d + mbclen(*d) - 1 < dend) - d += mbclen(*d) - 1; - d++; - SET_REGS_MATCHED; - break; - - case exactn: - /* Match the next few pattern characters exactly. - mcnt is how many characters to match. */ - mcnt = *p++; - /* This is written out as an if-else so we don't waste time - testing `translate' inside the loop. */ - if (TRANSLATE_P()) { - do { - unsigned char c; - - PREFETCH; - if (*p == 0xff) { - p++; - if (!--mcnt - || AT_STRINGS_END(d) - || (unsigned char)*d++ != (unsigned char)*p++) - goto fail; - continue; - } - c = *d++; - if (ismbchar(c)) { - int n; - - if (c != (unsigned char)*p++) - goto fail; - for (n = mbclen(c) - 1; n > 0; n--) - if (!--mcnt /* redundant check if pattern was - compiled properly. */ - || AT_STRINGS_END(d) - || (unsigned char)*d++ != (unsigned char)*p++) - goto fail; - continue; - } - /* compiled code translation needed for ruby */ - if ((unsigned char)translate[c] != (unsigned char)translate[*p++]) - goto fail; - } - while (--mcnt); - } - else { - do { - PREFETCH; - if (*p == 0xff) {p++; mcnt--;} - if (*d++ != *p++) goto fail; - } - while (--mcnt); - } - SET_REGS_MATCHED; - break; - } -#ifdef RUBY - CHECK_INTS; -#endif - continue; /* Successfully executed one pattern command; keep going. */ - - /* Jump here if any matching operation fails. */ - fail: - if (stackp != stackb) { - /* A restart point is known. Restart there and pop it. */ - short last_used_reg, this_reg; - - /* If this failure point is from a dummy_failure_point, just - skip it. */ - if (stackp[-4] == 0 || (best_regs_set && stackp[-1] == NON_GREEDY)) { - POP_FAILURE_POINT(); - goto fail; - } - stackp--; /* discard greedy flag */ - options = (long)*--stackp; - d = *--stackp; - p = *--stackp; - /* Restore register info. */ - last_used_reg = (long)*--stackp; - - /* Make the ones that weren't saved -1 or 0 again. */ - for (this_reg = num_regs - 1; this_reg > last_used_reg; this_reg--) { - regend[this_reg] = REG_UNSET_VALUE; - regstart[this_reg] = REG_UNSET_VALUE; - IS_ACTIVE(reg_info[this_reg]) = 0; - MATCHED_SOMETHING(reg_info[this_reg]) = 0; - } - - /* And restore the rest from the stack. */ - for ( ; this_reg > 0; this_reg--) { - reg_info[this_reg].word = *--stackp; - regend[this_reg] = *--stackp; - regstart[this_reg] = *--stackp; - } - mcnt = (long)*--stackp; - while (mcnt--) { - POP_FAILURE_COUNT(); - } - if (p < pend) { - int is_a_jump_n = 0; - int failed_paren = 0; - - p1 = p; - /* If failed to a backwards jump that's part of a repetition - loop, need to pop this failure point and use the next one. */ - switch ((enum regexpcode)*p1) { - case jump_n: - case finalize_push_n: - is_a_jump_n = 1; - case maybe_finalize_jump: - case finalize_jump: - case finalize_push: - case jump: - p1++; - EXTRACT_NUMBER_AND_INCR(mcnt, p1); - - if (mcnt >= 0) break; /* should be backward jump */ - p1 += mcnt; - - if (( is_a_jump_n && (enum regexpcode)*p1 == succeed_n) || - (!is_a_jump_n && (enum regexpcode)*p1 == on_failure_jump)) { - if (failed_paren) { - p1++; - EXTRACT_NUMBER_AND_INCR(mcnt, p1); - PUSH_FAILURE_POINT(p1 + mcnt, d); - } - goto fail; - } - break; - default: - /* do nothing */; - } - } - } - else - break; /* Matching at this starting point really fails. */ - } - - if (best_regs_set) - goto restore_best_regs; - - FREE_AND_RETURN(stackb,(-1)); /* Failure to match. */ -} - - -static int -memcmp_translate(s1, s2, len) - unsigned char *s1, *s2; - register int len; -{ - register unsigned char *p1 = s1, *p2 = s2, c; - while (len) { - c = *p1++; - if (ismbchar(c)) { - int n; - - if (c != *p2++) return 1; - for (n = mbclen(c) - 1; n > 0; n--) - if (!--len || *p1++ != *p2++) - return 1; - } - else - if (translate[c] != translate[*p2++]) - return 1; - len--; - } - return 0; -} - -void -re_copy_registers(regs1, regs2) - struct re_registers *regs1, *regs2; -{ - int i; - - if (regs1 == regs2) return; - if (regs1->allocated == 0) { - regs1->beg = TMALLOC(regs2->num_regs, int); - regs1->end = TMALLOC(regs2->num_regs, int); - regs1->allocated = regs2->num_regs; - } - else if (regs1->allocated < regs2->num_regs) { - TREALLOC(regs1->beg, regs2->num_regs, int); - TREALLOC(regs1->end, regs2->num_regs, int); - regs1->allocated = regs2->num_regs; - } - for (i=0; inum_regs; i++) { - regs1->beg[i] = regs2->beg[i]; - regs1->end[i] = regs2->end[i]; - } - regs1->num_regs = regs2->num_regs; -} - -void -re_free_registers(regs) - struct re_registers *regs; -{ - if (regs->allocated == 0) return; - if (regs->beg) xfree(regs->beg); - if (regs->end) xfree(regs->end); -} - -/* Functions for multi-byte support. - Created for grep multi-byte extension Jul., 1993 by t^2 (Takahiro Tanimoto) - Last change: Jul. 9, 1993 by t^2 */ -static const unsigned char mbctab_ascii[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -static const unsigned char mbctab_euc[] = { /* 0xA1-0xFE */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, -}; - -static const unsigned char mbctab_sjis[] = { /* 0x81-0x9F,0xE0-0xFC */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 -}; - -static const unsigned char mbctab_sjis_trail[] = { /* 0x40-0x7E,0x80-0xFC */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 -}; - -static const unsigned char mbctab_utf8[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 0, 0, -}; - -const unsigned char *re_mbctab = mbctab_ascii; - -void -re_mbcinit(mbctype) - int mbctype; -{ - switch (mbctype) { - case MBCTYPE_ASCII: - re_mbctab = mbctab_ascii; - current_mbctype = MBCTYPE_ASCII; - break; - case MBCTYPE_EUC: - re_mbctab = mbctab_euc; - current_mbctype = MBCTYPE_EUC; - break; - case MBCTYPE_SJIS: - re_mbctab = mbctab_sjis; - current_mbctype = MBCTYPE_SJIS; - break; - case MBCTYPE_UTF8: - re_mbctab = mbctab_utf8; - current_mbctype = MBCTYPE_UTF8; - break; - } -} - -#define mbc_isfirst(t, c) (t)[(unsigned char)(c)] -#define mbc_len(t, c) ((t)[(unsigned char)(c)]+1) - -static unsigned int -asc_startpos(string, pos) - const char *string; - unsigned int pos; -{ - return pos; -} - -#define euc_islead(c) ((unsigned char)((c) - 0xa1) > 0xfe - 0xa1) -#define euc_mbclen(c) mbc_len(mbctab_euc, (c)) -static unsigned int -euc_startpos(string, pos) - const char *string; - unsigned int pos; -{ - unsigned int i = pos, w; - - while (i > 0 && !euc_islead(string[i])) { - --i; - } - if (i == pos || i + (w = euc_mbclen(string[i])) > pos) { - return i; - } - i += w; - return i + ((pos - i) & ~1); -} - -#define sjis_isfirst(c) mbc_isfirst(mbctab_sjis, (c)) -#define sjis_istrail(c) mbctab_sjis_trail[(unsigned char)(c)] -#define sjis_mbclen(c) mbc_len(mbctab_sjis, (c)) -static unsigned int -sjis_startpos(string, pos) - const char *string; - unsigned int pos; -{ - unsigned int i = pos, w; - - if (i > 0 && sjis_istrail(string[i])) { - do { - if (!sjis_isfirst(string[--i])) { - ++i; - break; - } - } while (i > 0); - } - if (i == pos || i + (w = sjis_mbclen(string[i])) > pos) { - return i; - } - i += w; - return i + ((pos - i) & ~1); -} - -#define utf8_islead(c) ((unsigned char)((c) & 0xc0) != 0x80) -#define utf8_mbclen(c) mbc_len(mbctab_utf8, (c)) -static unsigned int -utf8_startpos(string, pos) - const char *string; - unsigned int pos; -{ - unsigned int i = pos, w; - - while (i > 0 && !utf8_islead(string[i])) { - --i; - } - if (i == pos || i + (w = utf8_mbclen(string[i])) > pos) { - return i; - } - return i + w; -} - -/* - vi: sw=2 ts=8 - Local variables: - mode : C - c-file-style : "gnu" - tab-width : 8 - End : -*/ -- cgit v1.2.3