- laststart = b;
-
- /* We test `*p == '^' twice, instead of using an if
- statement, so we only need one BUF_PUSH. */
- BUF_PUSH (*p == '^' ? charset_not : charset);
- if (*p == '^')
- p++;
-
- /* Remember the first position in the bracket expression. */
- p1 = p;
-
- /* Push the number of bytes in the bitmap. */
- BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
-
- /* Clear the whole map. */
- bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
-
- /* charset_not matches newline according to a syntax bit. */
- if ((re_opcode_t) b[-2] == charset_not
- && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
- SET_LIST_BIT ('\n');
-
- /* Read in characters and ranges, setting map bits. */
- for (;;)
- {
- if (p == pend) return REG_EBRACK;
-
- PATFETCH (c);
-
- /* \ might escape characters inside [...] and [^...]. */
- if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
- {
- if (p == pend) return REG_EESCAPE;
-
- PATFETCH (c1);
- SET_LIST_BIT (c1);
- continue;
- }
-
- /* Could be the end of the bracket expression. If it's
- not (i.e., when the bracket expression is `[]' so
- far), the ']' character bit gets set way below. */
- if (c == ']' && p != p1 + 1)
- break;
-
- /* Look ahead to see if it's a range when the last thing
- was a character class. */
- if (had_char_class && c == '-' && *p != ']')
- return REG_ERANGE;
-
- /* Look ahead to see if it's a range when the last thing
- was a character: if this is a hyphen not at the
- beginning or the end of a list, then it's the range
- operator. */
- if (c == '-'
- && !(p - 2 >= pattern && p[-2] == '[')
- && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
- && *p != ']')
- {
- reg_errcode_t ret
- = compile_range (&p, pend, translate, syntax, b);
- if (ret != REG_NOERROR) return ret;
- }
-
- else if (p[0] == '-' && p[1] != ']')
- { /* This handles ranges made up of characters only. */
- reg_errcode_t ret;
-
- /* Move past the `-'. */
- PATFETCH (c1);
-
- ret = compile_range (&p, pend, translate, syntax, b);
- if (ret != REG_NOERROR) return ret;
- }
-
- /* See if we're at the beginning of a possible character
- class. */
-
- else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
- { /* Leave room for the null. */
- char str[CHAR_CLASS_MAX_LENGTH + 1];
-
- PATFETCH (c);
- c1 = 0;
-
- /* If pattern is `[[:'. */
- if (p == pend) return REG_EBRACK;
-
- for (;;)
- {
- PATFETCH (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 leave
- the leading `:' and `[' (but set bits for them). */
- if (c == ':' && *p == ']')
- {
- int ch;
- boolean is_alnum = STREQ (str, "alnum");
- boolean is_alpha = STREQ (str, "alpha");
- boolean is_blank = STREQ (str, "blank");
- boolean is_cntrl = STREQ (str, "cntrl");
- boolean is_digit = STREQ (str, "digit");
- boolean is_graph = STREQ (str, "graph");
- boolean is_lower = STREQ (str, "lower");
- boolean is_print = STREQ (str, "print");
- boolean is_punct = STREQ (str, "punct");
- boolean is_space = STREQ (str, "space");
- boolean is_upper = STREQ (str, "upper");
- boolean is_xdigit = STREQ (str, "xdigit");
-
- if (!IS_CHAR_CLASS (str)) return REG_ECTYPE;
-
- /* Throw away the ] at the end of the character
- class. */
- PATFETCH (c);
-
- if (p == pend) return REG_EBRACK;
-
- 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 = true;
- }
- else
- {
- c1++;
- while (c1--)
- PATUNFETCH;
- SET_LIST_BIT ('[');
- SET_LIST_BIT (':');
- had_char_class = false;
- }
- }
- else
- {
- had_char_class = false;
- SET_LIST_BIT (c);
- }
- }
-
- /* Discard any (non)matching list bytes that are all 0 at the
- end of the map. Decrease the map-length byte too. */
- while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
- b[-1]--;
- b += b[-1];
- }
- break;
+ laststart = b;
+
+ /* We test `*p == '^' twice, instead of using an if
+ statement, so we only need one BUF_PUSH. */
+ BUF_PUSH (*p == '^' ? charset_not : charset);
+ if (*p == '^')
+ p++;
+
+ /* Remember the first position in the bracket expression. */
+ p1 = p;
+
+ /* Push the number of bytes in the bitmap. */
+ BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+
+ /* Clear the whole map. */
+ bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
+
+ /* charset_not matches newline according to a syntax bit. */
+ if ((re_opcode_t) b[-2] == charset_not
+ && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
+ SET_LIST_BIT ('\n');
+
+ /* Read in characters and ranges, setting map bits. */
+ for (;;)
+ {
+ boolean escaped_char = false;
+ const unsigned char *p2 = p;
+
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ PATFETCH (c);
+
+ /* \ might escape characters inside [...] and [^...]. */
+ if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
+ {
+ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+ PATFETCH (c);
+ escaped_char = true;
+ }
+ else
+ {
+ /* Could be the end of the bracket expression. If it's
+ not (i.e., when the bracket expression is `[]' so
+ far), the ']' character bit gets set way below. */
+ if (c == ']' && p2 != p1)
+ break;
+ }
+
+ /* What should we do for the character which is
+ greater than 0x7F, but not BASE_LEADING_CODE_P?
+ XXX */
+
+ /* See if we're at the beginning of a possible character
+ class. */
+
+ if (!escaped_char &&
+ syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
+ {
+ /* Leave room for the null. */
+ char str[CHAR_CLASS_MAX_LENGTH + 1];
+ const unsigned char *class_beg;
+
+ PATFETCH (c);
+ c1 = 0;
+ class_beg = p;
+
+ /* If pattern is `[[:'. */
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ for (;;)
+ {
+ PATFETCH (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
+ leave the leading `:' and `[' (but set bits for
+ them). */
+ if (c == ':' && *p == ']')
+ {
+ int ch;
+ boolean is_alnum = STREQ (str, "alnum");
+ boolean is_alpha = STREQ (str, "alpha");
+ boolean is_ascii = STREQ (str, "ascii");
+ boolean is_blank = STREQ (str, "blank");
+ boolean is_cntrl = STREQ (str, "cntrl");
+ boolean is_digit = STREQ (str, "digit");
+ boolean is_graph = STREQ (str, "graph");
+ boolean is_lower = STREQ (str, "lower");
+ boolean is_multibyte = STREQ (str, "multibyte");
+ boolean is_nonascii = STREQ (str, "nonascii");
+ boolean is_print = STREQ (str, "print");
+ boolean is_punct = STREQ (str, "punct");
+ boolean is_space = STREQ (str, "space");
+ boolean is_unibyte = STREQ (str, "unibyte");
+ boolean is_upper = STREQ (str, "upper");
+ boolean is_word = STREQ (str, "word");
+ boolean is_xdigit = STREQ (str, "xdigit");
+
+ if (!IS_CHAR_CLASS (str))
+ FREE_STACK_RETURN (REG_ECTYPE);
+
+ /* Throw away the ] at the end of the character
+ class. */
+ PATFETCH (c);
+
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ /* Most character classes in a multibyte match
+ just set a flag. Exceptions are is_blank,
+ is_digit, is_cntrl, and is_xdigit, since
+ they can only match ASCII characters. We
+ don't need to handle them for multibyte. */
+
+ if (multibyte)
+ {
+ int bit = 0;
+
+ if (is_alnum) bit = BIT_ALNUM;
+ if (is_alpha) bit = BIT_ALPHA;
+ if (is_ascii) bit = BIT_ASCII;
+ if (is_graph) bit = BIT_GRAPH;
+ if (is_lower) bit = BIT_LOWER;
+ if (is_multibyte) bit = BIT_MULTIBYTE;
+ if (is_nonascii) bit = BIT_NONASCII;
+ if (is_print) bit = BIT_PRINT;
+ if (is_punct) bit = BIT_PUNCT;
+ if (is_space) bit = BIT_SPACE;
+ if (is_unibyte) bit = BIT_UNIBYTE;
+ if (is_upper) bit = BIT_UPPER;
+ if (is_word) bit = BIT_WORD;
+ if (bit)
+ SET_RANGE_TABLE_WORK_AREA_BIT (range_table_work,
+ bit);
+ }
+
+ /* Handle character classes for ASCII characters. */
+ for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
+ {
+ int translated = TRANSLATE (ch);
+ /* This was split into 3 if's to
+ avoid an arbitrary limit in some compiler. */
+ if ( (is_alnum && ISALNUM (ch))
+ || (is_alpha && ISALPHA (ch))
+ || (is_blank && ISBLANK (ch))
+ || (is_cntrl && ISCNTRL (ch)))
+ SET_LIST_BIT (translated);
+ if ( (is_digit && ISDIGIT (ch))
+ || (is_graph && ISGRAPH (ch))
+ || (is_lower && ISLOWER (ch))
+ || (is_print && ISPRINT (ch)))
+ SET_LIST_BIT (translated);
+ if ( (is_punct && ISPUNCT (ch))
+ || (is_space && ISSPACE (ch))
+ || (is_upper && ISUPPER (ch))
+ || (is_xdigit && ISXDIGIT (ch)))
+ SET_LIST_BIT (translated);
+ if ( (is_ascii && IS_REAL_ASCII (ch))
+ || (is_nonascii && !IS_REAL_ASCII (ch))
+ || (is_unibyte && ISUNIBYTE (ch))
+ || (is_multibyte && !ISUNIBYTE (ch)))
+ SET_LIST_BIT (translated);
+
+ if ( (is_word && ISWORD (ch)))
+ SET_LIST_BIT (translated);
+ }
+
+ /* Repeat the loop. */
+ continue;
+ }
+ else
+ {
+ /* Go back to right after the "[:". */
+ p = class_beg;
+ SET_LIST_BIT ('[');
+
+ /* Because the `:' may starts the range, we
+ can't simply set bit and repeat the loop.
+ Instead, just set it to C and handle below. */
+ c = ':';
+ }
+ }
+
+ if (p < pend && p[0] == '-' && p[1] != ']')
+ {
+
+ /* Discard the `-'. */
+ PATFETCH (c1);
+
+ /* Fetch the character which ends the range. */
+ PATFETCH (c1);
+
+ if (SINGLE_BYTE_CHAR_P (c)
+ && ! SINGLE_BYTE_CHAR_P (c1))
+ {
+ /* Handle a range such as \177-\377 in multibyte mode.
+ Split that into two ranges,,
+ the low one ending at 0237, and the high one
+ starting at ...040. */
+ /* Unless I'm missing something,
+ this line is useless. -sm
+ int c1_base = (c1 & ~0177) | 040; */
+ SET_RANGE_TABLE_WORK_AREA (range_table_work, c, c1);
+ c1 = 0237;
+ }
+ else if (!SAME_CHARSET_P (c, c1))
+ FREE_STACK_RETURN (REG_ERANGE);
+ }
+ else
+ /* Range from C to C. */
+ c1 = c;
+
+ /* Set the range ... */
+ if (SINGLE_BYTE_CHAR_P (c))
+ /* ... into bitmap. */
+ {
+ unsigned this_char;
+ int range_start = c, range_end = c1;
+
+ /* If the start is after the end, the range is empty. */
+ if (range_start > range_end)
+ {
+ if (syntax & RE_NO_EMPTY_RANGES)
+ FREE_STACK_RETURN (REG_ERANGE);
+ /* Else, repeat the loop. */
+ }
+ else
+ {
+ for (this_char = range_start; this_char <= range_end;
+ this_char++)
+ SET_LIST_BIT (TRANSLATE (this_char));
+ }
+ }
+ else
+ /* ... into range table. */
+ SET_RANGE_TABLE_WORK_AREA (range_table_work, c, c1);
+ }
+
+ /* Discard any (non)matching list bytes that are all 0 at the
+ end of the map. Decrease the map-length byte too. */
+ while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
+ b[-1]--;
+ b += b[-1];
+
+ /* Build real range table from work area. */
+ if (RANGE_TABLE_WORK_USED (range_table_work)
+ || RANGE_TABLE_WORK_BITS (range_table_work))
+ {
+ int i;
+ int used = RANGE_TABLE_WORK_USED (range_table_work);
+
+ /* Allocate space for COUNT + RANGE_TABLE. Needs two
+ bytes for flags, two for COUNT, and three bytes for
+ each character. */
+ GET_BUFFER_SPACE (4 + used * 3);
+
+ /* Indicate the existence of range table. */
+ laststart[1] |= 0x80;
+
+ /* Store the character class flag bits into the range table.
+ If not in emacs, these flag bits are always 0. */
+ *b++ = RANGE_TABLE_WORK_BITS (range_table_work) & 0xff;
+ *b++ = RANGE_TABLE_WORK_BITS (range_table_work) >> 8;
+
+ STORE_NUMBER_AND_INCR (b, used / 2);
+ for (i = 0; i < used; i++)
+ STORE_CHARACTER_AND_INCR
+ (b, RANGE_TABLE_WORK_ELT (range_table_work, i));
+ }
+ }
+ break;