From 72bee015c74b7362d70765f7ac40e7b46c29d251 Mon Sep 17 00:00:00 2001 From: verhaegs Date: Sat, 17 Mar 2012 11:14:32 +0000 Subject: [PATCH] compiler/clib/regex: Switched to NetBSD version of the regex functions. These functions don't depend on functions in compiler/clib/locale allowing to reowrk locale support. Some netBSD peculiarities removed: * _DIAGASSERT() -> assert(), and define NDEBUG if !DEBUG * Don't incluce * Don't include "namespace.h" * u_int32_t -> uint32_t * __UNCONST(string) -> (char *)string git-svn-id: https://svn.aros.org/svn/aros/trunk/AROS@44417 fb15a70f-31f2-0310-bbcc-cdcc74a49acc --- compiler/clib/regex/COPYRIGHT | 8 +- compiler/clib/regex/Makefile.inc | 14 + compiler/clib/regex/WHATSNEW | 95 +++ compiler/clib/regex/cclass.h | 104 +++ compiler/clib/regex/cname.h | 237 ++++--- compiler/clib/regex/engine.c | 567 ++++++++------- compiler/clib/regex/re_format.7 | 299 ++++++++ compiler/clib/regex/regcomp.c | 1438 +++++++++++++++++++++----------------- compiler/clib/regex/regerror.c | 177 +++-- compiler/clib/regex/regex.3 | 628 +++++++++++++++++ compiler/clib/regex/regex2.h | 185 ++--- compiler/clib/regex/regexec.c | 181 ++--- compiler/clib/regex/regfree.c | 92 ++- compiler/clib/regex/utils.h | 41 +- 14 files changed, 2758 insertions(+), 1308 deletions(-) create mode 100644 compiler/clib/regex/Makefile.inc create mode 100644 compiler/clib/regex/WHATSNEW create mode 100644 compiler/clib/regex/cclass.h create mode 100644 compiler/clib/regex/re_format.7 create mode 100644 compiler/clib/regex/regex.3 diff --git a/compiler/clib/regex/COPYRIGHT b/compiler/clib/regex/COPYRIGHT index 574f6bcec6..f7a8f20c3b 100644 --- a/compiler/clib/regex/COPYRIGHT +++ b/compiler/clib/regex/COPYRIGHT @@ -1,3 +1,5 @@ +$NetBSD: COPYRIGHT,v 1.5 2003/08/07 16:43:19 agc Exp $ + Copyright 1992, 1993, 1994 Henry Spencer. All rights reserved. This software is not subject to any license of the American Telephone and Telegraph Company or of the Regents of the University of California. @@ -32,11 +34,7 @@ to the following restrictions: * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/compiler/clib/regex/Makefile.inc b/compiler/clib/regex/Makefile.inc new file mode 100644 index 0000000000..4dd74cf849 --- /dev/null +++ b/compiler/clib/regex/Makefile.inc @@ -0,0 +1,14 @@ +# $NetBSD: Makefile.inc,v 1.7 1997/11/14 02:04:46 mrg Exp $ +# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93 + +# regex sources +.PATH: ${.CURDIR}/regex + +CPPFLAGS+=-DPOSIX_MISTAKE + +SRCS+= regcomp.c regerror.c regexec.c regfree.c + +MAN+= regex.3 re_format.7 + +MLINKS+=regex.3 regcomp.3 regex.3 regexec.3 regex.3 regerror.3 \ + regex.3 regfree.3 diff --git a/compiler/clib/regex/WHATSNEW b/compiler/clib/regex/WHATSNEW new file mode 100644 index 0000000000..93eb936060 --- /dev/null +++ b/compiler/clib/regex/WHATSNEW @@ -0,0 +1,95 @@ +# $NetBSD: WHATSNEW,v 1.6 1995/02/27 13:28:25 cgd Exp $ +# @(#)WHATSNEW 8.3 (Berkeley) 3/18/94 + +New in alpha3.4: The complex bug alluded to below has been fixed (in a +slightly kludgey temporary way that may hurt efficiency a bit; this is +another "get it out the door for 4.4" release). The tests at the end of +the tests file have accordingly been uncommented. The primary sign of +the bug was that something like a?b matching ab matched b rather than ab. +(The bug was essentially specific to this exact situation, else it would +have shown up earlier.) + +New in alpha3.3: The definition of word boundaries has been altered +slightly, to more closely match the usual programming notion that "_" +is an alphabetic. Stuff used for pre-ANSI systems is now in a subdir, +and the makefile no longer alludes to it in mysterious ways. The +makefile has generally been cleaned up some. Fixes have been made +(again!) so that the regression test will run without -DREDEBUG, at +the cost of weaker checking. A workaround for a bug in some folks' + has been added. And some more things have been added to +tests, including a couple right at the end which are commented out +because the code currently flunks them (complex bug; fix coming). +Plus the usual minor cleanup. + +New in alpha3.2: Assorted bits of cleanup and portability improvement +(the development base is now a BSDI system using GCC instead of an ancient +Sun system, and the newer compiler exposed some glitches). Fix for a +serious bug that affected REs using many [] (including REG_ICASE REs +because of the way they are implemented), *sometimes*, depending on +memory-allocation patterns. The header-file prototypes no longer name +the parameters, avoiding possible name conflicts. The possibility that +some clot has defined CHAR_MIN as (say) `-128' instead of `(-128)' is +now handled gracefully. "uchar" is no longer used as an internal type +name (too many people have the same idea). Still the same old lousy +performance, alas. + +New in alpha3.1: Basically nothing, this release is just a bookkeeping +convenience. Stay tuned. + +New in alpha3.0: Performance is no better, alas, but some fixes have been +made and some functionality has been added. (This is basically the "get +it out the door in time for 4.4" release.) One bug fix: regfree() didn't +free the main internal structure (how embarrassing). It is now possible +to put NULs in either the RE or the target string, using (resp.) a new +REG_PEND flag and the old REG_STARTEND flag. The REG_NOSPEC flag to +regcomp() makes all characters ordinary, so you can match a literal +string easily (this will become more useful when performance improves!). +There are now primitives to match beginnings and ends of words, although +the syntax is disgusting and so is the implementation. The REG_ATOI +debugging interface has changed a bit. And there has been considerable +internal cleanup of various kinds. + +New in alpha2.3: Split change list out of README, and moved flags notes +into Makefile. Macro-ized the name of regex(7) in regex(3), since it has +to change for 4.4BSD. Cleanup work in engine.c, and some new regression +tests to catch tricky cases thereof. + +New in alpha2.2: Out-of-date manpages updated. Regerror() acquires two +small extensions -- REG_ITOA and REG_ATOI -- which avoid debugging kludges +in my own test program and might be useful to others for similar purposes. +The regression test will now compile (and run) without REDEBUG. The +BRE \$ bug is fixed. Most uses of "uchar" are gone; it's all chars now. +Char/uchar parameters are now written int/unsigned, to avoid possible +portability problems with unpromoted parameters. Some unsigned casts have +been introduced to minimize portability problems with shifting into sign +bits. + +New in alpha2.1: Lots of little stuff, cleanup and fixes. The one big +thing is that regex.h is now generated, using mkh, rather than being +supplied in the distribution; due to circularities in dependencies, +you have to build regex.h explicitly by "make h". The two known bugs +have been fixed (and the regression test now checks for them), as has a +problem with assertions not being suppressed in the absence of REDEBUG. +No performance work yet. + +New in alpha2: Backslash-anything is an ordinary character, not an +error (except, of course, for the handful of backslashed metacharacters +in BREs), which should reduce script breakage. The regression test +checks *where* null strings are supposed to match, and has generally +been tightened up somewhat. Small bug fixes in parameter passing (not +harmful, but technically errors) and some other areas. Debugging +invoked by defining REDEBUG rather than not defining NDEBUG. + +New in alpha+3: full prototyping for internal routines, using a little +helper program, mkh, which extracts prototypes given in stylized comments. +More minor cleanup. Buglet fix: it's CHAR_BIT, not CHAR_BITS. Simple +pre-screening of input when a literal string is known to be part of the +RE; this does wonders for performance. + +New in alpha+2: minor bits of cleanup. Notably, the number "32" for the +word width isn't hardwired into regexec.c any more, the public header +file prototypes the functions if __STDC__ is defined, and some small typos +in the manpages have been fixed. + +New in alpha+1: improvements to the manual pages, and an important +extension, the REG_STARTEND option to regexec(). diff --git a/compiler/clib/regex/cclass.h b/compiler/clib/regex/cclass.h new file mode 100644 index 0000000000..3ab2ccba47 --- /dev/null +++ b/compiler/clib/regex/cclass.h @@ -0,0 +1,104 @@ +/* $NetBSD: cclass.h,v 1.7 2003/08/07 16:43:19 agc Exp $ */ + +/*- + * Copyright (c) 1992, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cclass.h 8.3 (Berkeley) 3/20/94 + */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cclass.h 8.3 (Berkeley) 3/20/94 + */ + +/* character-class table */ +static const struct cclass { + const char *name; + const char *chars; + const char *multis; +} cclasses[] = { + { "alnum", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789", "" }, + { "alpha", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", + "" }, + { "blank", " \t", "" }, + { "cntrl", "\007\b\t\n\v\f\r\1\2\3\4\5\6\16\17\20\21\22\23\24\ +\25\26\27\30\31\32\33\34\35\36\37\177", "" }, + { "digit", "0123456789", "" }, + { "graph", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + "" }, + { "lower", "abcdefghijklmnopqrstuvwxyz", + "" }, + { "print", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ +0123456789!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~ ", + "" }, + { "punct", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", + "" }, + { "space", "\t\n\v\f\r ", "" }, + { "upper", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "" }, + { "xdigit", "0123456789ABCDEFabcdef", + "" }, + { NULL, 0, "" } +}; diff --git a/compiler/clib/regex/cname.h b/compiler/clib/regex/cname.h index 19b4ddb4bb..4b9ef3919d 100644 --- a/compiler/clib/regex/cname.h +++ b/compiler/clib/regex/cname.h @@ -1,5 +1,6 @@ +/* $NetBSD: cname.h,v 1.7 2003/08/07 16:43:19 agc Exp $ */ + /*- - * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -14,6 +15,43 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cname.h 8.3 (Berkeley) 3/20/94 + */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -31,108 +69,107 @@ * SUCH DAMAGE. * * @(#)cname.h 8.3 (Berkeley) 3/20/94 - * $FreeBSD: src/lib/libc/regex/cname.h,v 1.4 2007/01/09 00:28:04 imp Exp $ */ /* character-name table */ -static struct cname { - char *name; +static const struct cname { + const char *name; char code; } cnames[] = { - {"NUL", '\0'}, - {"SOH", '\001'}, - {"STX", '\002'}, - {"ETX", '\003'}, - {"EOT", '\004'}, - {"ENQ", '\005'}, - {"ACK", '\006'}, - {"BEL", '\007'}, - {"alert", '\007'}, - {"BS", '\010'}, - {"backspace", '\b'}, - {"HT", '\011'}, - {"tab", '\t'}, - {"LF", '\012'}, - {"newline", '\n'}, - {"VT", '\013'}, - {"vertical-tab", '\v'}, - {"FF", '\014'}, - {"form-feed", '\f'}, - {"CR", '\015'}, - {"carriage-return", '\r'}, - {"SO", '\016'}, - {"SI", '\017'}, - {"DLE", '\020'}, - {"DC1", '\021'}, - {"DC2", '\022'}, - {"DC3", '\023'}, - {"DC4", '\024'}, - {"NAK", '\025'}, - {"SYN", '\026'}, - {"ETB", '\027'}, - {"CAN", '\030'}, - {"EM", '\031'}, - {"SUB", '\032'}, - {"ESC", '\033'}, - {"IS4", '\034'}, - {"FS", '\034'}, - {"IS3", '\035'}, - {"GS", '\035'}, - {"IS2", '\036'}, - {"RS", '\036'}, - {"IS1", '\037'}, - {"US", '\037'}, - {"space", ' '}, - {"exclamation-mark", '!'}, - {"quotation-mark", '"'}, - {"number-sign", '#'}, - {"dollar-sign", '$'}, - {"percent-sign", '%'}, - {"ampersand", '&'}, - {"apostrophe", '\''}, - {"left-parenthesis", '('}, - {"right-parenthesis", ')'}, - {"asterisk", '*'}, - {"plus-sign", '+'}, - {"comma", ','}, - {"hyphen", '-'}, - {"hyphen-minus", '-'}, - {"period", '.'}, - {"full-stop", '.'}, - {"slash", '/'}, - {"solidus", '/'}, - {"zero", '0'}, - {"one", '1'}, - {"two", '2'}, - {"three", '3'}, - {"four", '4'}, - {"five", '5'}, - {"six", '6'}, - {"seven", '7'}, - {"eight", '8'}, - {"nine", '9'}, - {"colon", ':'}, - {"semicolon", ';'}, - {"less-than-sign", '<'}, - {"equals-sign", '='}, - {"greater-than-sign", '>'}, - {"question-mark", '?'}, - {"commercial-at", '@'}, - {"left-square-bracket", '['}, - {"backslash", '\\'}, - {"reverse-solidus", '\\'}, - {"right-square-bracket",']'}, - {"circumflex", '^'}, - {"circumflex-accent", '^'}, - {"underscore", '_'}, - {"low-line", '_'}, - {"grave-accent", '`'}, - {"left-brace", '{'}, - {"left-curly-bracket", '{'}, - {"vertical-line", '|'}, - {"right-brace", '}'}, - {"right-curly-bracket", '}'}, - {"tilde", '~'}, - {"DEL", '\177'}, - {NULL, 0} + { "NUL", '\0' }, + { "SOH", '\001' }, + { "STX", '\002' }, + { "ETX", '\003' }, + { "EOT", '\004' }, + { "ENQ", '\005' }, + { "ACK", '\006' }, + { "BEL", '\007' }, + { "alert", '\007' }, + { "BS", '\010' }, + { "backspace", '\b' }, + { "HT", '\011' }, + { "tab", '\t' }, + { "LF", '\012' }, + { "newline", '\n' }, + { "VT", '\013' }, + { "vertical-tab", '\v' }, + { "FF", '\014' }, + { "form-feed", '\f' }, + { "CR", '\015' }, + { "carriage-return", '\r' }, + { "SO", '\016' }, + { "SI", '\017' }, + { "DLE", '\020' }, + { "DC1", '\021' }, + { "DC2", '\022' }, + { "DC3", '\023' }, + { "DC4", '\024' }, + { "NAK", '\025' }, + { "SYN", '\026' }, + { "ETB", '\027' }, + { "CAN", '\030' }, + { "EM", '\031' }, + { "SUB", '\032' }, + { "ESC", '\033' }, + { "IS4", '\034' }, + { "FS", '\034' }, + { "IS3", '\035' }, + { "GS", '\035' }, + { "IS2", '\036' }, + { "RS", '\036' }, + { "IS1", '\037' }, + { "US", '\037' }, + { "space", ' ' }, + { "exclamation-mark", '!' }, + { "quotation-mark", '"' }, + { "number-sign", '#' }, + { "dollar-sign", '$' }, + { "percent-sign", '%' }, + { "ampersand", '&' }, + { "apostrophe", '\'' }, + { "left-parenthesis", '(' }, + { "right-parenthesis", ')' }, + { "asterisk", '*' }, + { "plus-sign", '+' }, + { "comma", ',' }, + { "hyphen", '-' }, + { "hyphen-minus", '-' }, + { "period", '.' }, + { "full-stop", '.' }, + { "slash", '/' }, + { "solidus", '/' }, + { "zero", '0' }, + { "one", '1' }, + { "two", '2' }, + { "three", '3' }, + { "four", '4' }, + { "five", '5' }, + { "six", '6' }, + { "seven", '7' }, + { "eight", '8' }, + { "nine", '9' }, + { "colon", ':' }, + { "semicolon", ';' }, + { "less-than-sign", '<' }, + { "equals-sign", '=' }, + { "greater-than-sign", '>' }, + { "question-mark", '?' }, + { "commercial-at", '@' }, + { "left-square-bracket", '[' }, + { "backslash", '\\' }, + { "reverse-solidus", '\\' }, + { "right-square-bracket", ']' }, + { "circumflex", '^' }, + { "circumflex-accent", '^' }, + { "underscore", '_' }, + { "low-line", '_' }, + { "grave-accent", '`' }, + { "left-brace", '{' }, + { "left-curly-bracket", '{' }, + { "vertical-line", '|' }, + { "right-brace", '}' }, + { "right-curly-bracket", '}' }, + { "tilde", '~' }, + { "DEL", '\177' }, + { NULL, 0 }, }; diff --git a/compiler/clib/regex/engine.c b/compiler/clib/regex/engine.c index 4b176a9a10..cd677895e5 100644 --- a/compiler/clib/regex/engine.c +++ b/compiler/clib/regex/engine.c @@ -1,5 +1,6 @@ +/* $NetBSD: engine.c,v 1.21 2007/02/08 05:44:18 junyoung Exp $ */ + /*- - * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -14,7 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -33,8 +34,42 @@ * @(#)engine.c 8.5 (Berkeley) 3/20/94 */ -#include -__FBSDID("$FreeBSD: src/lib/libc/regex/engine.c,v 1.21 2007/05/25 12:44:58 delphij Exp $"); +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)engine.c 8.5 (Berkeley) 3/20/94 + */ /* * The matching engine and friends. This file is #included by regexec.c @@ -53,6 +88,7 @@ __FBSDID("$FreeBSD: src/lib/libc/regex/engine.c,v 1.21 2007/05/25 12:44:58 delph #define print sprint #define at sat #define match smat +#define nope snope #endif #ifdef LNAMES #define matcher lmatcher @@ -64,17 +100,7 @@ __FBSDID("$FreeBSD: src/lib/libc/regex/engine.c,v 1.21 2007/05/25 12:44:58 delph #define print lprint #define at lat #define match lmat -#endif -#ifdef MNAMES -#define matcher mmatcher -#define fast mfast -#define slow mslow -#define dissect mdissect -#define backref mbackref -#define step mstep -#define print mprint -#define at mat -#define match mmat +#define nope lnope #endif /* another structure passed up and down to avoid zillions of parameters */ @@ -92,7 +118,6 @@ struct match { states fresh; /* states for a fresh start */ states tmp; /* temporary */ states empty; /* empty set of states */ - mbstate_t mbs; /* multibyte conversion state */ }; /* ========= begin header generated by ./mkh ========= */ @@ -103,27 +128,27 @@ extern "C" { /* === engine.c === */ static int matcher(struct re_guts *g, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags); static const char *dissect(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst); -static const char *backref(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst, sopno lev, int); +static const char *backref(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst, sopno lev); static const char *fast(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst); static const char *slow(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst); -static states step(struct re_guts *g, sopno start, sopno stop, states bef, wint_t ch, states aft); -#define MAX_RECURSION 100 -#define BOL (OUT-1) -#define EOL (BOL-1) -#define BOLEOL (BOL-2) -#define NOTHING (BOL-3) -#define BOW (BOL-4) -#define EOW (BOL-5) -#define BADCHAR (BOL-6) -#define NONCHAR(c) ((c) <= OUT) +static states step(struct re_guts *g, sopno start, sopno stop, states bef, int ch, states aft); +#define BOL (OUT+1) +#define EOL (BOL+1) +#define BOLEOL (BOL+2) +#define NOTHING (BOL+3) +#define BOW (BOL+4) +#define EOW (BOL+5) +#define CODEMAX (BOL+5) /* highest code used */ +#define NONCHAR(c) ((c) > CHAR_MAX) +#define NNONCHAR (CODEMAX-CHAR_MAX) #ifdef REDEBUG -static void print(struct match *m, const char *caption, states st, int ch, FILE *d); +static void print(struct match *m, char *caption, states st, int ch, FILE *d); #endif #ifdef REDEBUG -static void at(struct match *m, const char *title, const char *start, const char *stop, sopno startst, sopno stopst); +static void at(struct match *m, char *title, char *start, char *stop, sopno startst, sopno stopst); #endif #ifdef REDEBUG -static const char *pchar(int ch); +static char *pchar(int ch); #endif #ifdef __cplusplus @@ -135,6 +160,7 @@ static const char *pchar(int ch); #define SP(t, s, c) print(m, t, s, c, stdout) #define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2) #define NOTE(str) { if (m->eflags®_TRACE) printf("=%s\n", (str)); } +static int nope = 0; #else #define SP(t, s, c) /* nothing */ #define AT(t, p1, p2, s1, s2) /* nothing */ @@ -143,39 +169,39 @@ static const char *pchar(int ch); /* - matcher - the actual matching engine - == static int matcher(struct re_guts *g, const char *string, \ + == static int matcher(struct re_guts *g, char *string, \ == size_t nmatch, regmatch_t pmatch[], int eflags); */ static int /* 0 success, REG_NOMATCH failure */ -matcher(struct re_guts *g, - const char *string, - size_t nmatch, - regmatch_t pmatch[], - int eflags) +matcher( + struct re_guts *g, + const char *string, + size_t nmatch, + regmatch_t pmatch[], + int eflags) { const char *endp; int i; struct match mv; struct match *m = &mv; - const char *dp = NULL; + const char *dp; const sopno gf = g->firststate+1; /* +1 for OEND */ const sopno gl = g->laststate; const char *start; const char *stop; - /* Boyer-Moore algorithms variables */ - const char *pp; - int cj, mj; - const char *mustfirst; - const char *mustlast; - int *matchjump; - int *charjump; + int error = 0; + + assert(g != NULL); + assert(string != NULL); + /* pmatch checked below */ /* simplify the situation where possible */ if (g->cflags®_NOSUB) nmatch = 0; if (eflags®_STARTEND) { - start = string + pmatch[0].rm_so; - stop = string + pmatch[0].rm_eo; + assert(pmatch != NULL); + start = string + (size_t)pmatch[0].rm_so; + stop = string + (size_t)pmatch[0].rm_eo; } else { start = string; stop = start + strlen(start); @@ -185,46 +211,12 @@ matcher(struct re_guts *g, /* prescreening; this does wonders for this rather slow code */ if (g->must != NULL) { - if (g->charjump != NULL && g->matchjump != NULL) { - mustfirst = g->must; - mustlast = g->must + g->mlen - 1; - charjump = g->charjump; - matchjump = g->matchjump; - pp = mustlast; - for (dp = start+g->mlen-1; dp < stop;) { - /* Fast skip non-matches */ - while (dp < stop && charjump[(int)*dp]) - dp += charjump[(int)*dp]; - - if (dp >= stop) - break; - - /* Greedy matcher */ - /* We depend on not being used for - * for strings of length 1 - */ - while (*--dp == *--pp && pp != mustfirst); - - if (*dp == *pp) - break; - - /* Jump to next possible match */ - mj = matchjump[pp - mustfirst]; - cj = charjump[(int)*dp]; - dp += (cj < mj ? mj : cj); - pp = mustlast; - } - if (pp != mustfirst) - return(REG_NOMATCH); - } else { - for (dp = start; dp < stop; dp++) - if (*dp == g->must[0] && - stop - dp >= g->mlen && - memcmp(dp, g->must, (size_t)g->mlen) == 0) - break; - if (dp == stop) /* we didn't find g->must */ - return(REG_NOMATCH); - } + for (dp = start; dp < stop; dp++) + if (*dp == g->must[0] && stop - dp >= g->mlen && + memcmp(dp, g->must, (size_t)g->mlen) == 0) + break; + if (dp == stop) /* we didn't find g->must */ + return(REG_NOMATCH); } /* match struct setup */ @@ -241,22 +233,13 @@ matcher(struct re_guts *g, SETUP(m->tmp); SETUP(m->empty); CLEAR(m->empty); - ZAPSTATE(&m->mbs); - - /* Adjust start according to moffset, to speed things up */ - if (g->moffset > -1) - start = ((dp - g->moffset) < start) ? start : dp - g->moffset; /* this loop does only one repetition except for backrefs */ for (;;) { endp = fast(m, start, stop, gf, gl); if (endp == NULL) { /* a miss */ - if (m->pmatch != NULL) - free((char *)m->pmatch); - if (m->lastpos != NULL) - free((char *)m->lastpos); - STATETEARDOWN(m); - return(REG_NOMATCH); + error = REG_NOMATCH; + goto done; } if (nmatch == 0 && !g->backrefs) break; /* no further info needed */ @@ -269,8 +252,7 @@ matcher(struct re_guts *g, if (endp != NULL) break; assert(m->coldp < m->endp); - m->coldp += XMBRTOWC(NULL, m->coldp, - m->endp - m->coldp, &m->mbs, 0); + m->coldp++; } if (nmatch == 1 && !g->backrefs) break; /* no further info needed */ @@ -280,25 +262,24 @@ matcher(struct re_guts *g, m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) * sizeof(regmatch_t)); if (m->pmatch == NULL) { - STATETEARDOWN(m); - return(REG_ESPACE); + error = REG_ESPACE; + goto done; } for (i = 1; i <= m->g->nsub; i++) - m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1; + m->pmatch[i].rm_so = m->pmatch[i].rm_eo = (regoff_t)-1; if (!g->backrefs && !(m->eflags®_BACKR)) { NOTE("dissecting"); dp = dissect(m, m->coldp, endp, gf, gl); } else { if (g->nplus > 0 && m->lastpos == NULL) m->lastpos = malloc((g->nplus+1) * - sizeof(const char *)); + sizeof(const char *)); if (g->nplus > 0 && m->lastpos == NULL) { - free(m->pmatch); - STATETEARDOWN(m); - return(REG_ESPACE); + error = REG_ESPACE; + goto done; } NOTE("backref dissect"); - dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0); + dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); } if (dp != NULL) break; @@ -316,12 +297,12 @@ matcher(struct re_guts *g, /* try it on a shorter possibility */ #ifndef NDEBUG for (i = 1; i <= m->g->nsub; i++) { - assert(m->pmatch[i].rm_so == -1); - assert(m->pmatch[i].rm_eo == -1); + assert(m->pmatch[i].rm_so == (regoff_t)-1); + assert(m->pmatch[i].rm_eo == (regoff_t)-1); } #endif NOTE("backoff dissect"); - dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0); + dp = backref(m, m->coldp, endp, gf, gl, (sopno)0); } assert(dp == NULL || dp == endp); if (dp != NULL) /* found a shorter one */ @@ -329,14 +310,13 @@ matcher(struct re_guts *g, /* despite initial appearances, there is no match here */ NOTE("false alarm"); - /* recycle starting later */ - start = m->coldp + XMBRTOWC(NULL, m->coldp, - stop - m->coldp, &m->mbs, 0); + start = m->coldp + 1; /* recycle starting later */ assert(start <= stop); } /* fill in the details if requested */ if (nmatch > 0) { + assert(pmatch != NULL); pmatch[0].rm_so = m->coldp - m->offp; pmatch[0].rm_eo = endp - m->offp; } @@ -346,17 +326,22 @@ matcher(struct re_guts *g, if (i <= m->g->nsub) pmatch[i] = m->pmatch[i]; else { - pmatch[i].rm_so = -1; - pmatch[i].rm_eo = -1; + pmatch[i].rm_so = (regoff_t)-1; + pmatch[i].rm_eo = (regoff_t)-1; } } - if (m->pmatch != NULL) - free((char *)m->pmatch); - if (m->lastpos != NULL) - free((char *)m->lastpos); +done: + if (m->pmatch != NULL) { + free(m->pmatch); + m->pmatch = NULL; + } + if (m->lastpos != NULL) { + free(m->lastpos); + m->lastpos = NULL; + } STATETEARDOWN(m); - return(0); + return error; } /* @@ -364,26 +349,33 @@ matcher(struct re_guts *g, == static const char *dissect(struct match *m, const char *start, \ == const char *stop, sopno startst, sopno stopst); */ -static const char * /* == stop (success) always */ -dissect(struct match *m, - const char *start, - const char *stop, - sopno startst, - sopno stopst) +static const char * /* == stop (success) always */ +dissect( + struct match *m, + const char *start, + const char *stop, + sopno startst, + sopno stopst) { int i; - sopno ss; /* start sop of current subRE */ - sopno es; /* end sop of current subRE */ - const char *sp; /* start of string matched by it */ - const char *stp; /* string matched by it cannot pass here */ - const char *rest; /* start of rest of string */ - const char *tail; /* string unmatched by rest of RE */ - sopno ssub; /* start sop of subsubRE */ - sopno esub; /* end sop of subsubRE */ - const char *ssp; /* start of string matched by subsubRE */ - const char *sep; /* end of string matched by subsubRE */ - const char *oldssp; /* previous ssp */ + sopno ss; /* start sop of current subRE */ + sopno es; /* end sop of current subRE */ + const char *sp; /* start of string matched by it */ + const char *stp; /* string matched by it cannot pass here */ + const char *rest; /* start of rest of string */ + const char *tail; /* string unmatched by rest of RE */ + sopno ssub; /* start sop of subsubRE */ + sopno esub; /* end sop of subsubRE */ + const char *ssp; /* start of string matched by subsubRE */ + const char *sep; /* end of string matched by subsubRE */ + const char *oldssp; /* previous ssp */ +#ifndef NDEBUG const char *dp; +#endif + + assert(m != NULL); + assert(start != NULL); + assert(stop != NULL); AT("diss", start, stop, startst, stopst); sp = start; @@ -408,7 +400,7 @@ dissect(struct match *m, assert(nope); break; case OCHAR: - sp += XMBRTOWC(NULL, sp, stop - start, &m->mbs, 0); + sp++; break; case OBOL: case OEOL: @@ -417,7 +409,7 @@ dissect(struct match *m, break; case OANY: case OANYOF: - sp += XMBRTOWC(NULL, sp, stop - start, &m->mbs, 0); + sp++; break; case OBACK_: case O_BACK: @@ -442,11 +434,13 @@ dissect(struct match *m, esub = es - 1; /* did innards match? */ if (slow(m, sp, rest, ssub, esub) != NULL) { - dp = dissect(m, sp, rest, ssub, esub); - assert(dp == rest); #ifdef NDEBUG - (void)(dp); /* Silence gcc 4.6.1 lint */ + (void) +#else + dp = #endif + dissect(m, sp, rest, ssub, esub); + assert(dp == rest); } else /* no */ assert(sp == rest); sp = rest; @@ -483,7 +477,12 @@ dissect(struct match *m, } assert(sep == rest); /* must exhaust substring */ assert(slow(m, ssp, sep, ssub, esub) == rest); - dp = dissect(m, ssp, sep, ssub, esub); +#ifdef NDEBUG + (void) +#else + dp = +#endif + dissect(m, ssp, sep, ssub, esub); assert(dp == sep); sp = rest; break; @@ -518,7 +517,12 @@ dissect(struct match *m, else assert(OP(m->g->strip[esub]) == O_CH); } - dp = dissect(m, sp, rest, ssub, esub); +#ifdef NDEBUG + (void) +#else + dp = +#endif + dissect(m, sp, rest, ssub, esub); assert(dp == rest); sp = rest; break; @@ -555,27 +559,30 @@ dissect(struct match *m, == const char *stop, sopno startst, sopno stopst, sopno lev); */ static const char * /* == stop (success) or NULL (failure) */ -backref(struct match *m, - const char *start, - const char *stop, - sopno startst, - sopno stopst, - sopno lev, /* PLUS nesting level */ - int rec) +backref( + struct match *m, + const char *start, + const char *stop, + sopno startst, + sopno stopst, + sopno lev) /* PLUS nesting level */ { int i; - sopno ss; /* start sop of current subRE */ - const char *sp; /* start of string matched by it */ - sopno ssub; /* start sop of subsubRE */ - sopno esub; /* end sop of subsubRE */ - const char *ssp; /* start of string matched by subsubRE */ + sopno ss; /* start sop of current subRE */ + const char *sp; /* start of string matched by it */ + sopno ssub; /* start sop of subsubRE */ + sopno esub; /* end sop of subsubRE */ + const char *ssp; /* start of string matched by subsubRE */ const char *dp; size_t len; int hard; sop s; regoff_t offsave; cset *cs; - wint_t wc; + + assert(m != NULL); + assert(start != NULL); + assert(stop != NULL); AT("back", start, stop, startst, stopst); sp = start; @@ -585,25 +592,17 @@ backref(struct match *m, for (ss = startst; !hard && ss < stopst; ss++) switch (OP(s = m->g->strip[ss])) { case OCHAR: - if (sp == stop) - return(NULL); - sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR); - if (wc != OPND(s)) + if (sp == stop || *sp++ != (char)OPND(s)) return(NULL); break; case OANY: if (sp == stop) return(NULL); - sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR); - if (wc == BADCHAR) - return (NULL); + sp++; break; case OANYOF: - if (sp == stop) - return (NULL); cs = &m->g->sets[OPND(s)]; - sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR); - if (wc == BADCHAR || !CHIN(cs, wc)) + if (sp == stop || !CHIN(cs, *sp++)) return(NULL); break; case OBOL: @@ -672,51 +671,50 @@ backref(struct match *m, case OBACK_: /* the vilest depths */ i = OPND(s); assert(0 < i && i <= m->g->nsub); - if (m->pmatch[i].rm_eo == -1) + if (m->pmatch[i].rm_eo == (regoff_t)-1) return(NULL); - assert(m->pmatch[i].rm_so != -1); - len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so; - if (len == 0 && rec++ > MAX_RECURSION) + assert(m->pmatch[i].rm_so != (regoff_t)-1); + len = (size_t)(m->pmatch[i].rm_eo - m->pmatch[i].rm_so); + if (len == 0) return(NULL); assert(stop - m->beginp >= len); if (sp > stop - len) return(NULL); /* not enough left to match */ - ssp = m->offp + m->pmatch[i].rm_so; + ssp = m->offp + (size_t)m->pmatch[i].rm_so; if (memcmp(sp, ssp, len) != 0) return(NULL); while (m->g->strip[ss] != SOP(O_BACK, i)) ss++; - return(backref(m, sp+len, stop, ss+1, stopst, lev, rec)); - break; + return(backref(m, sp+len, stop, ss+1, stopst, lev)); + case OQUEST_: /* to null or not */ - dp = backref(m, sp, stop, ss+1, stopst, lev, rec); + dp = backref(m, sp, stop, ss+1, stopst, lev); if (dp != NULL) return(dp); /* not */ - return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev, rec)); - break; + return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev)); + case OPLUS_: assert(m->lastpos != NULL); assert(lev+1 <= m->g->nplus); m->lastpos[lev+1] = sp; - return(backref(m, sp, stop, ss+1, stopst, lev+1, rec)); - break; + return(backref(m, sp, stop, ss+1, stopst, lev+1)); + case O_PLUS: if (sp == m->lastpos[lev]) /* last pass matched null */ - return(backref(m, sp, stop, ss+1, stopst, lev-1, rec)); + return(backref(m, sp, stop, ss+1, stopst, lev-1)); /* try another pass */ m->lastpos[lev] = sp; - dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev, rec); + dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev); if (dp == NULL) - return(backref(m, sp, stop, ss+1, stopst, lev-1, rec)); - else - return(dp); - break; + dp = backref(m, sp, stop, ss+1, stopst, lev-1); + return(dp); + case OCH_: /* find the right one, if any */ ssub = ss + 1; esub = ss + OPND(s) - 1; assert(OP(m->g->strip[esub]) == OOR1); for (;;) { /* find first matching branch */ - dp = backref(m, sp, stop, ssub, esub, lev, rec); + dp = backref(m, sp, stop, ssub, esub, lev); if (dp != NULL) return(dp); /* that one missed, try next one */ @@ -731,29 +729,29 @@ backref(struct match *m, else assert(OP(m->g->strip[esub]) == O_CH); } - break; + case OLPAREN: /* must undo assignment if rest fails */ i = OPND(s); assert(0 < i && i <= m->g->nsub); offsave = m->pmatch[i].rm_so; m->pmatch[i].rm_so = sp - m->offp; - dp = backref(m, sp, stop, ss+1, stopst, lev, rec); + dp = backref(m, sp, stop, ss+1, stopst, lev); if (dp != NULL) return(dp); m->pmatch[i].rm_so = offsave; return(NULL); - break; + case ORPAREN: /* must undo assignment if rest fails */ i = OPND(s); assert(0 < i && i <= m->g->nsub); offsave = m->pmatch[i].rm_eo; m->pmatch[i].rm_eo = sp - m->offp; - dp = backref(m, sp, stop, ss+1, stopst, lev, rec); + dp = backref(m, sp, stop, ss+1, stopst, lev); if (dp != NULL) return(dp); m->pmatch[i].rm_eo = offsave; return(NULL); - break; + default: /* uh oh */ assert(nope); break; @@ -762,7 +760,7 @@ backref(struct match *m, /* "can't happen" */ assert(nope); /* NOTREACHED */ - return "shut up gcc"; + return NULL; } /* @@ -771,22 +769,26 @@ backref(struct match *m, == const char *stop, sopno startst, sopno stopst); */ static const char * /* where tentative match ended, or NULL */ -fast( struct match *m, - const char *start, - const char *stop, - sopno startst, - sopno stopst) +fast( + struct match *m, + const char *start, + const char *stop, + sopno startst, + sopno stopst) { states st = m->st; states fresh = m->fresh; states tmp = m->tmp; const char *p = start; - wint_t c; - wint_t lastc; /* previous c */ - wint_t flagch; + int c = (start == m->beginp) ? OUT : *(start-1); + int lastc; /* previous c */ + int flagch; int i; - const char *coldp; /* last p after which no match was underway */ - size_t clen; + const char *coldp; /* last p after which no match was underway */ + + assert(m != NULL); + assert(start != NULL); + assert(stop != NULL); CLEAR(st); SET1(st, startst); @@ -794,24 +796,10 @@ fast( struct match *m, ASSIGN(fresh, st); SP("start", st, *p); coldp = NULL; - if (start == m->beginp) - c = OUT; - else { - /* - * XXX Wrong if the previous character was multi-byte. - * Newline never is (in encodings supported by FreeBSD), - * so this only breaks the ISWORD tests below. - */ - c = (uch)*(start - 1); - } for (;;) { /* next character */ lastc = c; - if (p == m->endp) { - clen = 0; - c = OUT; - } else - clen = XMBRTOWC(&c, p, m->endp - p, &m->mbs, BADCHAR); + c = (p == m->endp) ? OUT : *p; if (EQ(st, fresh)) coldp = p; @@ -849,7 +837,7 @@ fast( struct match *m, } /* are we done? */ - if (ISSET(st, stopst) || p == stop || clen > stop - p) + if (ISSET(st, stopst) || p == stop) break; /* NOTE BREAK OUT */ /* no, we must deal with this character */ @@ -859,13 +847,13 @@ fast( struct match *m, st = step(m->g, startst, stopst, tmp, c, st); SP("aft", st, c); assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st)); - p += clen; + p++; } assert(coldp != NULL); m->coldp = coldp; if (ISSET(st, stopst)) - return(p+XMBRTOWC(NULL, p, stop - p, &m->mbs, 0)); + return(p+1); else return(NULL); } @@ -875,23 +863,27 @@ fast( struct match *m, == static const char *slow(struct match *m, const char *start, \ == const char *stop, sopno startst, sopno stopst); */ -static const char * /* where it ended */ -slow( struct match *m, - const char *start, - const char *stop, - sopno startst, - sopno stopst) +static const char * /* where it ended */ +slow( + struct match *m, + const char *start, + const char *stop, + sopno startst, + sopno stopst) { states st = m->st; states empty = m->empty; states tmp = m->tmp; const char *p = start; - wint_t c; - wint_t lastc; /* previous c */ - wint_t flagch; + int c = (start == m->beginp) ? OUT : *(start-1); + int lastc; /* previous c */ + int flagch; int i; const char *matchp; /* last p at which a match ended */ - size_t clen; + + assert(m != NULL); + assert(start != NULL); + assert(stop != NULL); AT("slow", start, stop, startst, stopst); CLEAR(st); @@ -899,24 +891,10 @@ slow( struct match *m, SP("sstart", st, *p); st = step(m->g, startst, stopst, st, NOTHING, st); matchp = NULL; - if (start == m->beginp) - c = OUT; - else { - /* - * XXX Wrong if the previous character was multi-byte. - * Newline never is (in encodings supported by FreeBSD), - * so this only breaks the ISWORD tests below. - */ - c = (uch)*(start - 1); - } for (;;) { /* next character */ lastc = c; - if (p == m->endp) { - c = OUT; - clen = 0; - } else - clen = XMBRTOWC(&c, p, m->endp - p, &m->mbs, BADCHAR); + c = (p == m->endp) ? OUT : *p; /* is there an EOL and/or BOL between lastc and c? */ flagch = '\0'; @@ -954,7 +932,7 @@ slow( struct match *m, /* are we done? */ if (ISSET(st, stopst)) matchp = p; - if (EQ(st, empty) || p == stop || clen > stop - p) + if (EQ(st, empty) || p == stop) break; /* NOTE BREAK OUT */ /* no, we must deal with this character */ @@ -964,7 +942,7 @@ slow( struct match *m, st = step(m->g, startst, stopst, tmp, c, st); SP("saft", st, c); assert(EQ(step(m->g, startst, stopst, st, NOTHING, st), st)); - p += clen; + p++; } return(matchp); @@ -975,22 +953,24 @@ slow( struct match *m, - step - map set of states reachable before char to set reachable after == static states step(struct re_guts *g, sopno start, sopno stop, \ == states bef, int ch, states aft); - == #define BOL (OUT-1) - == #define EOL (BOL-1) - == #define BOLEOL (BOL-2) - == #define NOTHING (BOL-3) - == #define BOW (BOL-4) - == #define EOW (BOL-5) - == #define BADCHAR (BOL-6) - == #define NONCHAR(c) ((c) <= OUT) + == #define BOL (OUT+1) + == #define EOL (BOL+1) + == #define BOLEOL (BOL+2) + == #define NOTHING (BOL+3) + == #define BOW (BOL+4) + == #define EOW (BOL+5) + == #define CODEMAX (BOL+5) // highest code used + == #define NONCHAR(c) ((c) > CHAR_MAX) + == #define NNONCHAR (CODEMAX-CHAR_MAX) */ static states -step(struct re_guts *g, - sopno start, /* start state within strip */ - sopno stop, /* state after stop state within strip */ - states bef, /* states reachable before */ - wint_t ch, /* character or NONCHAR code */ - states aft) /* states already known reachable after */ +step( + struct re_guts *g, + sopno start, /* start state within strip */ + sopno stop, /* state after stop state within strip */ + states bef, /* states reachable before */ + int ch, /* character or NONCHAR code */ + states aft) /* states already known reachable after */ { cset *cs; sop s; @@ -999,6 +979,8 @@ step(struct re_guts *g, sopno look; int i; + assert(g != NULL); + for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) { s = g->strip[pc]; switch (OP(s)) { @@ -1007,8 +989,8 @@ step(struct re_guts *g, break; case OCHAR: /* only characters can match */ - assert(!NONCHAR(ch) || ch != OPND(s)); - if (ch == OPND(s)) + assert(!NONCHAR(ch) || ch != (char)OPND(s)); + if (ch == (char)OPND(s)) FWD(aft, bef, 1); break; case OBOL: @@ -1101,24 +1083,30 @@ step(struct re_guts *g, /* - print - print a set of states == #ifdef REDEBUG - == static void print(struct match *m, const char *caption, states st, \ + == static void print(struct match *m, char *caption, states st, \ == int ch, FILE *d); == #endif */ static void -print(struct match *m, - const char *caption, - states st, - int ch, - FILE *d) +print( + struct match *m, + char *caption, + states st, + int ch, + FILE *d) { struct re_guts *g = m->g; int i; int first = 1; + assert(m != NULL); + assert(caption != NULL); + if (!(m->eflags®_TRACE)) return; + assert(d != NULL); + fprintf(d, "%s", caption); if (ch != '\0') fprintf(d, " %s", pchar(ch)); @@ -1130,21 +1118,28 @@ print(struct match *m, fprintf(d, "\n"); } -/* +/* - at - print current situation == #ifdef REDEBUG - == static void at(struct match *m, const char *title, const char *start, \ - == const char *stop, sopno startst, sopno stopst); + == static void at(struct match *m, char *title, char *start, char *stop, \ + == sopno startst, sopno stopst); == #endif */ static void -at( struct match *m, - const char *title, - const char *start, - const char *stop, - sopno startst, - sopno stopst) +at( + struct match *m, + char *title, + char *start, + char *stop, + sopno startst, + sopno stopst) { + + assert(m != NULL); + assert(title != NULL); + assert(start != NULL); + assert(stop != NULL); + if (!(m->eflags®_TRACE)) return; @@ -1158,7 +1153,7 @@ at( struct match *m, /* - pchar - make a character printable == #ifdef REDEBUG - == static const char *pchar(int ch); + == static char *pchar(int ch); == #endif * * Is this identical to regchar() over in debug.c? Well, yes. But a @@ -1166,15 +1161,16 @@ at( struct match *m, * a matching debug.o, and this is convenient. It all disappears in * the non-debug compilation anyway, so it doesn't matter much. */ -static const char * /* -> representation */ -pchar(int ch) +static char * /* -> representation */ +pchar( + int ch) { static char pbuf[10]; - if (isprint((uch)ch) || ch == ' ') - sprintf(pbuf, "%c", ch); + if (isprint(ch) || ch == ' ') + (void)snprintf(pbuf, sizeof pbuf, "%c", ch); else - sprintf(pbuf, "\\%o", ch); + (void)snprintf(pbuf, sizeof pbuf, "\\%o", ch); return(pbuf); } #endif @@ -1189,3 +1185,4 @@ pchar(int ch) #undef print #undef at #undef match +#undef nope diff --git a/compiler/clib/regex/re_format.7 b/compiler/clib/regex/re_format.7 new file mode 100644 index 0000000000..7e43631c7c --- /dev/null +++ b/compiler/clib/regex/re_format.7 @@ -0,0 +1,299 @@ +.\" $NetBSD: re_format.7,v 1.8 2003/08/07 16:43:20 agc Exp $ +.\" +.\" Copyright (c) 1992, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Henry Spencer. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Copyright (c) 1992, 1993, 1994 Henry Spencer. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Henry Spencer. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)re_format.7 8.3 (Berkeley) 3/20/94 +.\" +.TH RE_FORMAT 7 "March 20, 1994" +.SH NAME +re_format \- POSIX 1003.2 regular expressions +.SH DESCRIPTION +Regular expressions (``RE''s), +as defined in POSIX 1003.2, come in two forms: +modern REs (roughly those of +.IR egrep ; +1003.2 calls these ``extended'' REs) +and obsolete REs (roughly those of +.IR ed ; +1003.2 ``basic'' REs). +Obsolete REs mostly exist for backward compatibility in some old programs; +they will be discussed at the end. +1003.2 leaves some aspects of RE syntax and semantics open; +`\(dg' marks decisions on these aspects that +may not be fully portable to other 1003.2 implementations. +.PP +A (modern) RE is one\(dg or more non-empty\(dg \fIbranches\fR, +separated by `|'. +It matches anything that matches one of the branches. +.PP +A branch is one\(dg or more \fIpieces\fR, concatenated. +It matches a match for the first, followed by a match for the second, etc. +.PP +A piece is an \fIatom\fR possibly followed +by a single\(dg `*', `+', `?', or \fIbound\fR. +An atom followed by `*' matches a sequence of 0 or more matches of the atom. +An atom followed by `+' matches a sequence of 1 or more matches of the atom. +An atom followed by `?' matches a sequence of 0 or 1 matches of the atom. +.PP +A \fIbound\fR is `{' followed by an unsigned decimal integer, +possibly followed by `,' +possibly followed by another unsigned decimal integer, +always followed by `}'. +The integers must lie between 0 and RE_DUP_MAX (255\(dg) inclusive, +and if there are two of them, the first may not exceed the second. +An atom followed by a bound containing one integer \fIi\fR +and no comma matches +a sequence of exactly \fIi\fR matches of the atom. +An atom followed by a bound +containing one integer \fIi\fR and a comma matches +a sequence of \fIi\fR or more matches of the atom. +An atom followed by a bound +containing two integers \fIi\fR and \fIj\fR matches +a sequence of \fIi\fR through \fIj\fR (inclusive) matches of the atom. +.PP +An atom is a regular expression enclosed in `()' (matching a match for the +regular expression), +an empty set of `()' (matching the null string)\(dg, +a \fIbracket expression\fR (see below), `.' +(matching any single character), `^' (matching the null string at the +beginning of a line), `$' (matching the null string at the +end of a line), a `\e' followed by one of the characters +`^.[$()|*+?{\e' +(matching that character taken as an ordinary character), +a `\e' followed by any other character\(dg +(matching that character taken as an ordinary character, +as if the `\e' had not been present\(dg), +or a single character with no other significance (matching that character). +A `{' followed by a character other than a digit is an ordinary +character, not the beginning of a bound\(dg. +It is illegal to end an RE with `\e'. +.PP +A \fIbracket expression\fR is a list of characters enclosed in `[]'. +It normally matches any single character from the list (but see below). +If the list begins with `^', +it matches any single character +(but see below) \fInot\fR from the rest of the list. +If two characters in the list are separated by `\-', this is shorthand +for the full \fIrange\fR of characters between those two (inclusive) in the +collating sequence, +e.g. `[0-9]' in ASCII matches any decimal digit. +It is illegal\(dg for two ranges to share an +endpoint, e.g. `a-c-e'. +Ranges are very collating-sequence-dependent, +and portable programs should avoid relying on them. +.PP +To include a literal `]' in the list, make it the first character +(following a possible `^'). +To include a literal `\-', make it the first or last character, +or the second endpoint of a range. +To use a literal `\-' as the first endpoint of a range, +enclose it in `[.' and `.]' to make it a collating element (see below). +With the exception of these and some combinations using `[' (see next +paragraphs), all other special characters, including `\e', lose their +special significance within a bracket expression. +.PP +Within a bracket expression, a collating element (a character, +a multi-character sequence that collates as if it were a single character, +or a collating-sequence name for either) +enclosed in `[.' and `.]' stands for the +sequence of characters of that collating element. +The sequence is a single element of the bracket expression's list. +A bracket expression containing a multi-character collating element +can thus match more than one character, +e.g. if the collating sequence includes a `ch' collating element, +then the RE `[[.ch.]]*c' matches the first five characters +of `chchcc'. +.PP +Within a bracket expression, a collating element enclosed in `[=' and +`=]' is an equivalence class, standing for the sequences of characters +of all collating elements equivalent to that one, including itself. +(If there are no other equivalent collating elements, +the treatment is as if the enclosing delimiters were `[.' and `.]'.) +For example, if o and \o'o^' are the members of an equivalence class, +then `[[=o=]]', `[[=\o'o^'=]]', and `[o\o'o^']' are all synonymous. +An equivalence class may not\(dg be an endpoint +of a range. +.PP +Within a bracket expression, the name of a \fIcharacter class\fR enclosed +in `[:' and `:]' stands for the list of all characters belonging to that +class. +Standard character class names are: +.PP +.RS +.nf +.ta 3c 6c 9c +alnum digit punct +alpha graph space +blank lower upper +cntrl print xdigit +.fi +.RE +.PP +These stand for the character classes defined in +.IR ctype (3). +A locale may provide others. +A character class may not be used as an endpoint of a range. +.PP +There are two special cases\(dg of bracket expressions: +the bracket expressions `[[:\*[Lt]:]]' and `[[:\*[Gt]:]]' match the null string at +the beginning and end of a word respectively. +A word is defined as a sequence of +word characters +which is neither preceded nor followed by +word characters. +A word character is an +.I alnum +character (as defined by +.IR ctype (3)) +or an underscore. +This is an extension, +compatible with but not specified by POSIX 1003.2, +and should be used with +caution in software intended to be portable to other systems. +.PP +In the event that an RE could match more than one substring of a given +string, +the RE matches the one starting earliest in the string. +If the RE could match more than one substring starting at that point, +it matches the longest. +Subexpressions also match the longest possible substrings, subject to +the constraint that the whole match be as long as possible, +with subexpressions starting earlier in the RE taking priority over +ones starting later. +Note that higher-level subexpressions thus take priority over +their lower-level component subexpressions. +.PP +Match lengths are measured in characters, not collating elements. +A null string is considered longer than no match at all. +For example, +`bb*' matches the three middle characters of `abbbc', +`(wee|week)(knights|nights)' matches all ten characters of `weeknights', +when `(.*).*' is matched against `abc' the parenthesized subexpression +matches all three characters, and +when `(a*)*' is matched against `bc' both the whole RE and the parenthesized +subexpression match the null string. +.PP +If case-independent matching is specified, +the effect is much as if all case distinctions had vanished from the +alphabet. +When an alphabetic that exists in multiple cases appears as an +ordinary character outside a bracket expression, it is effectively +transformed into a bracket expression containing both cases, +e.g. `x' becomes `[xX]'. +When it appears inside a bracket expression, all case counterparts +of it are added to the bracket expression, so that (e.g.) `[x]' +becomes `[xX]' and `[^x]' becomes `[^xX]'. +.PP +No particular limit is imposed on the length of REs\(dg. +Programs intended to be portable should not employ REs longer +than 256 bytes, +as an implementation can refuse to accept such REs and remain +POSIX-compliant. +.PP +Obsolete (``basic'') regular expressions differ in several respects. +`|', `+', and `?' are ordinary characters and there is no equivalent +for their functionality. +The delimiters for bounds are `\e{' and `\e}', +with `{' and `}' by themselves ordinary characters. +The parentheses for nested subexpressions are `\e(' and `\e)', +with `(' and `)' by themselves ordinary characters. +`^' is an ordinary character except at the beginning of the +RE or\(dg the beginning of a parenthesized subexpression, +`$' is an ordinary character except at the end of the +RE or\(dg the end of a parenthesized subexpression, +and `*' is an ordinary character if it appears at the beginning of the +RE or the beginning of a parenthesized subexpression +(after a possible leading `^'). +Finally, there is one new type of atom, a \fIback reference\fR: +`\e' followed by a non-zero decimal digit \fId\fR +matches the same sequence of characters +matched by the \fId\fRth parenthesized subexpression +(numbering subexpressions by the positions of their opening parentheses, +left to right), +so that (e.g.) `\e([bc]\e)\e1' matches `bb' or `cc' but not `bc'. +.SH SEE ALSO +regex(3) +.PP +POSIX 1003.2, section 2.8 (Regular Expression Notation). +.SH BUGS +Having two kinds of REs is a botch. +.PP +The current 1003.2 spec says that `)' is an ordinary character in +the absence of an unmatched `('; +this was an unintentional result of a wording error, +and change is likely. +Avoid relying on it. +.PP +Back references are a dreadful botch, +posing major problems for efficient implementations. +They are also somewhat vaguely defined +(does +`a\e(\e(b\e)*\e2\e)*d' match `abbbd'?). +Avoid using them. +.PP +1003.2's specification of case-independent matching is vague. +The ``one case implies all cases'' definition given above +is current consensus among implementors as to the right interpretation. +.PP +The syntax for word boundaries is incredibly ugly. diff --git a/compiler/clib/regex/regcomp.c b/compiler/clib/regex/regcomp.c index a76b453912..85d4f29ee9 100644 --- a/compiler/clib/regex/regcomp.c +++ b/compiler/clib/regex/regcomp.c @@ -1,5 +1,6 @@ +/* $NetBSD: regcomp.c,v 1.28 2007/02/09 23:44:18 junyoung Exp $ */ + /*- - * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -14,6 +15,43 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regcomp.c 8.5 (Berkeley) 3/20/94 + */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -33,28 +71,36 @@ * @(#)regcomp.c 8.5 (Berkeley) 3/20/94 */ -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)regcomp.c 8.5 (Berkeley) 3/20/94"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD: src/lib/libc/regex/regcomp.c,v 1.36 2007/06/11 03:05:54 delphij Exp $"); +/* +__RCSID("$NetBSD: regcomp.c,v 1.28 2007/02/09 23:44:18 junyoung Exp $"); +*/ + +#if defined(__AROS__) +#if !DEBUG +#define NDEBUG +#else +#define REDEBUG +#endif +#endif #include -#include -#include + +#include #include #include +#include #include +#include #include -#include -#include -#include -#include "locale/collate.h" +#ifdef __weak_alias +__weak_alias(regcomp,_regcomp) +#endif #include "utils.h" #include "regex2.h" +#include "cclass.h" #include "cname.h" /* @@ -62,8 +108,8 @@ __FBSDID("$FreeBSD: src/lib/libc/regex/regcomp.c,v 1.36 2007/06/11 03:05:54 delp * other clumsinesses */ struct parse { - char *next; /* next character in RE */ - char *end; /* end of string (-> NUL normally) */ + const char *next; /* next character in RE */ + const char *end; /* end of string (-> NUL normally) */ int error; /* has an error been seen? */ sop *strip; /* malloced strip */ sopno ssize; /* malloced strip size (allocated) */ @@ -81,42 +127,48 @@ extern "C" { #endif /* === regcomp.c === */ -static void p_ere(struct parse *p, wint_t stop); +static void p_ere(struct parse *p, int stop); static void p_ere_exp(struct parse *p); static void p_str(struct parse *p); -static void p_bre(struct parse *p, wint_t end1, wint_t end2); +static void p_bre(struct parse *p, int end1, int end2); static int p_simp_re(struct parse *p, int starordinary); static int p_count(struct parse *p); static void p_bracket(struct parse *p); static void p_b_term(struct parse *p, cset *cs); static void p_b_cclass(struct parse *p, cset *cs); static void p_b_eclass(struct parse *p, cset *cs); -static wint_t p_b_symbol(struct parse *p); -static wint_t p_b_coll_elem(struct parse *p, wint_t endc); -static wint_t othercase(wint_t ch); -static void bothcases(struct parse *p, wint_t ch); -static void ordinary(struct parse *p, wint_t ch); +static char p_b_symbol(struct parse *p); +static char p_b_coll_elem(struct parse *p, int endc); +static int othercase(int ch); +static void bothcases(struct parse *p, int ch); +static void ordinary(struct parse *p, int ch); static void nonnewline(struct parse *p); static void repeat(struct parse *p, sopno start, int from, int to); static int seterr(struct parse *p, int e); static cset *allocset(struct parse *p); static void freeset(struct parse *p, cset *cs); -static void CHadd(struct parse *p, cset *cs, wint_t ch); -static void CHaddrange(struct parse *p, cset *cs, wint_t min, wint_t max); -static void CHaddtype(struct parse *p, cset *cs, wctype_t wct); -static wint_t singleton(cset *cs); +static int freezeset(struct parse *p, cset *cs); +static int firstch(struct parse *p, cset *cs); +static int nch(struct parse *p, cset *cs); +static void mcadd(struct parse *p, cset *cs, const char *cp); +#if 0 +static void mcsub(cset *cs, char *cp); +static int mcin(cset *cs, char *cp); +static char *mcfind(cset *cs, char *cp); +#endif +static void mcinvert(struct parse *p, cset *cs); +static void mccase(struct parse *p, cset *cs); +static int isinsets(struct re_guts *g, int c); +static int samesets(struct re_guts *g, int c1, int c2); +static void categorize(struct parse *p, struct re_guts *g); static sopno dupl(struct parse *p, sopno start, sopno finish); -static void doemit(struct parse *p, sop op, size_t opnd); -static void doinsert(struct parse *p, sop op, size_t opnd, sopno pos); -static void dofwd(struct parse *p, sopno pos, sop value); +static void doemit(struct parse *p, sop op, sopno opnd); +static void doinsert(struct parse *p, sop op, sopno opnd, sopno pos); +static void dofwd(struct parse *p, sopno pos, sopno value); static void enlarge(struct parse *p, sopno size); static void stripsnug(struct parse *p, struct re_guts *g); static void findmust(struct parse *p, struct re_guts *g); -static int altoffset(sop *scan, int offset); -static void computejumps(struct parse *p, struct re_guts *g); -static void computematchjumps(struct parse *p, struct re_guts *g); static sopno pluscount(struct parse *p, struct re_guts *g); -static wint_t wgetnext(struct parse *p); #ifdef __cplusplus } @@ -141,13 +193,12 @@ static char nuls[10]; /* place to point scanner in event of error */ #define NEXT2() (p->next += 2) #define NEXTn(n) (p->next += (n)) #define GETNEXT() (*p->next++) -#define WGETNEXT() wgetnext(p) #define SETERROR(e) seterr(p, (e)) -#define REQUIRE(co, e) ((co) || SETERROR(e)) +#define REQUIRE(co, e) (void) ((co) || SETERROR(e)) #define MUSTSEE(c, e) (REQUIRE(MORE() && PEEK() == (c), e)) -#define MUSTEAT(c, e) (REQUIRE(MORE() && GETNEXT() == (c), e)) +#define MUSTEAT(c, e) (void) (REQUIRE(MORE() && GETNEXT() == (c), e)) #define MUSTNOTSEE(c, e) (REQUIRE(!MORE() || PEEK() != (c), e)) -#define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd)) +#define EMIT(op, sopnd) doemit(p, (sop)(op), sopnd) #define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos) #define AHEAD(pos) dofwd(p, pos, HERE()-(pos)) #define ASTERN(sop, pos) EMIT(sop, HERE()-pos) @@ -162,9 +213,6 @@ static int never = 0; /* for use in asserts; shuts lint up */ #define never 0 /* some s have bugs too */ #endif -/* Macro used by computejump()/computematchjump() */ -#define MIN(a,b) ((a)<(b)?(a):(b)) - /* - regcomp - interface for parser and compilation = extern int regcomp(regex_t *, const char *, int); @@ -178,9 +226,10 @@ static int never = 0; /* for use in asserts; shuts lint up */ = #define REG_DUMP 0200 */ int /* 0 success, otherwise REG_something */ -regcomp(regex_t * __restrict preg, - const char * __restrict pattern, - int cflags) +regcomp( + regex_t *preg, + const char *pattern, + int cflags) { struct parse pa; struct re_guts *g; @@ -193,6 +242,9 @@ regcomp(regex_t * __restrict preg, # define GOODFLAGS(f) ((f)&~REG_DUMP) #endif + assert(preg != NULL); + assert(pattern != NULL); + cflags = GOODFLAGS(cflags); if ((cflags®_EXTENDED) && (cflags®_NOSPEC)) return(REG_INVARG); @@ -202,23 +254,24 @@ regcomp(regex_t * __restrict preg, return(REG_INVARG); len = preg->re_endp - pattern; } else - len = strlen((char *)pattern); + len = strlen(pattern); /* do the mallocs early so failure handling is easy */ - g = (struct re_guts *)malloc(sizeof(struct re_guts)); + g = (struct re_guts *)malloc(sizeof(struct re_guts) + + (NC-1)*sizeof(cat_t)); if (g == NULL) return(REG_ESPACE); p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */ p->strip = (sop *)malloc(p->ssize * sizeof(sop)); p->slen = 0; if (p->strip == NULL) { - free((char *)g); + free(g); return(REG_ESPACE); } /* set things up */ p->g = g; - p->next = (char *)pattern; /* convenience; we do not modify it */ + p->next = pattern; p->end = p->next + len; p->error = 0; p->ncsalloc = 0; @@ -226,18 +279,20 @@ regcomp(regex_t * __restrict preg, p->pbegin[i] = 0; p->pend[i] = 0; } + g->csetsize = NC; g->sets = NULL; + g->setbits = NULL; g->ncsets = 0; g->cflags = cflags; g->iflags = 0; g->nbol = 0; g->neol = 0; g->must = NULL; - g->moffset = -1; - g->charjump = NULL; - g->matchjump = NULL; g->mlen = 0; g->nsub = 0; + g->ncategories = 1; /* category 0 is "everything else" */ + g->categories = &g->catspace[-(CHAR_MIN)]; + (void) memset((char *)g->catspace, 0, NC*sizeof(cat_t)); g->backrefs = 0; /* do it */ @@ -253,19 +308,9 @@ regcomp(regex_t * __restrict preg, g->laststate = THERE(); /* tidy up loose ends and fill things in */ + categorize(p, g); stripsnug(p, g); findmust(p, g); - /* only use Boyer-Moore algorithm if the pattern is bigger - * than three characters - */ - if(g->mlen > 3) { - computejumps(p, g); - computematchjumps(p, g); - if(g->matchjump == NULL && g->charjump != NULL) { - free(g->charjump); - g->charjump = NULL; - } - } g->nplus = pluscount(p, g); g->magic = MAGIC2; preg->re_nsub = g->nsub; @@ -288,21 +333,24 @@ regcomp(regex_t * __restrict preg, == static void p_ere(struct parse *p, int stop); */ static void -p_ere(struct parse *p, - wint_t stop) /* character this ERE should end at */ +p_ere( + struct parse *p, + int stop) /* character this ERE should end at */ { char c; - sopno prevback = 0; - sopno prevfwd = 0; + sopno prevback = 0; /* pacify gcc */ + sopno prevfwd = 0; /* pacify gcc */ sopno conc; int first = 1; /* is this the first alternative? */ + assert(p != NULL); + for (;;) { /* do a bunch of concatenated expressions */ conc = HERE(); while (MORE() && (c = PEEK()) != '|' && c != stop) p_ere_exp(p); - (void)REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */ + REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */ if (!EAT('|')) break; /* NOTE BREAK OUT */ @@ -333,23 +381,25 @@ p_ere(struct parse *p, == static void p_ere_exp(struct parse *p); */ static void -p_ere_exp(struct parse *p) +p_ere_exp( + struct parse *p) { char c; - wint_t wc; sopno pos; int count; int count2; sopno subno; int wascaret = 0; + assert(p != NULL); + assert(MORE()); /* caller should have ensured this */ c = GETNEXT(); pos = HERE(); switch (c) { case '(': - (void)REQUIRE(MORE(), REG_EPAREN); + REQUIRE(MORE(), REG_EPAREN); p->g->nsub++; subno = p->g->nsub; if (subno < NPAREN) @@ -362,7 +412,7 @@ p_ere_exp(struct parse *p) assert(p->pend[subno] != 0); } EMIT(ORPAREN, subno); - (void)MUSTEAT(')', REG_EPAREN); + MUSTEAT(')', REG_EPAREN); break; #ifndef POSIX_MISTAKE case ')': /* happens only if no current unmatched ( */ @@ -405,17 +455,15 @@ p_ere_exp(struct parse *p) p_bracket(p); break; case '\\': - (void)REQUIRE(MORE(), REG_EESCAPE); - wc = WGETNEXT(); - ordinary(p, wc); + REQUIRE(MORE(), REG_EESCAPE); + c = GETNEXT(); + ordinary(p, c); break; case '{': /* okay as ordinary except if digit follows */ - (void)REQUIRE(!MORE() || !isdigit((uch)PEEK()), REG_BADRPT); + REQUIRE(!MORE() || !isdigit((unsigned char)PEEK()), REG_BADRPT); /* FALLTHROUGH */ default: - p->next--; - wc = WGETNEXT(); - ordinary(p, wc); + ordinary(p, c); break; } @@ -424,11 +472,11 @@ p_ere_exp(struct parse *p) c = PEEK(); /* we call { a repetition if followed by a digit */ if (!( c == '*' || c == '+' || c == '?' || - (c == '{' && MORE2() && isdigit((uch)PEEK2())) )) + (c == '{' && MORE2() && isdigit((unsigned char)PEEK2())) )) return; /* no repetition, we're done */ NEXT(); - (void)REQUIRE(!wascaret, REG_BADRPT); + REQUIRE(!wascaret, REG_BADRPT); switch (c) { case '*': /* implemented as +? */ /* this case does not require the (y|) trick, noKLUDGE */ @@ -453,9 +501,9 @@ p_ere_exp(struct parse *p) case '{': count = p_count(p); if (EAT(',')) { - if (isdigit((uch)PEEK())) { + if (isdigit((unsigned char)PEEK())) { count2 = p_count(p); - (void)REQUIRE(count <= count2, REG_BADBR); + REQUIRE(count <= count2, REG_BADBR); } else /* single number with comma */ count2 = INFINITY; } else /* just a single number */ @@ -464,7 +512,7 @@ p_ere_exp(struct parse *p) if (!EAT('}')) { /* error heuristics */ while (MORE() && PEEK() != '}') NEXT(); - (void)REQUIRE(MORE(), REG_EBRACE); + REQUIRE(MORE(), REG_EBRACE); SETERROR(REG_BADBR); } break; @@ -474,7 +522,7 @@ p_ere_exp(struct parse *p) return; c = PEEK(); if (!( c == '*' || c == '+' || c == '?' || - (c == '{' && MORE2() && isdigit((uch)PEEK2())) ) ) + (c == '{' && MORE2() && isdigit((unsigned char)PEEK2())) ) ) return; SETERROR(REG_BADRPT); } @@ -484,11 +532,15 @@ p_ere_exp(struct parse *p) == static void p_str(struct parse *p); */ static void -p_str(struct parse *p) +p_str( + struct parse *p) { - (void)REQUIRE(MORE(), REG_EMPTY); + + assert(p != NULL); + + REQUIRE(MORE(), REG_EMPTY); while (MORE()) - ordinary(p, WGETNEXT()); + ordinary(p, GETNEXT()); } /* @@ -498,18 +550,25 @@ p_str(struct parse *p) * Giving end1 as OUT essentially eliminates the end1/end2 check. * * This implementation is a bit of a kludge, in that a trailing $ is first - * taken as an ordinary character and then revised to be an anchor. + * taken as an ordinary character and then revised to be an anchor. The + * only undesirable side effect is that '$' gets included as a character + * category in such cases. This is fairly harmless; not worth fixing. * The amount of lookahead needed to avoid this kludge is excessive. */ static void -p_bre(struct parse *p, - wint_t end1, /* first terminating character */ - wint_t end2) /* second terminating character */ +p_bre( + struct parse *p, + int end1, /* first terminating character */ + int end2) /* second terminating character */ { - sopno start = HERE(); + sopno start; int first = 1; /* first subexpression? */ int wasdollar = 0; + assert(p != NULL); + + start = HERE(); + if (EAT('^')) { EMIT(OBOL, 0); p->g->iflags |= USEBOL; @@ -526,7 +585,7 @@ p_bre(struct parse *p, p->g->neol++; } - (void)REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */ + REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */ } /* @@ -534,25 +593,27 @@ p_bre(struct parse *p, == static int p_simp_re(struct parse *p, int starordinary); */ static int /* was the simple RE an unbackslashed $? */ -p_simp_re(struct parse *p, - int starordinary) /* is a leading * an ordinary character? */ +p_simp_re( + struct parse *p, + int starordinary) /* is a leading * an ordinary character? */ { int c; int count; int count2; sopno pos; int i; - wint_t wc; sopno subno; # define BACKSL (1<pend[subno] != 0); } EMIT(ORPAREN, subno); - (void)REQUIRE(EATTWO('\\', ')'), REG_EPAREN); + REQUIRE(EATTWO('\\', ')'), REG_EPAREN); break; case BACKSL|')': /* should not get here -- must be user */ case BACKSL|'}': @@ -611,12 +672,10 @@ p_simp_re(struct parse *p, p->g->backrefs = 1; break; case '*': - (void)REQUIRE(starordinary, REG_BADRPT); + REQUIRE(starordinary, REG_BADRPT); /* FALLTHROUGH */ default: - p->next--; - wc = WGETNEXT(); - ordinary(p, wc); + ordinary(p, c &~ BACKSL); break; } @@ -629,9 +688,9 @@ p_simp_re(struct parse *p, } else if (EATTWO('\\', '{')) { count = p_count(p); if (EAT(',')) { - if (MORE() && isdigit((uch)PEEK())) { + if (MORE() && isdigit((unsigned char)PEEK())) { count2 = p_count(p); - (void)REQUIRE(count <= count2, REG_BADBR); + REQUIRE(count <= count2, REG_BADBR); } else /* single number with comma */ count2 = INFINITY; } else /* just a single number */ @@ -640,10 +699,10 @@ p_simp_re(struct parse *p, if (!EATTWO('\\', '}')) { /* error heuristics */ while (MORE() && !SEETWO('\\', '}')) NEXT(); - (void)REQUIRE(MORE(), REG_EBRACE); + REQUIRE(MORE(), REG_EBRACE); SETERROR(REG_BADBR); } - } else if (c == '$') /* $ (but not \$) ends it */ + } else if (c == (unsigned char)'$') /* $ (but not \$) ends it */ return(1); return(0); @@ -654,70 +713,104 @@ p_simp_re(struct parse *p, == static int p_count(struct parse *p); */ static int /* the value */ -p_count(struct parse *p) +p_count( + struct parse *p) { int count = 0; int ndigits = 0; - while (MORE() && isdigit((uch)PEEK()) && count <= DUPMAX) { + assert(p != NULL); + + while (MORE() && isdigit((unsigned char)PEEK()) && count <= DUPMAX) { count = count*10 + (GETNEXT() - '0'); ndigits++; } - (void)REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR); + REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR); return(count); } /* - p_bracket - parse a bracketed character list == static void p_bracket(struct parse *p); + * + * Note a significant property of this code: if the allocset() did SETERROR, + * no set operations are done. */ static void -p_bracket(struct parse *p) +p_bracket( + struct parse *p) { cset *cs; - wint_t ch; + int invert = 0; + + assert(p != NULL); + + cs = allocset(p); /* Dept of Truly Sickening Special-Case Kludges */ - if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) { + if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", + (size_t)6) == 0) { EMIT(OBOW, 0); NEXTn(6); return; } - if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) { + if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", + (size_t)6) == 0) { EMIT(OEOW, 0); NEXTn(6); return; } - if ((cs = allocset(p)) == NULL) - return; - - if (p->g->cflags®_ICASE) - cs->icase = 1; if (EAT('^')) - cs->invert = 1; + invert++; /* make note to invert set at end */ if (EAT(']')) - CHadd(p, cs, ']'); + CHadd(cs, ']'); else if (EAT('-')) - CHadd(p, cs, '-'); + CHadd(cs, '-'); while (MORE() && PEEK() != ']' && !SEETWO('-', ']')) p_b_term(p, cs); if (EAT('-')) - CHadd(p, cs, '-'); - (void)MUSTEAT(']', REG_EBRACK); + CHadd(cs, '-'); + MUSTEAT(']', REG_EBRACK); if (p->error != 0) /* don't mess things up further */ return; - if (cs->invert && p->g->cflags®_NEWLINE) - cs->bmp['\n' >> 3] |= 1 << ('\n' & 7); + if (p->g->cflags®_ICASE) { + int i; + int ci; - if ((ch = singleton(cs)) != OUT) { /* optimize singleton sets */ - ordinary(p, ch); + for (i = p->g->csetsize - 1; i >= 0; i--) + if (CHIN(cs, i) && isalpha(i)) { + ci = othercase(i); + if (ci != i) + CHadd(cs, ci); + } + if (cs->multis != NULL) + mccase(p, cs); + } + if (invert) { + int i; + + for (i = p->g->csetsize - 1; i >= 0; i--) + if (CHIN(cs, i)) + CHsub(cs, i); + else + CHadd(cs, i); + if (p->g->cflags®_NEWLINE) + CHsub(cs, '\n'); + if (cs->multis != NULL) + mcinvert(p, cs); + } + + assert(cs->multis == NULL); /* xxx */ + + if (nch(p, cs) == 1) { /* optimize singleton sets */ + ordinary(p, firstch(p, cs)); freeset(p, cs); } else - EMIT(OANYOF, (int)(cs - p->g->sets)); + EMIT(OANYOF, freezeset(p, cs)); } /* @@ -725,21 +818,27 @@ p_bracket(struct parse *p) == static void p_b_term(struct parse *p, cset *cs); */ static void -p_b_term(struct parse *p, cset *cs) +p_b_term( + struct parse *p, + cset *cs) { char c; - wint_t start, finish; - wint_t i; + char start, finish; + int i; + + assert(p != NULL); + assert(cs != NULL); /* classify what we've got */ switch ((MORE()) ? PEEK() : '\0') { case '[': c = (MORE2()) ? PEEK2() : '\0'; break; + case '-': SETERROR(REG_ERANGE); return; /* NOTE RETURN */ - break; + default: c = '\0'; break; @@ -748,23 +847,24 @@ p_b_term(struct parse *p, cset *cs) switch (c) { case ':': /* character class */ NEXT2(); - (void)REQUIRE(MORE(), REG_EBRACK); + REQUIRE(MORE(), REG_EBRACK); c = PEEK(); - (void)REQUIRE(c != '-' && c != ']', REG_ECTYPE); + REQUIRE(c != '-' && c != ']', REG_ECTYPE); p_b_cclass(p, cs); - (void)REQUIRE(MORE(), REG_EBRACK); - (void)REQUIRE(EATTWO(':', ']'), REG_ECTYPE); + REQUIRE(MORE(), REG_EBRACK); + REQUIRE(EATTWO(':', ']'), REG_ECTYPE); break; case '=': /* equivalence class */ NEXT2(); - (void)REQUIRE(MORE(), REG_EBRACK); + REQUIRE(MORE(), REG_EBRACK); c = PEEK(); - (void)REQUIRE(c != '-' && c != ']', REG_ECOLLATE); + REQUIRE(c != '-' && c != ']', REG_ECOLLATE); p_b_eclass(p, cs); - (void)REQUIRE(MORE(), REG_EBRACK); - (void)REQUIRE(EATTWO('=', ']'), REG_ECOLLATE); + REQUIRE(MORE(), REG_EBRACK); + REQUIRE(EATTWO('=', ']'), REG_ECOLLATE); break; default: /* symbol, ordinary character, or range */ +/* xxx revision needed for multichar stuff */ start = p_b_symbol(p); if (SEE('-') && MORE2() && PEEK2() != ']') { /* range */ @@ -775,22 +875,10 @@ p_b_term(struct parse *p, cset *cs) finish = p_b_symbol(p); } else finish = start; - if (start == finish) - CHadd(p, cs, start); - else { - if (__collate_load_error) { - (void)REQUIRE((uch)start <= (uch)finish, REG_ERANGE); - CHaddrange(p, cs, start, finish); - } else { - (void)REQUIRE(__collate_range_cmp(start, finish) <= 0, REG_ERANGE); - for (i = 0; i <= UCHAR_MAX; i++) { - if ( __collate_range_cmp(start, i) <= 0 - && __collate_range_cmp(i, finish) <= 0 - ) - CHadd(p, cs, i); - } - } - } +/* xxx what about signed chars here... */ + REQUIRE(start <= finish, REG_ERANGE); + for (i = start; i <= finish; i++) + CHadd(cs, i); break; } } @@ -800,27 +888,38 @@ p_b_term(struct parse *p, cset *cs) == static void p_b_cclass(struct parse *p, cset *cs); */ static void -p_b_cclass(struct parse *p, cset *cs) +p_b_cclass( + struct parse *p, + cset *cs) { - char *sp = p->next; + const char *sp; + const struct cclass *cp; size_t len; - wctype_t wct; - char clname[16]; + const char *u; + char c; + + assert(p != NULL); + assert(cs != NULL); - while (MORE() && isalpha((uch)PEEK())) + sp = p->next; + + while (MORE() && isalpha((unsigned char)PEEK())) NEXT(); len = p->next - sp; - if (len >= sizeof(clname) - 1) { - SETERROR(REG_ECTYPE); - return; - } - memcpy(clname, sp, len); - clname[len] = '\0'; - if ((wct = wctype(clname)) == 0) { + for (cp = cclasses; cp->name != NULL; cp++) + if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0') + break; + if (cp->name == NULL) { + /* oops, didn't find it */ SETERROR(REG_ECTYPE); return; } - CHaddtype(p, cs, wct); + + u = cp->chars; + while ((c = *u++) != '\0') + CHadd(cs, c); + for (u = cp->multis; *u != '\0'; u += strlen(u) + 1) + MCadd(p, cs, u); } /* @@ -830,30 +929,38 @@ p_b_cclass(struct parse *p, cset *cs) * This implementation is incomplete. xxx */ static void -p_b_eclass(struct parse *p, cset *cs) +p_b_eclass( + struct parse *p, + cset *cs) { - wint_t c; + char c; + + assert(p != NULL); + assert(cs != NULL); c = p_b_coll_elem(p, '='); - CHadd(p, cs, c); + CHadd(cs, c); } /* - p_b_symbol - parse a character or [..]ed multicharacter collating symbol == static char p_b_symbol(struct parse *p); */ -static wint_t /* value of symbol */ -p_b_symbol(struct parse *p) +static char /* value of symbol */ +p_b_symbol( + struct parse *p) { - wint_t value; + char value; + + assert(p != NULL); - (void)REQUIRE(MORE(), REG_EBRACK); + REQUIRE(MORE(), REG_EBRACK); if (!EATTWO('[', '.')) - return(WGETNEXT()); + return(GETNEXT()); /* collating symbol */ value = p_b_coll_elem(p, '.'); - (void)REQUIRE(EATTWO('.', ']'), REG_ECOLLATE); + REQUIRE(EATTWO('.', ']'), REG_ECOLLATE); return(value); } @@ -861,16 +968,18 @@ p_b_symbol(struct parse *p) - p_b_coll_elem - parse a collating-element name and look it up == static char p_b_coll_elem(struct parse *p, int endc); */ -static wint_t /* value of collating element */ -p_b_coll_elem(struct parse *p, - wint_t endc) /* name ended by endc,']' */ +static char /* value of collating element */ +p_b_coll_elem( + struct parse *p, + int endc) /* name ended by endc,']' */ { - char *sp = p->next; - struct cname *cp; - int len; - mbstate_t mbs; - wchar_t wc; - size_t clen; + const char *sp; + const struct cname *cp; + size_t len; + + assert(p != NULL); + + sp = p->next; while (MORE() && !SEETWO(endc, ']')) NEXT(); @@ -882,28 +991,25 @@ p_b_coll_elem(struct parse *p, for (cp = cnames; cp->name != NULL; cp++) if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0') return(cp->code); /* known name */ - memset(&mbs, 0, sizeof(mbs)); - if ((clen = mbrtowc(&wc, sp, len, &mbs)) == len) - return (wc); /* single character */ - else if (clen == (size_t)-1 || clen == (size_t)-2) - SETERROR(REG_ILLSEQ); - else - SETERROR(REG_ECOLLATE); /* neither */ + if (len == 1) + return(*sp); /* single character */ + SETERROR(REG_ECOLLATE); /* neither */ return(0); } /* - othercase - return the case counterpart of an alphabetic - == static char othercase(int ch); + == static int othercase(int ch); */ -static wint_t /* if no counterpart, return ch */ -othercase(wint_t ch) +static int /* if no counterpart, return ch */ +othercase( + int ch) { - assert(iswalpha(ch)); - if (iswupper(ch)) - return(towlower(ch)); - else if (iswlower(ch)) - return(towupper(ch)); + assert(isalpha(ch)); + if (isupper(ch)) + return(tolower(ch)); + else if (islower(ch)) + return(toupper(ch)); else /* peculiar, but could happen */ return(ch); } @@ -915,24 +1021,27 @@ othercase(wint_t ch) * Boy, is this implementation ever a kludge... */ static void -bothcases(struct parse *p, wint_t ch) +bothcases( + struct parse *p, + int ch) { - char *oldnext = p->next; - char *oldend = p->end; - char bracket[3 + MB_LEN_MAX]; - size_t n; - mbstate_t mbs; + const char *oldnext; + const char *oldend; + char bracket[3]; + + assert(p != NULL); + + oldnext = p->next; + oldend = p->end; assert(othercase(ch) != ch); /* p_bracket() would recurse */ p->next = bracket; - memset(&mbs, 0, sizeof(mbs)); - n = wcrtomb(bracket, ch, &mbs); - assert(n != (size_t)-1); - bracket[n] = ']'; - bracket[n + 1] = '\0'; - p->end = bracket+n+1; + p->end = bracket+2; + bracket[0] = ch; + bracket[1] = ']'; + bracket[2] = '\0'; p_bracket(p); - assert(p->next == p->end); + assert(p->next == bracket+2); p->next = oldnext; p->end = oldend; } @@ -942,23 +1051,22 @@ bothcases(struct parse *p, wint_t ch) == static void ordinary(struct parse *p, int ch); */ static void -ordinary(struct parse *p, wint_t ch) +ordinary( + struct parse *p, + int ch) { - cset *cs; + cat_t *cap; + + assert(p != NULL); - if ((p->g->cflags®_ICASE) && iswalpha(ch) && othercase(ch) != ch) - bothcases(p, ch); - else if ((ch & OPDMASK) == ch) - EMIT(OCHAR, ch); + cap = p->g->categories; + if ((p->g->cflags®_ICASE) && isalpha((unsigned char) ch) + && othercase((unsigned char) ch) != (unsigned char) ch) + bothcases(p, (unsigned char) ch); else { - /* - * Kludge: character is too big to fit into an OCHAR operand. - * Emit a singleton set. - */ - if ((cs = allocset(p)) == NULL) - return; - CHadd(p, cs, ch); - EMIT(OANYOF, (int)(cs - p->g->sets)); + EMIT(OCHAR, (unsigned char)ch); + if (cap[ch] == 0) + cap[ch] = p->g->ncategories++; } } @@ -969,12 +1077,18 @@ ordinary(struct parse *p, wint_t ch) * Boy, is this implementation ever a kludge... */ static void -nonnewline(struct parse *p) +nonnewline( + struct parse *p) { - char *oldnext = p->next; - char *oldend = p->end; + const char *oldnext; + const char *oldend; char bracket[4]; + assert(p != NULL); + + oldnext = p->next; + oldend = p->end; + p->next = bracket; p->end = bracket+3; bracket[0] = '^'; @@ -992,18 +1106,23 @@ nonnewline(struct parse *p) == static void repeat(struct parse *p, sopno start, int from, int to); */ static void -repeat(struct parse *p, - sopno start, /* operand from here to end of strip */ - int from, /* repeated from this number */ - int to) /* to this number of times (maybe INFINITY) */ +repeat( + struct parse *p, + sopno start, /* operand from here to end of strip */ + int from, /* repeated from this number */ + int to) /* to this number of times (maybe INFINITY) */ { - sopno finish = HERE(); + sopno finish; # define N 2 # define INF 3 # define REP(f, t) ((f)*8 + (t)) # define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N) sopno copy; + assert(p != NULL); + + finish = HERE(); + if (p->error != 0) /* head off possible runaway recursion */ return; @@ -1059,36 +1178,17 @@ repeat(struct parse *p, } /* - - wgetnext - helper function for WGETNEXT() macro. Gets the next wide - - character from the parse struct, signals a REG_ILLSEQ error if the - - character can't be converted. Returns the number of bytes consumed. - */ -static wint_t -wgetnext(struct parse *p) -{ - mbstate_t mbs; - wchar_t wc; - size_t n; - - memset(&mbs, 0, sizeof(mbs)); - n = mbrtowc(&wc, p->next, p->end - p->next, &mbs); - if (n == (size_t)-1 || n == (size_t)-2) { - SETERROR(REG_ILLSEQ); - return (0); - } - if (n == 0) - n = 1; - p->next += n; - return (wc); -} - -/* - seterr - set an error condition == static int seterr(struct parse *p, int e); */ static int /* useless but makes type checking happy */ -seterr(struct parse *p, int e) +seterr( + struct parse *p, + int e) { + + assert(p != NULL); + if (p->error == 0) /* keep earliest error condition */ p->error = e; p->next = nuls; /* try to bring things to a halt */ @@ -1101,18 +1201,54 @@ seterr(struct parse *p, int e) == static cset *allocset(struct parse *p); */ static cset * -allocset(struct parse *p) +allocset( + struct parse *p) { - cset *cs, *ncs; + int no; + size_t nc; + size_t nbytes; + cset *cs; + size_t css; + int i; - ncs = realloc(p->g->sets, (p->g->ncsets + 1) * sizeof(*ncs)); - if (ncs == NULL) { - SETERROR(REG_ESPACE); - return (NULL); + assert(p != NULL); + + no = p->g->ncsets++; + css = (size_t)p->g->csetsize; + if (no >= p->ncsalloc) { /* need another column of space */ + p->ncsalloc += CHAR_BIT; + nc = p->ncsalloc; + assert(nc % CHAR_BIT == 0); + nbytes = nc / CHAR_BIT * css; + if (p->g->sets == NULL) + p->g->sets = malloc(nc * sizeof(cset)); + else + p->g->sets = realloc(p->g->sets, nc * sizeof(cset)); + if (p->g->setbits == NULL) + p->g->setbits = malloc(nbytes); + else { + p->g->setbits = realloc(p->g->setbits, nbytes); + /* xxx this isn't right if setbits is now NULL */ + for (i = 0; i < no; i++) + p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT); + } + if (p->g->sets != NULL && p->g->setbits != NULL) + (void) memset((char *)p->g->setbits + (nbytes - css), + 0, css); + else { + no = 0; + SETERROR(REG_ESPACE); + /* caller's responsibility not to do set ops */ + } } - p->g->sets = ncs; - cs = &p->g->sets[p->g->ncsets++]; - memset(cs, 0, sizeof(*cs)); + + assert(p->g->sets != NULL); /* xxx */ + cs = &p->g->sets[no]; + cs->ptr = p->g->setbits + css*((no)/CHAR_BIT); + cs->mask = 1 << ((no) % CHAR_BIT); + cs->hash = 0; + cs->smultis = 0; + cs->multis = NULL; return(cs); } @@ -1122,113 +1258,348 @@ allocset(struct parse *p) == static void freeset(struct parse *p, cset *cs); */ static void -freeset(struct parse *p, cset *cs) +freeset( + struct parse *p, + cset *cs) { - cset *top = &p->g->sets[p->g->ncsets]; + int i; + cset *top; + size_t css; + + assert(p != NULL); + assert(cs != NULL); - free(cs->wides); - free(cs->ranges); - free(cs->types); - memset(cs, 0, sizeof(*cs)); + top = &p->g->sets[p->g->ncsets]; + css = (size_t)p->g->csetsize; + + for (i = 0; i < css; i++) + CHsub(cs, i); if (cs == top-1) /* recover only the easy case */ p->g->ncsets--; } /* - - singleton - Determine whether a set contains only one character, - - returning it if so, otherwise returning OUT. + - freezeset - final processing on a set of characters + == static int freezeset(struct parse *p, cset *cs); + * + * The main task here is merging identical sets. This is usually a waste + * of time (although the hash code minimizes the overhead), but can win + * big if REG_ICASE is being used. REG_ICASE, by the way, is why the hash + * is done using addition rather than xor -- all ASCII [aA] sets xor to + * the same value! */ -static wint_t -singleton(cset *cs) +static int /* set number */ +freezeset( + struct parse *p, + cset *cs) { - wint_t i, s = 0, n; + uch h; + int i; + cset *top; + cset *cs2; + size_t css; + + assert(p != NULL); + assert(cs != NULL); + + h = cs->hash; + top = &p->g->sets[p->g->ncsets]; + css = (size_t)p->g->csetsize; + + /* look for an earlier one which is the same */ + for (cs2 = &p->g->sets[0]; cs2 < top; cs2++) + if (cs2->hash == h && cs2 != cs) { + /* maybe */ + for (i = 0; i < css; i++) + if (!!CHIN(cs2, i) != !!CHIN(cs, i)) + break; /* no */ + if (i == css) + break; /* yes */ + } - for (i = n = 0; i < NC; i++) - if (CHIN(cs, i)) { + if (cs2 < top) { /* found one */ + freeset(p, cs); + cs = cs2; + } + + return((int)(cs - p->g->sets)); +} + +/* + - firstch - return first character in a set (which must have at least one) + == static int firstch(struct parse *p, cset *cs); + */ +static int /* character; there is no "none" value */ +firstch( + struct parse *p, + cset *cs) +{ + int i; + size_t css; + + assert(p != NULL); + assert(cs != NULL); + + css = (size_t)p->g->csetsize; + + for (i = 0; i < css; i++) + if (CHIN(cs, i)) + return((char)i); + assert(never); + return(0); /* arbitrary */ +} + +/* + - nch - number of characters in a set + == static int nch(struct parse *p, cset *cs); + */ +static int +nch( + struct parse *p, + cset *cs) +{ + int i; + size_t css; + int n = 0; + + assert(p != NULL); + assert(cs != NULL); + + css = (size_t)p->g->csetsize; + + for (i = 0; i < css; i++) + if (CHIN(cs, i)) n++; - s = i; - } - if (n == 1) - return (s); - if (cs->nwides == 1 && cs->nranges == 0 && cs->ntypes == 0 && - cs->icase == 0) - return (cs->wides[0]); - /* Don't bother handling the other cases. */ - return (OUT); + return(n); } /* - - CHadd - add character to character set. + - mcadd - add a collating element to a cset + == static void mcadd(struct parse *p, cset *cs, \ + == char *cp); */ static void -CHadd(struct parse *p, cset *cs, wint_t ch) +mcadd( + struct parse *p, + cset *cs, + const char *cp) { - wint_t nch, *newwides; - assert(ch >= 0); - if (ch < NC) - cs->bmp[ch >> 3] |= 1 << (ch & 7); - else { - newwides = realloc(cs->wides, (cs->nwides + 1) * - sizeof(*cs->wides)); - if (newwides == NULL) { - SETERROR(REG_ESPACE); - return; - } - cs->wides = newwides; - cs->wides[cs->nwides++] = ch; - } - if (cs->icase) { - if ((nch = towlower(ch)) < NC) - cs->bmp[nch >> 3] |= 1 << (nch & 7); - if ((nch = towupper(ch)) < NC) - cs->bmp[nch >> 3] |= 1 << (nch & 7); + size_t oldend; + + assert(p != NULL); + assert(cs != NULL); + assert(cp != NULL); + + oldend = cs->smultis; + + cs->smultis += strlen(cp) + 1; + if (cs->multis == NULL) + cs->multis = malloc(cs->smultis); + else + cs->multis = realloc(cs->multis, cs->smultis); + if (cs->multis == NULL) { + SETERROR(REG_ESPACE); + return; } + + (void) strcpy(cs->multis + oldend - 1, cp); + cs->multis[cs->smultis - 1] = '\0'; } +#if 0 /* - - CHaddrange - add all characters in the range [min,max] to a character set. + - mcsub - subtract a collating element from a cset + == static void mcsub(cset *cs, char *cp); */ static void -CHaddrange(struct parse *p, cset *cs, wint_t min, wint_t max) +mcsub( + cset *cs, + char *cp) { - crange *newranges; + char *fp; + size_t len; - for (; min < NC && min <= max; min++) - CHadd(p, cs, min); - if (min >= max) - return; - newranges = realloc(cs->ranges, (cs->nranges + 1) * - sizeof(*cs->ranges)); - if (newranges == NULL) { - SETERROR(REG_ESPACE); + assert(cs != NULL); + assert(cp != NULL); + + fp = mcfind(cs, cp); + len = strlen(fp); + + assert(fp != NULL); + (void) memmove(fp, fp + len + 1, + cs->smultis - (fp + len + 1 - cs->multis)); + cs->smultis -= len; + + if (cs->smultis == 0) { + free(cs->multis); + cs->multis = NULL; return; } - cs->ranges = newranges; - cs->ranges[cs->nranges].min = min; - cs->ranges[cs->nranges].min = max; - cs->nranges++; + + cs->multis = realloc(cs->multis, cs->smultis); + assert(cs->multis != NULL); +} + +/* + - mcin - is a collating element in a cset? + == static int mcin(cset *cs, char *cp); + */ +static int +mcin( + cset *cs, + char *cp) +{ + + assert(cs != NULL); + assert(cp != NULL); + + return(mcfind(cs, cp) != NULL); +} + +/* + - mcfind - find a collating element in a cset + == static char *mcfind(cset *cs, char *cp); + */ +static char * +mcfind( + cset *cs, + char *cp) +{ + char *p; + + assert(cs != NULL); + assert(cp != NULL); + + if (cs->multis == NULL) + return(NULL); + for (p = cs->multis; *p != '\0'; p += strlen(p) + 1) + if (strcmp(cp, p) == 0) + return(p); + return(NULL); +} +#endif + +/* + - mcinvert - invert the list of collating elements in a cset + == static void mcinvert(struct parse *p, cset *cs); + * + * This would have to know the set of possibilities. Implementation + * is deferred. + */ +/* ARGSUSED */ +static void +mcinvert( + struct parse *p, + cset *cs) +{ + + assert(p != NULL); + assert(cs != NULL); + + assert(cs->multis == NULL); /* xxx */ } /* - - CHaddtype - add all characters of a certain type to a character set. + - mccase - add case counterparts of the list of collating elements in a cset + == static void mccase(struct parse *p, cset *cs); + * + * This would have to know the set of possibilities. Implementation + * is deferred. */ +/* ARGSUSED */ static void -CHaddtype(struct parse *p, cset *cs, wctype_t wct) +mccase( + struct parse *p, + cset *cs) { - wint_t i; - wctype_t *newtypes; - - for (i = 0; i < NC; i++) - if (iswctype(i, wct)) - CHadd(p, cs, i); - newtypes = realloc(cs->types, (cs->ntypes + 1) * - sizeof(*cs->types)); - if (newtypes == NULL) { - SETERROR(REG_ESPACE); + + assert(p != NULL); + assert(cs != NULL); + + assert(cs->multis == NULL); /* xxx */ +} + +/* + - isinsets - is this character in any sets? + == static int isinsets(struct re_guts *g, int c); + */ +static int /* predicate */ +isinsets( + struct re_guts *g, + int c) +{ + uch *col; + int i; + int ncols; + unsigned uc = (unsigned char)c; + + assert(g != NULL); + + ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT; + + for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize) + if (col[uc] != 0) + return(1); + return(0); +} + +/* + - samesets - are these two characters in exactly the same sets? + == static int samesets(struct re_guts *g, int c1, int c2); + */ +static int /* predicate */ +samesets( + struct re_guts *g, + int c1, + int c2) +{ + uch *col; + int i; + int ncols; + unsigned uc1 = (unsigned char)c1; + unsigned uc2 = (unsigned char)c2; + + assert(g != NULL); + + ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT; + + for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize) + if (col[uc1] != col[uc2]) + return(0); + return(1); +} + +/* + - categorize - sort out character categories + == static void categorize(struct parse *p, struct re_guts *g); + */ +static void +categorize( + struct parse *p, + struct re_guts *g) +{ + cat_t *cats; + int c; + int c2; + cat_t cat; + + assert(p != NULL); + assert(g != NULL); + + cats = g->categories; + + /* avoid making error situations worse */ + if (p->error != 0) return; - } - cs->types = newtypes; - cs->types[cs->ntypes++] = wct; + + for (c = CHAR_MIN; c <= CHAR_MAX; c++) + if (cats[c] == 0 && isinsets(g, c)) { + cat = g->ncategories++; + cats[c] = cat; + for (c2 = c+1; c2 <= CHAR_MAX; c2++) + if (cats[c2] == 0 && samesets(g, c, c2)) + cats[c2] = cat; + } } /* @@ -1236,20 +1607,25 @@ CHaddtype(struct parse *p, cset *cs, wctype_t wct) == static sopno dupl(struct parse *p, sopno start, sopno finish); */ static sopno /* start of duplicate */ -dupl(struct parse *p, - sopno start, /* from here */ - sopno finish) /* to this less one */ +dupl( + struct parse *p, + sopno start, /* from here */ + sopno finish) /* to this less one */ { - sopno ret = HERE(); + sopno ret; sopno len = finish - start; + assert(p != NULL); + + ret = HERE(); + assert(finish >= start); if (len == 0) return(ret); enlarge(p, p->ssize + len); /* this many unexpected additions */ assert(p->ssize >= p->slen + len); - (void) memcpy((char *)(p->strip + p->slen), - (char *)(p->strip + start), (size_t)len*sizeof(sop)); + (void)memcpy(p->strip + p->slen, p->strip + start, + (size_t)len * sizeof(sop)); p->slen += len; return(ret); } @@ -1263,8 +1639,14 @@ dupl(struct parse *p, * some changes to the data structures. Maybe later. */ static void -doemit(struct parse *p, sop op, size_t opnd) +doemit( + struct parse *p, + sop op, + sopno opnd) { + + assert(p != NULL); + /* avoid making error situations worse */ if (p->error != 0) return; @@ -1286,12 +1668,18 @@ doemit(struct parse *p, sop op, size_t opnd) == static void doinsert(struct parse *p, sop op, size_t opnd, sopno pos); */ static void -doinsert(struct parse *p, sop op, size_t opnd, sopno pos) +doinsert( + struct parse *p, + sop op, + sopno opnd, + sopno pos) { sopno sn; sop s; int i; + assert(p != NULL); + /* avoid making error situations worse */ if (p->error != 0) return; @@ -1312,8 +1700,7 @@ doinsert(struct parse *p, sop op, size_t opnd, sopno pos) } } - memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos], - (HERE()-pos-1)*sizeof(sop)); + memmove(&p->strip[pos+1], &p->strip[pos], (HERE()-pos-1)*sizeof(sop)); p->strip[pos] = s; } @@ -1322,8 +1709,14 @@ doinsert(struct parse *p, sop op, size_t opnd, sopno pos) == static void dofwd(struct parse *p, sopno pos, sop value); */ static void -dofwd(struct parse *p, sopno pos, sop value) +dofwd( + struct parse *p, + sopno pos, + sopno value) { + + assert(p != NULL); + /* avoid making error situations worse */ if (p->error != 0) return; @@ -1337,10 +1730,14 @@ dofwd(struct parse *p, sopno pos, sop value) == static void enlarge(struct parse *p, sopno size); */ static void -enlarge(struct parse *p, sopno size) +enlarge( + struct parse *p, + sopno size) { sop *sp; + assert(p != NULL); + if (p->ssize >= size) return; @@ -1358,10 +1755,16 @@ enlarge(struct parse *p, sopno size) == static void stripsnug(struct parse *p, struct re_guts *g); */ static void -stripsnug(struct parse *p, struct re_guts *g) +stripsnug( + struct parse *p, + struct re_guts *g) { + + assert(p != NULL); + assert(g != NULL); + g->nstates = p->slen; - g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop)); + g->strip = realloc(p->strip, p->slen * sizeof(sop)); if (g->strip == NULL) { SETERROR(REG_ESPACE); g->strip = p->strip; @@ -1379,7 +1782,9 @@ stripsnug(struct parse *p, struct re_guts *g) * Note that must and mlen got initialized during setup. */ static void -findmust(struct parse *p, struct re_guts *g) +findmust( + struct parse *p, + struct re_guts *g) { sop *scan; sop *start = NULL; @@ -1387,41 +1792,25 @@ findmust(struct parse *p, struct re_guts *g) sopno newlen; sop s; char *cp; - int offset; - char buf[MB_LEN_MAX]; - size_t clen; - mbstate_t mbs; + sopno i; + + assert(p != NULL); + assert(g != NULL); /* avoid making error situations worse */ if (p->error != 0) return; - /* - * It's not generally safe to do a ``char'' substring search on - * multibyte character strings, but it's safe for at least - * UTF-8 (see RFC 3629). - */ - if (MB_CUR_MAX > 1 && - strcmp(_CurrentRuneLocale->__encoding, "UTF-8") != 0) - return; - /* find the longest OCHAR sequence in strip */ newlen = 0; - offset = 0; - g->moffset = 0; scan = g->strip + 1; do { s = *scan++; switch (OP(s)) { case OCHAR: /* sequence member */ - if (newlen == 0) { /* new sequence */ - memset(&mbs, 0, sizeof(mbs)); + if (newlen == 0) /* new sequence */ newstart = scan - 1; - } - clen = wcrtomb(buf, OPND(s), &mbs); - if (clen == (size_t)-1) - goto toohard; - newlen += clen; + newlen++; break; case OPLUS_: /* things that don't break one */ case OLPAREN: @@ -1429,7 +1818,6 @@ findmust(struct parse *p, struct re_guts *g) break; case OQUEST_: /* things that must be skipped */ case OCH_: - offset = altoffset(scan, offset); scan--; do { scan += OPND(s); @@ -1442,317 +1830,57 @@ findmust(struct parse *p, struct re_guts *g) } } while (OP(s) != O_QUEST && OP(s) != O_CH); /* FALLTHROUGH */ - case OBOW: /* things that break a sequence */ - case OEOW: - case OBOL: - case OEOL: - case O_QUEST: - case O_CH: - case OEND: + default: /* things that break a sequence */ if (newlen > g->mlen) { /* ends one */ start = newstart; g->mlen = newlen; - if (offset > -1) { - g->moffset += offset; - offset = newlen; - } else - g->moffset = offset; - } else { - if (offset > -1) - offset += newlen; } newlen = 0; break; - case OANY: - if (newlen > g->mlen) { /* ends one */ - start = newstart; - g->mlen = newlen; - if (offset > -1) { - g->moffset += offset; - offset = newlen; - } else - g->moffset = offset; - } else { - if (offset > -1) - offset += newlen; - } - if (offset > -1) - offset++; - newlen = 0; - break; - case OANYOF: /* may or may not invalidate offset */ - /* First, everything as OANY */ - if (newlen > g->mlen) { /* ends one */ - start = newstart; - g->mlen = newlen; - if (offset > -1) { - g->moffset += offset; - offset = newlen; - } else - g->moffset = offset; - } else { - if (offset > -1) - offset += newlen; - } - if (offset > -1) - offset++; - newlen = 0; - break; - toohard: - default: - /* Anything here makes it impossible or too hard - * to calculate the offset -- so we give up; - * save the last known good offset, in case the - * must sequence doesn't occur later. - */ - if (newlen > g->mlen) { /* ends one */ - start = newstart; - g->mlen = newlen; - if (offset > -1) - g->moffset += offset; - else - g->moffset = offset; - } - offset = -1; - newlen = 0; - break; } } while (OP(s) != OEND); - if (g->mlen == 0) { /* there isn't one */ - g->moffset = -1; + if (start == NULL) + g->mlen = 0; + + if (g->mlen == 0) /* there isn't one */ return; - } /* turn it into a character string */ g->must = malloc((size_t)g->mlen + 1); if (g->must == NULL) { /* argh; just forget it */ g->mlen = 0; - g->moffset = -1; return; } cp = g->must; scan = start; - memset(&mbs, 0, sizeof(mbs)); - while (cp < g->must + g->mlen) { + for (i = g->mlen; i > 0; i--) { while (OP(s = *scan++) != OCHAR) continue; - clen = wcrtomb(cp, OPND(s), &mbs); - assert(clen != (size_t)-1); - cp += clen; + assert(cp < g->must + g->mlen); + *cp++ = (char)OPND(s); } assert(cp == g->must + g->mlen); *cp++ = '\0'; /* just on general principles */ } /* - - altoffset - choose biggest offset among multiple choices - == static int altoffset(sop *scan, int offset); - * - * Compute, recursively if necessary, the largest offset among multiple - * re paths. - */ -static int -altoffset(sop *scan, int offset) -{ - int largest; - int try; - sop s; - - /* If we gave up already on offsets, return */ - if (offset == -1) - return -1; - - largest = 0; - try = 0; - s = *scan++; - while (OP(s) != O_QUEST && OP(s) != O_CH) { - switch (OP(s)) { - case OOR1: - if (try > largest) - largest = try; - try = 0; - break; - case OQUEST_: - case OCH_: - try = altoffset(scan, try); - if (try == -1) - return -1; - scan--; - do { - scan += OPND(s); - s = *scan; - if (OP(s) != O_QUEST && OP(s) != O_CH && - OP(s) != OOR2) - return -1; - } while (OP(s) != O_QUEST && OP(s) != O_CH); - /* We must skip to the next position, or we'll - * leave altoffset() too early. - */ - scan++; - break; - case OANYOF: - case OCHAR: - case OANY: - try++; - case OBOW: - case OEOW: - case OLPAREN: - case ORPAREN: - case OOR2: - break; - default: - try = -1; - break; - } - if (try == -1) - return -1; - s = *scan++; - } - - if (try > largest) - largest = try; - - return largest+offset; -} - -/* - - computejumps - compute char jumps for BM scan - == static void computejumps(struct parse *p, struct re_guts *g); - * - * This algorithm assumes g->must exists and is has size greater than - * zero. It's based on the algorithm found on Computer Algorithms by - * Sara Baase. - * - * A char jump is the number of characters one needs to jump based on - * the value of the character from the text that was mismatched. - */ -static void -computejumps(struct parse *p, struct re_guts *g) -{ - int ch; - int mindex; - - /* Avoid making errors worse */ - if (p->error != 0) - return; - - g->charjump = (int*) malloc((NC + 1) * sizeof(int)); - if (g->charjump == NULL) /* Not a fatal error */ - return; - /* Adjust for signed chars, if necessary */ - g->charjump = &g->charjump[-(CHAR_MIN)]; - - /* If the character does not exist in the pattern, the jump - * is equal to the number of characters in the pattern. - */ - for (ch = CHAR_MIN; ch < (CHAR_MAX + 1); ch++) - g->charjump[ch] = g->mlen; - - /* If the character does exist, compute the jump that would - * take us to the last character in the pattern equal to it - * (notice that we match right to left, so that last character - * is the first one that would be matched). - */ - for (mindex = 0; mindex < g->mlen; mindex++) - g->charjump[(int)g->must[mindex]] = g->mlen - mindex - 1; -} - -/* - - computematchjumps - compute match jumps for BM scan - == static void computematchjumps(struct parse *p, struct re_guts *g); - * - * This algorithm assumes g->must exists and is has size greater than - * zero. It's based on the algorithm found on Computer Algorithms by - * Sara Baase. - * - * A match jump is the number of characters one needs to advance based - * on the already-matched suffix. - * Notice that all values here are minus (g->mlen-1), because of the way - * the search algorithm works. - */ -static void -computematchjumps(struct parse *p, struct re_guts *g) -{ - int mindex; /* General "must" iterator */ - int suffix; /* Keeps track of matching suffix */ - int ssuffix; /* Keeps track of suffixes' suffix */ - int* pmatches; /* pmatches[k] points to the next i - * such that i+1...mlen is a substring - * of k+1...k+mlen-i-1 - */ - - /* Avoid making errors worse */ - if (p->error != 0) - return; - - pmatches = (int*) malloc(g->mlen * sizeof(unsigned int)); - if (pmatches == NULL) { - g->matchjump = NULL; - return; - } - - g->matchjump = (int*) malloc(g->mlen * sizeof(unsigned int)); - if (g->matchjump == NULL) /* Not a fatal error */ - return; - - /* Set maximum possible jump for each character in the pattern */ - for (mindex = 0; mindex < g->mlen; mindex++) - g->matchjump[mindex] = 2*g->mlen - mindex - 1; - - /* Compute pmatches[] */ - for (mindex = g->mlen - 1, suffix = g->mlen; mindex >= 0; - mindex--, suffix--) { - pmatches[mindex] = suffix; - - /* If a mismatch is found, interrupting the substring, - * compute the matchjump for that position. If no - * mismatch is found, then a text substring mismatched - * against the suffix will also mismatch against the - * substring. - */ - while (suffix < g->mlen - && g->must[mindex] != g->must[suffix]) { - g->matchjump[suffix] = MIN(g->matchjump[suffix], - g->mlen - mindex - 1); - suffix = pmatches[suffix]; - } - } - - /* Compute the matchjump up to the last substring found to jump - * to the beginning of the largest must pattern prefix matching - * it's own suffix. - */ - for (mindex = 0; mindex <= suffix; mindex++) - g->matchjump[mindex] = MIN(g->matchjump[mindex], - g->mlen + suffix - mindex); - - ssuffix = pmatches[suffix]; - while (suffix < g->mlen) { - while (suffix <= ssuffix && suffix < g->mlen) { - g->matchjump[suffix] = MIN(g->matchjump[suffix], - g->mlen + ssuffix - suffix); - suffix++; - } - if (suffix < g->mlen) - ssuffix = pmatches[ssuffix]; - } - - free(pmatches); -} - -/* - pluscount - count + nesting == static sopno pluscount(struct parse *p, struct re_guts *g); */ static sopno /* nesting depth */ -pluscount(struct parse *p, struct re_guts *g) +pluscount( + struct parse *p, + struct re_guts *g) { sop *scan; sop s; sopno plusnest = 0; sopno maxnest = 0; + assert(p != NULL); + assert(g != NULL); + if (p->error != 0) return(0); /* there may not be an OEND */ diff --git a/compiler/clib/regex/regerror.c b/compiler/clib/regex/regerror.c index 9364bd4329..f6daec8eb9 100644 --- a/compiler/clib/regex/regerror.c +++ b/compiler/clib/regex/regerror.c @@ -1,5 +1,6 @@ +/* $NetBSD: regerror.c,v 1.23 2007/02/09 23:44:18 junyoung Exp $ */ + /*- - * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -14,6 +15,43 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regerror.c 8.4 (Berkeley) 3/20/94 + */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -33,19 +71,32 @@ * @(#)regerror.c 8.4 (Berkeley) 3/20/94 */ -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)regerror.c 8.4 (Berkeley) 3/20/94"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD: src/lib/libc/regex/regerror.c,v 1.11 2007/06/11 03:05:54 delphij Exp $"); +/* +__RCSID("$NetBSD: regerror.c,v 1.23 2007/02/09 23:44:18 junyoung Exp $"); +*/ + +#if defined(__AROS__) +#if !DEBUG +#define NDEBUG +#else +#define REDEBUG +#endif +#endif #include -#include -#include + +#include +#include #include +#include #include +#include #include +#ifdef __weak_alias +__weak_alias(regerror,_regerror) +#endif + #include "utils.h" /* ========= begin header generated by ./mkh ========= */ @@ -54,7 +105,7 @@ extern "C" { #endif /* === regerror.c === */ -static char *regatoi(const regex_t *preg, char *localbuf); +static const char *regatoi(const regex_t *preg, char *localbuf, size_t buflen); #ifdef __cplusplus } @@ -77,98 +128,98 @@ static char *regatoi(const regex_t *preg, char *localbuf); = #define REG_EMPTY 14 = #define REG_ASSERT 15 = #define REG_INVARG 16 - = #define REG_ILLSEQ 17 = #define REG_ATOI 255 // convert name to number (!) = #define REG_ITOA 0400 // convert number to name (!) */ -static struct rerr { +static const struct rerr { int code; - char *name; - char *explain; + const char *name; + const char *explain; } rerrs[] = { - {REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match"}, - {REG_BADPAT, "REG_BADPAT", "invalid regular expression"}, - {REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element"}, - {REG_ECTYPE, "REG_ECTYPE", "invalid character class"}, - {REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)"}, - {REG_ESUBREG, "REG_ESUBREG", "invalid backreference number"}, - {REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced"}, - {REG_EPAREN, "REG_EPAREN", "parentheses not balanced"}, - {REG_EBRACE, "REG_EBRACE", "braces not balanced"}, - {REG_BADBR, "REG_BADBR", "invalid repetition count(s)"}, - {REG_ERANGE, "REG_ERANGE", "invalid character range"}, - {REG_ESPACE, "REG_ESPACE", "out of memory"}, - {REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid"}, - {REG_EMPTY, "REG_EMPTY", "empty (sub)expression"}, - {REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug"}, - {REG_INVARG, "REG_INVARG", "invalid argument to regex routine"}, - {REG_ILLSEQ, "REG_ILLSEQ", "illegal byte sequence"}, - {0, "", "*** unknown regexp error code ***"} + { REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match" }, + { REG_BADPAT, "REG_BADPAT", "invalid regular expression" }, + { REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element" }, + { REG_ECTYPE, "REG_ECTYPE", "invalid character class" }, + { REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)" }, + { REG_ESUBREG, "REG_ESUBREG", "invalid backreference number" }, + { REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced" }, + { REG_EPAREN, "REG_EPAREN", "parentheses not balanced" }, + { REG_EBRACE, "REG_EBRACE", "braces not balanced" }, + { REG_BADBR, "REG_BADBR", "invalid repetition count(s)" }, + { REG_ERANGE, "REG_ERANGE", "invalid character range" }, + { REG_ESPACE, "REG_ESPACE", "out of memory" }, + { REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid" }, + { REG_EMPTY, "REG_EMPTY", "empty (sub)expression" }, + { REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug" }, + { REG_INVARG, "REG_INVARG", "invalid argument to regex routine" }, + { 0, "", "*** unknown regexp error code ***" } }; /* - - regerror - the interface to error numbers - = extern size_t regerror(int, const regex_t *, char *, size_t); + * regerror - the interface to error numbers + * extern size_t regerror(int, const regex_t *, char *, size_t); */ /* ARGSUSED */ size_t -regerror(int errcode, - const regex_t * __restrict preg, - char * __restrict errbuf, - size_t errbuf_size) +regerror( + int errcode, + const regex_t *preg, + char *errbuf, + size_t errbuf_size) { - struct rerr *r; + const struct rerr *r; size_t len; int target = errcode &~ REG_ITOA; - char *s; + const char *s; char convbuf[50]; + assert(errcode != REG_ATOI || preg != NULL); + assert(errbuf != NULL); + if (errcode == REG_ATOI) - s = regatoi(preg, convbuf); + s = regatoi(preg, convbuf, sizeof convbuf); else { for (r = rerrs; r->code != 0; r++) if (r->code == target) break; - - if (errcode®_ITOA) { - if (r->code != 0) - (void) strcpy(convbuf, r->name); - else - sprintf(convbuf, "REG_0x%x", target); - assert(strlen(convbuf) < sizeof(convbuf)); + + if (errcode & REG_ITOA) { + if (r->code != 0) { + (void)strlcpy(convbuf, r->name, sizeof convbuf); + } else + (void)snprintf(convbuf, sizeof convbuf, + "REG_0x%x", target); s = convbuf; } else s = r->explain; } len = strlen(s) + 1; - if (errbuf_size > 0) { - if (errbuf_size > len) - (void) strcpy(errbuf, s); - else { - (void) strncpy(errbuf, s, errbuf_size-1); - errbuf[errbuf_size-1] = '\0'; - } - } + if (errbuf_size > 0) + (void)strlcpy(errbuf, s, errbuf_size); return(len); } /* - - regatoi - internal routine to implement REG_ATOI - == static char *regatoi(const regex_t *preg, char *localbuf); + * regatoi - internal routine to implement REG_ATOI + * static const char *regatoi(const regex_t *preg, char *localbuf, + * size_t buflen); */ -static char * -regatoi(const regex_t *preg, char *localbuf) +static const char * +regatoi( + const regex_t *preg, + char *localbuf, + size_t buflen) { - struct rerr *r; + const struct rerr *r; for (r = rerrs; r->code != 0; r++) if (strcmp(r->name, preg->re_endp) == 0) break; if (r->code == 0) - return("0"); + return "0"; - sprintf(localbuf, "%d", r->code); - return(localbuf); + (void)snprintf(localbuf, buflen, "%d", r->code); + return localbuf; } diff --git a/compiler/clib/regex/regex.3 b/compiler/clib/regex/regex.3 new file mode 100644 index 0000000000..d73e840e77 --- /dev/null +++ b/compiler/clib/regex/regex.3 @@ -0,0 +1,628 @@ +.\" $NetBSD: regex.3,v 1.18 2003/12/29 17:36:12 wiz Exp $ +.\" +.\" Copyright (c) 1992, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Henry Spencer. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Copyright (c) 1992, 1993, 1994 Henry Spencer. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Henry Spencer. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)regex.3 8.4 (Berkeley) 3/20/94 +.\" +.Dd December 29, 2003 +.Dt REGEX 3 +.Os +.Sh NAME +.Nm regex , +.Nm regcomp , +.Nm regexec , +.Nm regerror , +.Nm regfree +.Nd regular-expression library +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In regex.h +.Ft int +.Fn regcomp "regex_t * restrict preg" "const char * restrict pattern" "int cflags" +.Ft int +.Fn regexec "const regex_t * restrict preg" "const char * restrict string" "size_t nmatch" "regmatch_t pmatch[]" "int eflags" +.Ft size_t +.Fn regerror "int errcode" "const regex_t * restrict preg" "char * restrict errbuf" "size_t errbuf_size" +.Ft void +.Fn regfree "regex_t *preg" +.Sh DESCRIPTION +These routines implement +.St -p1003.2-92 +regular expressions (``RE''s); +see +.Xr re_format 7 . +.Fn regcomp +compiles an RE written as a string into an internal form, +.Fn regexec +matches that internal form against a string and reports results, +.Fn regerror +transforms error codes from either into human-readable messages, +and +.Fn regfree +frees any dynamically-allocated storage used by the internal form +of an RE. +.Pp +The header +.Em \*[Lt]regex.h\*[Gt] +declares two structure types, +.Fa regex_t +and +.Fa regmatch_t , +the former for compiled internal forms and the latter for match reporting. +It also declares the four functions, +a type +.Fa regoff_t , +and a number of constants with names starting with ``REG_''. +.Pp +.Fn regcomp +compiles the regular expression contained in the +.Fa pattern +string, +subject to the flags in +.Fa cflags , +and places the results in the +.Fa regex_t +structure pointed to by +.Fa preg . +.Fa cflags +is the bitwise OR of zero or more of the following flags: +.Bl -tag -width XXXREG_EXTENDED +.It Dv REG_EXTENDED +Compile modern (``extended'') REs, rather than the obsolete +(``basic'') REs that are the default. +.It Dv REG_BASIC +This is a synonym for 0, +provided as a counterpart to REG_EXTENDED to improve readability. +.It Dv REG_NOSPEC +Compile with recognition of all special characters turned off. +All characters are thus considered ordinary, so the ``RE'' is a literal +string. +This is an extension, compatible with but not specified by +.St -p1003.2-92 , +and should be used with caution in software intended to be portable to +other systems. +.Dv REG_EXTENDED +and +.Dv REG_NOSPEC +may not be used in the same call to +.Fn regcomp . +.It Dv REG_ICASE +Compile for matching that ignores upper/lower case distinctions. +See +.Xr re_format 7 . +.It Dv REG_NOSUB +Compile for matching that need only report success or failure, not +what was matched. +.It Dv REG_NEWLINE +Compile for newline-sensitive matching. +By default, newline is a completely ordinary character with no special +meaning in either REs or strings. +With this flag, +`[^' bracket expressions and `.' never match newline, +a `^' anchor matches the null string after any newline in the string +in addition to its normal function, +and the `$' anchor matches the null string before any newline in the +string in addition to its normal function. +.It Dv REG_PEND +The regular expression ends, not at the first NUL, but just before the +character pointed to by the +.Fa re_endp +member of the structure pointed to by +.Fa preg . +The +.Fa re_endp +member is of type +.Fa "const\ char\ *" . +This flag permits inclusion of NULs in the RE; they are considered +ordinary characters. +This is an extension, compatible with but not specified by +.St -p1003.2-92 , +and should be used with caution in software intended to be portable to +other systems. +.El +.Pp +When successful, +.Fn regcomp +returns 0 and fills in the structure pointed to by +.Fa preg . +One member of that structure (other than +.Fa re_endp ) +is publicized: +.Fa re_nsub , +of type +.Fa size_t , +contains the number of parenthesized subexpressions within the RE +(except that the value of this member is undefined if the +.Dv REG_NOSUB +flag was used). +If +.Fn regcomp +fails, it returns a non-zero error code; +see +.Sx DIAGNOSTICS . +.Pp +.Fn regexec +matches the compiled RE pointed to by +.Fa preg +against the +.Fa string , +subject to the flags in +.Fa eflags , +and reports results using +.Fa nmatch , +.Fa pmatch , +and the returned value. +The RE must have been compiled by a previous invocation of +.Fn regcomp . +The compiled form is not altered during execution of +.Fn regexec , +so a single compiled RE can be used simultaneously by multiple threads. +.Pp +By default, +the NUL-terminated string pointed to by +.Fa string +is considered to be the text of an entire line, minus any terminating +newline. +The +.Fa eflags +argument is the bitwise OR of zero or more of the following flags: +.Bl -tag -width XXXREG_NOTBOL +.It Dv REG_NOTBOL +The first character of the string +is not the beginning of a line, so the `^' anchor should not match before it. +This does not affect the behavior of newlines under +.Dv REG_NEWLINE . +.It Dv REG_NOTEOL +The NUL terminating the string does not end a line, so the `$' anchor +should not match before it. +This does not affect the behavior of newlines under +.Dv REG_NEWLINE . +.It Dv REG_STARTEND +The string is considered to start at +.Fa string ++ +.Fa pmatch[0].rm_so +and to have a terminating NUL located at +.Fa string ++ +.Fa pmatch[0].rm_eo +(there need not actually be a NUL at that location), +regardless of the value of +.Fa nmatch . +See below for the definition of +.Fa pmatch +and +.Fa nmatch . +This is an extension, compatible with but not specified by +.St -p1003.2-92 , +and should be used with caution in software intended to be portable to +other systems. +Note that a non-zero +.Fa rm_so +does not imply +.Dv REG_NOTBOL ; +.Dv REG_STARTEND +affects only the location of the string, not how it is matched. +.El +.Pp +See +.Xr re_format 7 +for a discussion of what is matched in situations where an RE or a +portion thereof could match any of several substrings of +.Fa string . +.Pp +Normally, +.Fn regexec +returns 0 for success and the non-zero code +.Dv REG_NOMATCH +for failure. +Other non-zero error codes may be returned in exceptional situations; +see +.Sx DIAGNOSTICS . +.Pp +If +.Dv REG_NOSUB +was specified in the compilation of the RE, or if +.Fa nmatch +is 0, +.Fn regexec +ignores the +.Fa pmatch +argument (but see below for the case where +.Dv REG_STARTEND +is specified). +Otherwise, +.Fa pmatch +points to an array of +.Fa nmatch +structures of type +.Fa regmatch_t . +Such a structure has at least the members +.Fa rm_so +and +.Fa rm_eo , +both of type +.Fa regoff_t +(a signed arithmetic type at least as large as an +.Fa off_t +and a +.Fa ssize_t ) , +containing respectively the offset of the first character of a substring +and the offset of the first character after the end of the substring. +Offsets are measured from the beginning of the +.Fa string +argument given to +.Fn regexec . +An empty substring is denoted by equal offsets, +both indicating the character following the empty substring. +.Pp +The 0th member of the +.Fa pmatch +array is filled in to indicate what substring of +.Fa string +was matched by the entire RE. +Remaining members report what substring was matched by parenthesized +subexpressions within the RE; +member +.Fa i +reports subexpression +.Fa i , +with subexpressions counted (starting at 1) by the order of their +opening parentheses in the RE, left to right. +Unused entries in the array\(emcorresponding either to subexpressions that +did not participate in the match at all, or to subexpressions that do not +exist in the RE (that is, +.Fa i +\*[Gt] +.Fa preg-\*[Gt]re_nsub ) +\(emhave both +.Fa rm_so +and +.Fa rm_eo +set to -1. +If a subexpression participated in the match several times, +the reported substring is the last one it matched. +(Note, as an example in particular, that when the RE `(b*)+' matches `bbb', +the parenthesized subexpression matches each of the three `b's and then +an infinite number of empty strings following the last `b', +so the reported substring is one of the empties.) +.Pp +If +.Dv REG_STARTEND +is specified, +.Fa pmatch +must point to at least one +.Fa regmatch_t +(even if +.Fa nmatch +is 0 or +.Dv REG_NOSUB +was specified), +to hold the input offsets for +.Dv REG_STARTEND . +Use for output is still entirely controlled by +.Fa nmatch ; +if +.Fa nmatch +is 0 or +.Dv REG_NOSUB +was specified, +the value of +.Fa pmatch [0] +will not be changed by a successful +.Fn regexec . +.Pp +.Fn regerror +maps a non-zero +.Fa errcode +from either +.Fn regcomp +or +.Fn regexec +to a human-readable, printable message. +If +.Fa preg +is non-NULL, +the error code should have arisen from use of the +.Fa regex_t +pointed to by +.Fa preg , +and if the error code came from +.Fn regcomp , +it should have been the result from the most recent +.Fn regcomp +using that +.Fa regex_t . ( +.Fn regerror +may be able to supply a more detailed message using information +from the +.Fa regex_t . ) +.Fn regerror +places the NUL-terminated message into the buffer pointed to by +.Fa errbuf , +limiting the length (including the NUL) to at most +.Fa errbuf_size +bytes. +If the whole message won't fit, +as much of it as will fit before the terminating NUL is supplied. +In any case, +the returned value is the size of buffer needed to hold the whole +message (including terminating NUL). +If +.Fa errbuf_size +is 0, +.Fa errbuf +is ignored but the return value is still correct. +.Pp +If the +.Fa errcode +given to +.Fn regerror +is first ORed with +.Dv REG_ITOA , +the ``message'' that results is the printable name of the error code, +e.g. ``REG_NOMATCH'', +rather than an explanation thereof. +If +.Fa errcode +is +.Dv REG_ATOI , +then +.Fa preg +shall be non-NULL and the +.Fa re_endp +member of the structure it points to +must point to the printable name of an error code; +in this case, the result in +.Fa errbuf +is the decimal digits of +the numeric value of the error code +(0 if the name is not recognized). +.Dv REG_ITOA +and +.Dv REG_ATOI +are intended primarily as debugging facilities; +they are extensions, compatible with but not specified by +.St -p1003.2-92 , +and should be used with caution in software intended to be portable to +other systems. +Be warned also that they are considered experimental and changes are possible. +.Pp +.Fn regfree +frees any dynamically-allocated storage associated with the compiled RE +pointed to by +.Fa preg . +The remaining +.Fa regex_t +is no longer a valid compiled RE +and the effect of supplying it to +.Fn regexec +or +.Fn regerror +is undefined. +.Pp +None of these functions references global variables except for tables +of constants; +all are safe for use from multiple threads if the arguments are safe. +.Sh IMPLEMENTATION CHOICES +There are a number of decisions that +.St -p1003.2-92 +leaves up to the implementor, +either by explicitly saying ``undefined'' or by virtue of them being +forbidden by the RE grammar. +This implementation treats them as follows. +.Pp +See +.Xr re_format 7 +for a discussion of the definition of case-independent matching. +.Pp +There is no particular limit on the length of REs, +except insofar as memory is limited. +Memory usage is approximately linear in RE size, and largely insensitive +to RE complexity, except for bounded repetitions. +See BUGS for one short RE using them +that will run almost any system out of memory. +.Pp +A backslashed character other than one specifically given a magic meaning +by +.St -p1003.2-92 +(such magic meanings occur only in obsolete [``basic''] REs) +is taken as an ordinary character. +.Pp +Any unmatched [ is a +.Dv REG_EBRACK +error. +.Pp +Equivalence classes cannot begin or end bracket-expression ranges. +The endpoint of one range cannot begin another. +.Pp +.Dv RE_DUP_MAX , +the limit on repetition counts in bounded repetitions, is 255. +.Pp +A repetition operator (?, *, +, or bounds) cannot follow another +repetition operator. +A repetition operator cannot begin an expression or subexpression +or follow `^' or `|'. +.Pp +`|' cannot appear first or last in a (sub)expression or after another `|', +i.e. an operand of `|' cannot be an empty subexpression. +An empty parenthesized subexpression, `()', is legal and matches an +empty (sub)string. +An empty string is not a legal RE. +.Pp +A `{' followed by a digit is considered the beginning of bounds for a +bounded repetition, which must then follow the syntax for bounds. +A `{' \fInot\fR followed by a digit is considered an ordinary character. +.Pp +`^' and `$' beginning and ending subexpressions in obsolete (``basic'') +REs are anchors, not ordinary characters. +.Sh DIAGNOSTICS +Non-zero error codes from +.Fn regcomp +and +.Fn regexec +include the following: +.Pp +.Bl -tag -width XXXREG_ECOLLATE -compact +.It Dv REG_NOMATCH +regexec() failed to match +.It Dv REG_BADPAT +invalid regular expression +.It Dv REG_ECOLLATE +invalid collating element +.It Dv REG_ECTYPE +invalid character class +.It Dv REG_EESCAPE +\e applied to unescapable character +.It Dv REG_ESUBREG +invalid backreference number +.It Dv REG_EBRACK +brackets [ ] not balanced +.It Dv REG_EPAREN +parentheses ( ) not balanced +.It Dv REG_EBRACE +braces { } not balanced +.It Dv REG_BADBR +invalid repetition count(s) in { } +.It Dv REG_ERANGE +invalid character range in [ ] +.It Dv REG_ESPACE +ran out of memory +.It Dv REG_BADRPT +?, *, or + operand invalid +.It Dv REG_EMPTY +empty (sub)expression +.It Dv REG_ASSERT +``can't happen''\(emyou found a bug +.It Dv REG_INVARG +invalid argument, e.g. negative-length string +.El +.Sh SEE ALSO +.Xr grep 1 , +.Xr sed 1 , +.Xr re_format 7 +.Pp +.St -p1003.2-92 , +sections 2.8 (Regular Expression Notation) +and +B.5 (C Binding for Regular Expression Matching). +.Sh HISTORY +Originally written by Henry Spencer. +Altered for inclusion in the +.Bx 4.4 +distribution. +.Sh BUGS +There is one known functionality bug. +The implementation of internationalization is incomplete: +the locale is always assumed to be the default one of +.St -p1003.2-92 , +and only the collating elements etc. of that locale are available. +.Pp +The back-reference code is subtle and doubts linger about its correctness +in complex cases. +.Pp +.Fn regexec +performance is poor. +This will improve with later releases. +.Fa nmatch +exceeding 0 is expensive; +.Fa nmatch +exceeding 1 is worse. +.Fa regexec +is largely insensitive to RE complexity +.Em except +that back references are massively expensive. +RE length does matter; in particular, there is a strong speed bonus +for keeping RE length under about 30 characters, +with most special characters counting roughly double. +.Pp +.Fn regcomp +implements bounded repetitions by macro expansion, +which is costly in time and space if counts are large +or bounded repetitions are nested. +An RE like, say, +`((((a{1,100}){1,100}){1,100}){1,100}){1,100}' +will (eventually) run almost any existing machine out of swap space. +.Pp +There are suspected problems with response to obscure error conditions. +Notably, +certain kinds of internal overflow, +produced only by truly enormous REs or by multiply nested bounded repetitions, +are probably not handled well. +.Pp +Due to a mistake in +.St -p1003.2-92 , +things like `a)b' are legal REs because `)' is a special character +only in the presence of a previous unmatched `('. +This can't be fixed until the spec is fixed. +.Pp +The standard's definition of back references is vague. +For example, does +`a\e(\e(b\e)*\e2\e)*d' match `abbbd'? +Until the standard is clarified, behavior in such cases should not be +relied on. +.Pp +The implementation of word-boundary matching is a bit of a kludge, +and bugs may lurk in combinations of word-boundary matching and anchoring. diff --git a/compiler/clib/regex/regex2.h b/compiler/clib/regex/regex2.h index 13bbf64a73..6741a9d729 100644 --- a/compiler/clib/regex/regex2.h +++ b/compiler/clib/regex/regex2.h @@ -1,5 +1,6 @@ +/* $NetBSD: regex2.h,v 1.11 2004/03/26 22:42:17 enami Exp $ */ + /*- - * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -14,6 +15,43 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regex2.h 8.4 (Berkeley) 3/20/94 + */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -31,7 +69,6 @@ * SUCH DAMAGE. * * @(#)regex2.h 8.4 (Berkeley) 3/20/94 - * $FreeBSD: src/lib/libc/regex/regex2.h,v 1.11 2007/01/09 00:28:04 imp Exp $ */ /* @@ -72,91 +109,68 @@ * In state representations, an operator's bit is on to signify a state * immediately *preceding* "execution" of that operator. */ -typedef unsigned long sop; /* strip operator */ -typedef long sopno; -#define OPRMASK 0xf8000000L -#define OPDMASK 0x07ffffffL +typedef uint32_t sop; /* strip operator */ +typedef int sopno; +#define OPRMASK ((uint32_t)0xf8000000UL) +#define OPDMASK ((uint32_t)0x07ffffffUL) #define OPSHIFT ((unsigned)27) #define OP(n) ((n)&OPRMASK) -#define OPND(n) ((n)&OPDMASK) +#define OPND(n) ((int)((n)&OPDMASK)) #define SOP(op, opnd) ((op)|(opnd)) -/* operators meaning operand */ -/* (back, fwd are offsets) */ -#define OEND (1L< uch [csetsize] */ + uch mask; /* bit within array */ + uch hash; /* hash code */ + size_t smultis; + char *multis; /* -> char[smulti] ab\0cd\0ef\0\0 */ } cset; +/* note that CHadd and CHsub are unsafe, and CHIN doesn't yield 0/1 */ +#define CHadd(cs, c) ((cs)->ptr[(uch)(c)] |= (cs)->mask, (cs)->hash += (c)) +#define CHsub(cs, c) ((cs)->ptr[(uch)(c)] &= ~(cs)->mask, (cs)->hash -= (c)) +#define CHIN(cs, c) ((cs)->ptr[(uch)(c)] & (cs)->mask) +#define MCadd(p, cs, cp) mcadd(p, cs, cp) /* regcomp() internal fns */ +#define MCsub(p, cs, cp) mcsub(p, cs, cp) +#define MCin(p, cs, cp) mcin(p, cs, cp) -static int -CHIN1(cset *cs, wint_t ch) -{ - int i; - - assert(ch >= 0); - if (ch < NC) - return (((cs->bmp[ch >> 3] & (1 << (ch & 7))) != 0) ^ - cs->invert); - for (i = 0; i < cs->nwides; i++) - if (ch == cs->wides[i]) - return (!cs->invert); - for (i = 0; i < cs->nranges; i++) - if (cs->ranges[i].min <= ch && ch <= cs->ranges[i].max) - return (!cs->invert); - for (i = 0; i < cs->ntypes; i++) - if (iswctype(ch, cs->types[i])) - return (!cs->invert); - return (cs->invert); -} - -static __inline int -CHIN(cset *cs, wint_t ch) -{ - - assert(ch >= 0); - if (ch < NC) - return (((cs->bmp[ch >> 3] & (1 << (ch & 7))) != 0) ^ - cs->invert); - else if (cs->icase) - return (CHIN1(cs, ch) || CHIN1(cs, towlower(ch)) || - CHIN1(cs, towupper(ch))); - else - return (CHIN1(cs, ch)); -} +/* stuff for character categories */ +typedef unsigned char cat_t; /* * main compiled-expression structure @@ -165,8 +179,10 @@ struct re_guts { int magic; # define MAGIC2 ((('R'^0200)<<8)|'E') sop *strip; /* malloced area for strip */ + int csetsize; /* number of bits in a cset vector */ int ncsets; /* number of csets in use */ cset *sets; /* -> cset [ncsets] */ + uch *setbits; /* -> uch[csetsize][ncsets/CHAR_BIT] */ int cflags; /* copy of regcomp() cflags argument */ sopno nstates; /* = number of sops */ sopno firststate; /* the initial OEND (normally 0) */ @@ -177,16 +193,17 @@ struct re_guts { # define BAD 04 /* something wrong */ int nbol; /* number of ^ used */ int neol; /* number of $ used */ + int ncategories; /* how many character categories */ + cat_t *categories; /* ->catspace[-CHAR_MIN] */ char *must; /* match must contain this string */ - int moffset; /* latest point at which must may be located */ - int *charjump; /* Boyer-Moore char jump table */ - int *matchjump; /* Boyer-Moore match jump table */ int mlen; /* length of must */ - size_t nsub; /* copy of re_nsub */ + sopno nsub; /* copy of re_nsub */ int backrefs; /* does it use back references? */ sopno nplus; /* how deep does it nest +s? */ + /* catspace must be last */ + cat_t catspace[1]; /* actually [NC] */ }; /* misc utilities */ -#define OUT (CHAR_MIN - 1) /* a non-character value */ -#define ISWORD(c) (iswalnum((uch)(c)) || (c) == '_') +#define OUT (CHAR_MAX+1) /* a non-character value */ +#define ISWORD(c) (isalnum((unsigned char)c) || (c) == '_') diff --git a/compiler/clib/regex/regexec.c b/compiler/clib/regex/regexec.c index 4bc04ae6bd..ad53f0499f 100644 --- a/compiler/clib/regex/regexec.c +++ b/compiler/clib/regex/regexec.c @@ -1,5 +1,6 @@ +/* $NetBSD: regexec.c,v 1.20 2007/02/09 23:44:18 junyoung Exp $ */ + /*- - * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -14,6 +15,43 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regexec.c 8.3 (Berkeley) 3/20/94 + */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -33,81 +71,56 @@ * @(#)regexec.c 8.3 (Berkeley) 3/20/94 */ -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)regexec.c 8.3 (Berkeley) 3/20/94"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD: src/lib/libc/regex/regexec.c,v 1.8 2007/06/11 03:05:54 delphij Exp $"); +/* +__RCSID("$NetBSD: regexec.c,v 1.20 2007/02/09 23:44:18 junyoung Exp $"); +*/ + +#if defined(__AROS__) +#if !DEBUG +#define NDEBUG +#else +#define REDEBUG +#endif +#endif /* * the outer shell of regexec() * - * This file includes engine.c three times, after muchos fiddling with the + * This file includes engine.c *twice*, after muchos fiddling with the * macros that code uses. This lets the same code operate on two different - * representations for state sets and characters. + * representations for state sets. */ #include + +#include +#include +#include #include #include #include -#include -#include #include -#include -#include + +#ifdef __weak_alias +__weak_alias(regexec,_regexec) +#endif #include "utils.h" #include "regex2.h" -static int nope __unused = 0; /* for use in asserts; shuts lint up */ - -static __inline size_t -xmbrtowc(wint_t *wi, const char *s, size_t n, mbstate_t *mbs, wint_t dummy) -{ - size_t nr; - wchar_t wc; - - nr = mbrtowc(&wc, s, n, mbs); - if (wi != NULL) - *wi = wc; - if (nr == 0) - return (1); - else if (nr == (size_t)-1 || nr == (size_t)-2) { - memset(mbs, 0, sizeof(*mbs)); - if (wi != NULL) - *wi = dummy; - return (1); - } else - return (nr); -} - -static __inline size_t -xmbrtowc_dummy(wint_t *wi, - const char *s, - size_t n __unused, - mbstate_t *mbs __unused, - wint_t dummy __unused) -{ - - if (wi != NULL) - *wi = (unsigned char)*s; - return (1); -} - /* macros for manipulating states, small version */ -#define states long -#define states1 states /* for later use in regexec() decision */ +#define states unsigned long +#define states1 unsigned long /* for later use in regexec() decision */ #define CLEAR(v) ((v) = 0) #define SET0(v, n) ((v) &= ~((unsigned long)1 << (n))) #define SET1(v, n) ((v) |= (unsigned long)1 << (n)) #define ISSET(v, n) (((v) & ((unsigned long)1 << (n))) != 0) #define ASSIGN(d, s) ((d) = (s)) #define EQ(a, b) ((a) == (b)) -#define STATEVARS long dummy /* dummy version */ +#define STATEVARS int dummy /* dummy version */ #define STATESETUP(m, n) /* nothing */ #define STATETEARDOWN(m) /* nothing */ #define SETUP(v) ((v) = 0) -#define onestate long +#define onestate unsigned long #define INIT(o, n) ((o) = (unsigned long)1 << (n)) #define INC(o) ((o) <<= 1) #define ISSTATEIN(v, o) (((v) & (o)) != 0) @@ -116,9 +129,6 @@ xmbrtowc_dummy(wint_t *wi, #define FWD(dst, src, n) ((dst) |= ((unsigned long)(src)&(here)) << (n)) #define BACK(dst, src, n) ((dst) |= ((unsigned long)(src)&(here)) >> (n)) #define ISSETBACK(v, n) (((v) & ((unsigned long)here >> (n))) != 0) -/* no multibyte support */ -#define XMBRTOWC xmbrtowc_dummy -#define ZAPSTATE(mbs) ((void)(mbs)) /* function names */ #define SNAMES /* engine.c looks after details */ @@ -144,24 +154,25 @@ xmbrtowc_dummy(wint_t *wi, #undef BACK #undef ISSETBACK #undef SNAMES -#undef XMBRTOWC -#undef ZAPSTATE /* macros for manipulating states, large version */ #define states char * -#define CLEAR(v) memset(v, 0, m->g->nstates) +#define CLEAR(v) memset(v, 0, (size_t)m->g->nstates) #define SET0(v, n) ((v)[n] = 0) #define SET1(v, n) ((v)[n] = 1) #define ISSET(v, n) ((v)[n]) -#define ASSIGN(d, s) memcpy(d, s, m->g->nstates) -#define EQ(a, b) (memcmp(a, b, m->g->nstates) == 0) -#define STATEVARS long vn; char *space -#define STATESETUP(m, nv) { (m)->space = malloc((nv)*(m)->g->nstates); \ - if ((m)->space == NULL) return(REG_ESPACE); \ - (m)->vn = 0; } -#define STATETEARDOWN(m) { free((m)->space); } -#define SETUP(v) ((v) = &m->space[m->vn++ * m->g->nstates]) -#define onestate long +#define ASSIGN(d, s) memcpy(d, s, (size_t)m->g->nstates) +#define EQ(a, b) (memcmp(a, b, (size_t)m->g->nstates) == 0) +#define STATEVARS int vn; char *space +#define STATESETUP(m, nv) \ + if (((m)->space = malloc((size_t)((nv)*(m)->g->nstates))) == NULL) \ + return(REG_ESPACE); \ + else \ + (m)->vn = 0 + +#define STATETEARDOWN(m) { free((m)->space); m->space = NULL; } +#define SETUP(v) ((v) = &m->space[(size_t)(m->vn++ * m->g->nstates)]) +#define onestate int #define INIT(o, n) ((o) = (n)) #define INC(o) ((o)++) #define ISSTATEIN(v, o) ((v)[o]) @@ -170,24 +181,11 @@ xmbrtowc_dummy(wint_t *wi, #define FWD(dst, src, n) ((dst)[here+(n)] |= (src)[here]) #define BACK(dst, src, n) ((dst)[here-(n)] |= (src)[here]) #define ISSETBACK(v, n) ((v)[here - (n)]) -/* no multibyte support */ -#define XMBRTOWC xmbrtowc_dummy -#define ZAPSTATE(mbs) ((void)(mbs)) /* function names */ #define LNAMES /* flag */ #include "engine.c" -/* multibyte character & large states version */ -#undef LNAMES -#undef XMBRTOWC -#undef ZAPSTATE -#define XMBRTOWC xmbrtowc -#define ZAPSTATE(mbs) memset((mbs), 0, sizeof(*(mbs))) -#define MNAMES - -#include "engine.c" - /* - regexec - interface for matching = extern int regexec(const regex_t *, const char *, size_t, \ @@ -204,19 +202,24 @@ xmbrtowc_dummy(wint_t *wi, * have been prototyped. */ int /* 0 success, REG_NOMATCH failure */ -regexec(const regex_t * __restrict preg, - const char * __restrict string, - size_t nmatch, - regmatch_t pmatch[__restrict], - int eflags) +regexec( + const regex_t *preg, + const char *string, + size_t nmatch, + regmatch_t pmatch[], + int eflags) { struct re_guts *g = preg->re_g; + char *s; #ifdef REDEBUG # define GOODFLAGS(f) (f) #else # define GOODFLAGS(f) ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND)) #endif + assert(preg != NULL); + assert(string != NULL); + if (preg->re_magic != MAGIC1 || g->magic != MAGIC2) return(REG_BADPAT); assert(!(g->iflags&BAD)); @@ -224,10 +227,10 @@ regexec(const regex_t * __restrict preg, return(REG_BADPAT); eflags = GOODFLAGS(eflags); - if (MB_CUR_MAX > 1) - return(mmatcher(g, (char *)string, nmatch, pmatch, eflags)); - else if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags®_LARGE)) - return(smatcher(g, (char *)string, nmatch, pmatch, eflags)); + s = (char *)string; + + if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags®_LARGE)) + return(smatcher(g, s, nmatch, pmatch, eflags)); else - return(lmatcher(g, (char *)string, nmatch, pmatch, eflags)); + return(lmatcher(g, s, nmatch, pmatch, eflags)); } diff --git a/compiler/clib/regex/regfree.c b/compiler/clib/regex/regfree.c index aa795fa783..4f881f30d2 100644 --- a/compiler/clib/regex/regfree.c +++ b/compiler/clib/regex/regfree.c @@ -1,5 +1,6 @@ +/* $NetBSD: regfree.c,v 1.15 2007/02/09 23:44:18 junyoung Exp $ */ + /*- - * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -14,6 +15,43 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)regfree.c 8.3 (Berkeley) 3/20/94 + */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -33,19 +71,28 @@ * @(#)regfree.c 8.3 (Berkeley) 3/20/94 */ -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)regfree.c 8.3 (Berkeley) 3/20/94"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD: src/lib/libc/regex/regfree.c,v 1.8 2007/06/11 03:05:54 delphij Exp $"); +/* +__RCSID("$NetBSD: regfree.c,v 1.15 2007/02/09 23:44:18 junyoung Exp $"); +*/ + +#if defined(__AROS__) +#if !DEBUG +#define NDEBUG +#else +#define REDEBUG +#endif +#endif #include + +#include #include #include -#include #include -#include -#include + +#ifdef __weak_alias +__weak_alias(regfree,_regfree) +#endif #include "utils.h" #include "regex2.h" @@ -55,11 +102,14 @@ __FBSDID("$FreeBSD: src/lib/libc/regex/regfree.c,v 1.8 2007/06/11 03:05:54 delph = extern void regfree(regex_t *); */ void -regfree(regex_t *preg) +regfree( + regex_t *preg) { struct re_guts *g; - int i; + assert(preg != NULL); + + assert(preg->re_magic == MAGIC1); if (preg->re_magic != MAGIC1) /* oops */ return; /* nice to complain, but hard */ @@ -70,20 +120,12 @@ regfree(regex_t *preg) g->magic = 0; /* mark it invalid */ if (g->strip != NULL) - free((char *)g->strip); - if (g->sets != NULL) { - for (i = 0; i < g->ncsets; i++) { - free(g->sets[i].ranges); - free(g->sets[i].wides); - free(g->sets[i].types); - } - free((char *)g->sets); - } + free(g->strip); + if (g->sets != NULL) + free(g->sets); + if (g->setbits != NULL) + free(g->setbits); if (g->must != NULL) free(g->must); - if (g->charjump != NULL) - free(&g->charjump[CHAR_MIN]); - if (g->matchjump != NULL) - free(g->matchjump); - free((char *)g); + free(g); } diff --git a/compiler/clib/regex/utils.h b/compiler/clib/regex/utils.h index 2a2ed9694d..762caeeb69 100644 --- a/compiler/clib/regex/utils.h +++ b/compiler/clib/regex/utils.h @@ -1,5 +1,6 @@ +/* $NetBSD: utils.h,v 1.6 2003/08/07 16:43:21 agc Exp $ */ + /*- - * Copyright (c) 1992, 1993, 1994 Henry Spencer. * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -14,6 +15,43 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)utils.h 8.3 (Berkeley) 3/20/94 + */ + +/*- + * Copyright (c) 1992, 1993, 1994 Henry Spencer. + * + * This code is derived from software contributed to Berkeley by + * Henry Spencer. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -31,7 +69,6 @@ * SUCH DAMAGE. * * @(#)utils.h 8.3 (Berkeley) 3/20/94 - * $FreeBSD: src/lib/libc/regex/utils.h,v 1.3 2007/01/09 00:28:04 imp Exp $ */ /* utility definitions */ -- 2.11.4.GIT