History

moved RegEx type out of core and into RegEx.chug

Ge Wang committed 3 years ago

Commit 2cd0f171 parent c13c0ea35 files · +66 −9794Browse files

Showing the changes to src (35 of 35 files). Show all

Unified · Split

35 files
  1. src/core/chuck_compile.cpp +0 −10
  2. src/core/makefile +1 −1
  3. src/core/makefile.x/makefile.win32 +63 −63
  4. src/core/regex/LICENSE.txt +0 −29
  5. src/core/regex/README.txt +0 −235
  6. src/core/regex/config.h +0 −186
  7. src/core/regex/regcomp.c +0 −129
  8. src/core/regex/regerror.c +0 −83
  9. src/core/regex/regex.h +0 −38
  10. src/core/regex/regexec.c +0 −348
  11. src/core/regex/tre-ast.c +0 −226
  12. src/core/regex/tre-ast.h +0 −128
  13. src/core/regex/tre-compile.c +0 −2296
  14. src/core/regex/tre-compile.h +0 −27
  15. src/core/regex/tre-config.h +0 −52
  16. src/core/regex/tre-filter.c +0 −73
  17. src/core/regex/tre-filter.h +0 −19
  18. src/core/regex/tre-internal.h +0 −287
  19. src/core/regex/tre-match-approx.c +0 −812
  20. src/core/regex/tre-match-backtrack.c +0 −666
  21. src/core/regex/tre-match-parallel.c +0 −501
  22. src/core/regex/tre-match-utils.h +0 −215
  23. src/core/regex/tre-mem.c +0 −155
  24. src/core/regex/tre-mem.h +0 −66
  25. src/core/regex/tre-parse.c +0 −1739
  26. src/core/regex/tre-parse.h +0 −50
  27. src/core/regex/tre-stack.c +0 −125
  28. src/core/regex/tre-stack.h +0 −76
  29. src/core/regex/tre.h +0 −276
  30. src/core/regex/xmalloc.c +0 −351
  31. src/core/regex/xmalloc.h +0 −77
  32. src/core/ulib_regex.cpp +0 −407
  33. src/core/ulib_regex.h +0 −40
  34. src/makefile +2 −2
  35. src/xcode/chuck.xcodeproj/project.pbxproj +0 −6
src/core/chuck_compile.cpp+0−10
@@ -54,11 +54,6 @@ · 53 unmodified lines
5454 #include "ulib_opsc.h"
5555 #endif
5656
57−// 1.5.0.0 (ge) | chunreal
58−#ifndef __DISABLE_REGEX__
59−#include "ulib_regex.h"
60−#endif
61−
6257 #if defined(__PLATFORM_WIN32__)
6358 #include "dirent_win32.h"
6459 #else
@@ -706,11 +701,6 @@ t_CKBOOL load_internal_modules( Chuck_Compiler * compiler ) · 641 unmodified lines
706701 if( !load_module( compiler, env, opensoundcontrol_query, "opsc", "global" ) ) goto error;
707702 #endif
708703
709− #ifndef __DISABLE_REGEX__
710− EM_log( CK_LOG_SEVERE, "module 'RegEx'" );
711− if( !load_module( compiler, env, regex_query, "RegEx", "global" ) ) goto error;
712− #endif
713−
714704 // deprecated:
715705 // if( !load_module( compiler, env, net_query, "net", "global" ) ) goto error;
716706
src/core/makefile+1−1
@@ -83,7 +83,7 @@ CXXSRCS_CORE+= chuck_absyn.cpp chuck_parse.cpp chuck_errmsg.cpp \ · 82 unmodified lines
8383 midiio_rtmidi.cpp rtmidi.cpp hidio_sdl.cpp \
8484 ugen_osc.cpp ugen_filter.cpp ugen_stk.cpp ugen_xxx.cpp \
8585 ulib_ai.cpp ulib_doc.cpp ulib_machine.cpp ulib_math.cpp \
86− ulib_std.cpp ulib_opsc.cpp ulib_regex.cpp util_buffers.cpp \
86+ ulib_std.cpp ulib_opsc.cpp util_buffers.cpp \
8787 util_console.cpp util_string.cpp util_thread.cpp util_opsc.cpp \
8888 util_serial.cpp util_hid.cpp uana_xform.cpp uana_extract.cpp
8989 LO_CSRCS+= lo/address.c lo/blob.c lo/bundle.c lo/message.c lo/method.c \
src/core/makefile.x/makefile.win32+63−63
@@ -1,63 +1,63 @@
1−# NOTE: chuck_win32.h and chuck_win32.c come from the output of
2−# chuck.lex and chuck.y
3−#
4−# > flex -ochuck.yy.c chuck.lex
5−# > bison -dv -b chuck chuck.y
6−#
7−# to create the chuck_win32 files:
8−#
9−# > cat chuck.tab.c chuck.yy.c > chuck_win32.c
10−# > cp chuck.tab.h chuck_win32.h
11−#
12−# ALSO: we are actually now building in 64-bit, but yeah.
13−
14−MSBUILD=msbuild.exe
15−RTAUDIODIR=rtaudio
16−
17−ifneq (,$(CHUCK_DEBUG))
18−CONFIG=Debug
19−CHUCK_BIN=Debug/chuck.exe
20−else
21−CONFIG=Release
22−CHUCK_BIN=Release/chuck.exe
23−endif
24−
25−CSRCS+= chuck_win32.c util_math.c util_network.c util_raw.c \
26− util_xforms.c
27−CXXSRCS+= chuck_absyn.cpp chuck_parse.cpp chuck_errmsg.cpp \
28− chuck_frame.cpp chuck_symbol.cpp chuck_table.cpp chuck_utils.cpp \
29− chuck_vm.cpp chuck_instr.cpp chuck_scan.cpp chuck_type.cpp chuck_emit.cpp \
30− chuck_compile.cpp chuck_dl.cpp chuck_oo.cpp chuck_lang.cpp chuck_ugen.cpp \
31− chuck_otf.cpp chuck_stats.cpp chuck_shell.cpp \
32− chuck_io.cpp chuck_carrier.cpp chuck.cpp \
33− hidio_sdl.cpp \
34− midiio_rtmidi.cpp rtmidi.cpp ugen_osc.cpp ugen_filter.cpp \
35− ugen_stk.cpp ugen_xxx.cpp ulib_machine.cpp ulib_math.cpp ulib_std.cpp \
36− ulib_opsc.cpp ulib_regex.cpp util_buffers.cpp util_console.cpp \
37− util_string.cpp util_thread.cpp util_opsc.cpp util_serial.cpp \
38− util_hid.cpp uana_xform.cpp uana_extract.cpp
39−CXXINC_HOST+= -I${RTAUDIODIR} -I${RTAUDIODIR}/include
40−CXXSRCS_HOST+= chuck_main.cpp chuck_audio.cpp chuck_console.cpp ../${RTAUDIODIR}/RtAudio.cpp
41−LO_CSRCS+= lo/address.c lo/blob.c lo/bundle.c lo/message.c lo/method.c \
42− lo/pattern_match.c lo/send.c lo/server.c lo/server_thread.c lo/timetag.c
43−
44−CSRCS:=$(addprefix core/,$(CSRCS))
45−CXXSRCS:=$(addprefix core/,$(CXXSRCS))
46−CXXSRCS_HOST:=$(addprefix host/,$(CXXSRCS_HOST))
47−LO_CSRCS:=$(addprefix core/,$(LO_CSRCS))
48−
49−CXXOBJS_HOST=$(addprefix $(HOSTDIR)/,$(CXXSRCS_HOST:.cpp=.o))
50−
51−COBJS=$(COBJS_HOST) $(addprefix $(COREDIR)/,$(COBJS_CORE))
52−CXXOBJS=$(CXXOBJS_HOST) $(addprefix $(COREDIR)/,$(CXXOBJS_CORE))
53−LO_COBJS=$(addprefix $(COREDIR)/,$(LO_COBJS_CORE))
54−SF_COBJS=$(addprefix $(COREDIR)/,$(SF_CSRCS:.c=.o))
55−OBJS=$(COBJS) $(CXXOBJS) $(LO_COBJS) $(SF_COBJS)
56−SRCS=$(CSRCS) $(CXXSRCS) $(CXXSRCS_HOST) $(LO_CSRCS)
57−
58−$(CHUCK_BIN): $(SRCS)
59− $(MSBUILD) visual-studio/chuck.sln /p:Configuration=$(CONFIG)
60−
61−clean:
62− $(MSBUILD) visual-studio/chuck.sln /p:Configuration=$(CONFIG) /t:Clean
63−
1+# NOTE: chuck_win32.h and chuck_win32.c come from the output of
2+# chuck.lex and chuck.y
3+#
4+# > flex -ochuck.yy.c chuck.lex
5+# > bison -dv -b chuck chuck.y
6+#
7+# to create the chuck_win32 files:
8+#
9+# > cat chuck.tab.c chuck.yy.c > chuck_win32.c
10+# > cp chuck.tab.h chuck_win32.h
11+#
12+# ALSO: we are actually now building in 64-bit, but yeah.
13+
14+MSBUILD=msbuild.exe
15+RTAUDIODIR=rtaudio
16+
17+ifneq (,$(CHUCK_DEBUG))
18+CONFIG=Debug
19+CHUCK_BIN=Debug/chuck.exe
20+else
21+CONFIG=Release
22+CHUCK_BIN=Release/chuck.exe
23+endif
24+
25+CSRCS+= chuck_win32.c util_math.c util_network.c util_raw.c \
26+ util_xforms.c
27+CXXSRCS+= chuck_absyn.cpp chuck_parse.cpp chuck_errmsg.cpp \
28+ chuck_frame.cpp chuck_symbol.cpp chuck_table.cpp chuck_utils.cpp \
29+ chuck_vm.cpp chuck_instr.cpp chuck_scan.cpp chuck_type.cpp chuck_emit.cpp \
30+ chuck_compile.cpp chuck_dl.cpp chuck_oo.cpp chuck_lang.cpp chuck_ugen.cpp \
31+ chuck_otf.cpp chuck_stats.cpp chuck_shell.cpp \
32+ chuck_io.cpp chuck_carrier.cpp chuck.cpp \
33+ hidio_sdl.cpp \
34+ midiio_rtmidi.cpp rtmidi.cpp ugen_osc.cpp ugen_filter.cpp \
35+ ugen_stk.cpp ugen_xxx.cpp ulib_machine.cpp ulib_math.cpp ulib_std.cpp \
36+ ulib_opsc.cpp util_buffers.cpp util_console.cpp \
37+ util_string.cpp util_thread.cpp util_opsc.cpp util_serial.cpp \
38+ util_hid.cpp uana_xform.cpp uana_extract.cpp
39+CXXINC_HOST+= -I${RTAUDIODIR} -I${RTAUDIODIR}/include
40+CXXSRCS_HOST+= chuck_main.cpp chuck_audio.cpp chuck_console.cpp ../${RTAUDIODIR}/RtAudio.cpp
41+LO_CSRCS+= lo/address.c lo/blob.c lo/bundle.c lo/message.c lo/method.c \
42+ lo/pattern_match.c lo/send.c lo/server.c lo/server_thread.c lo/timetag.c
43+
44+CSRCS:=$(addprefix core/,$(CSRCS))
45+CXXSRCS:=$(addprefix core/,$(CXXSRCS))
46+CXXSRCS_HOST:=$(addprefix host/,$(CXXSRCS_HOST))
47+LO_CSRCS:=$(addprefix core/,$(LO_CSRCS))
48+
49+CXXOBJS_HOST=$(addprefix $(HOSTDIR)/,$(CXXSRCS_HOST:.cpp=.o))
50+
51+COBJS=$(COBJS_HOST) $(addprefix $(COREDIR)/,$(COBJS_CORE))
52+CXXOBJS=$(CXXOBJS_HOST) $(addprefix $(COREDIR)/,$(CXXOBJS_CORE))
53+LO_COBJS=$(addprefix $(COREDIR)/,$(LO_COBJS_CORE))
54+SF_COBJS=$(addprefix $(COREDIR)/,$(SF_CSRCS:.c=.o))
55+OBJS=$(COBJS) $(CXXOBJS) $(LO_COBJS) $(SF_COBJS)
56+SRCS=$(CSRCS) $(CXXSRCS) $(CXXSRCS_HOST) $(LO_CSRCS)
57+
58+$(CHUCK_BIN): $(SRCS)
59+ $(MSBUILD) visual-studio/chuck.sln /p:Configuration=$(CONFIG)
60+
61+clean:
62+ $(MSBUILD) visual-studio/chuck.sln /p:Configuration=$(CONFIG) /t:Clean
63+
src/core/regex/LICENSE.txt+0−29
@@ -1,29 +0,0 @@
1−This is the license, copyright notice, and disclaimer for TRE, a regex
2−matching package (library and tools) with support for approximate
3−matching.
4−
5−Copyright (c) 2001-2009 Ville Laurikari <vl@iki.fi>
6−All rights reserved.
7−
8−Redistribution and use in source and binary forms, with or without
9−modification, are permitted provided that the following conditions
10−are met:
11−
12− 1. Redistributions of source code must retain the above copyright
13− notice, this list of conditions and the following disclaimer.
14−
15− 2. Redistributions in binary form must reproduce the above copyright
16− notice, this list of conditions and the following disclaimer in the
17− documentation and/or other materials provided with the distribution.
18−
19−THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
20−``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21−LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22−A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23−HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24−SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25−LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26−DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27−THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28−(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29−OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
src/core/regex/README.txt+0−235
@@ -1,235 +0,0 @@
1−Introduction
2−
3− TRE is a lightweight, robust, and efficient POSIX compliant regexp
4− matching library with some exciting features such as approximate
5− (fuzzy) matching.
6−
7− The matching algorithm used in TRE uses linear worst-case time in
8− the length of the text being searched, and quadratic worst-case
9− time in the length of the used regular expression. In other words,
10− the time complexity of the algorithm is O(M^2N), where M is the
11− length of the regular expression and N is the length of the
12− text. The used space is also quadratic on the length of the regex,
13− but does not depend on the searched string. This quadratic
14− behaviour occurs only on pathological cases which are probably very
15− rare in practice.
16−
17−Features
18−
19− TRE is not just yet another regexp matcher. TRE has some features
20− which are not there in most free POSIX compatible
21− implementations. Most of these features are not present in non-free
22− implementations either, for that matter.
23−
24−Approximate matching
25−
26− Approximate pattern matching allows matches to be approximate, that
27− is, allows the matches to be close to the searched pattern under
28− some measure of closeness. TRE uses the edit-distance measure (also
29− known as the Levenshtein distance) where characters can be
30− inserted, deleted, or substituted in the searched text in order to
31− get an exact match. Each insertion, deletion, or substitution adds
32− the distance, or cost, of the match. TRE can report the matches
33− which have a cost lower than some given threshold value. TRE can
34− also be used to search for matches with the lowest cost.
35−
36− TRE includes a version of the agrep (approximate grep) command line
37− tool for approximate regexp matching in the style of grep. Unlike
38− other agrep implementations (like the one by Sun Wu and Udi Manber
39− from University of Arizona available here) TRE agrep allows full
40− regexps of any length, any number of errors, and non-uniform costs
41− for insertion, deletion and substitution.
42−
43−Strict standard conformance
44−
45− POSIX defines the behaviour of regexp functions precisely. TRE
46− attempts to conform to these specifications as strictly as
47− possible. TRE always returns the correct matches for subpatterns,
48− for example. Very few other implementations do this correctly. In
49− fact, the only other implementations besides TRE that I am aware of
50− (free or not) that get it right are Rx by Tom Lord, Regex++ by John
51− Maddock, and the AT&T ast regex by Glenn Fowler and Doug McIlroy.
52−
53− The standard TRE tries to conform to is the IEEE Std 1003.1-2001,
54− or Open Group Base Specifications Issue 6, commonly referred to as
55− "POSIX". It can be found online here. The relevant parts are the
56− base specifications on regular expressions (and the rationale) and
57− the description of the regcomp() API.
58−
59− For an excellent survey on POSIX regexp matchers, see the testregex
60− pages by Glenn Fowler of AT&T Labs Research.
61−
62−Predictable matching speed
63−
64− Because of the matching algorithm used in TRE, the maximum time
65− consumed by any regexec() call is always directly proportional to
66− the length of the searched string. There is one exception: if back
67− references are used, the matching may take time that grows
68− exponentially with the length of the string. This is because
69− matching back references is an NP complete problem, and almost
70− certainly requires exponential time to match in the worst case.
71−
72−Predictable and modest memory consumption
73−
74− A regexec() call never allocates memory from the heap. TRE
75− allocates all the memory it needs during a regcomp() call, and some
76− temporary working space from the stack frame for the duration of
77− the regexec() call. The amount of temporary space needed is
78− constant during matching and does not depend on the searched
79− string. For regexps of reasonable size TRE needs less than 50K of
80− dynamically allocated memory during the regcomp() call, less than
81− 20K for the compiled pattern buffer, and less than two kilobytes of
82− temporary working space from the stack frame during a regexec()
83− call. There is no time/memory tradeoff. TRE is also small in code
84− size; statically linking with TRE increases the executable size
85− less than 30K (gcc-3.2, x86, GNU/Linux).
86−
87−Wide character and multibyte character set support
88−
89− TRE supports multibyte character sets. This makes it possible to
90− use regexps seamlessly with, for example, Japanese locales. TRE
91− also provides a wide character API.
92−
93−Binary pattern and data support
94−
95− TRE provides APIs which allow binary zero characters both in
96− regexps and searched strings. The standard API cannot be easily
97− used to, for example, search for printable words from binary data
98− (although it is possible with some hacking). Searching for patterns
99− which contain binary zeroes embedded is not possible at all with
100− the standard API.
101−
102−Completely thread safe
103−
104− TRE is completely thread safe. All the exported functions are
105− re-entrant, and a single compiled regexp object can be used
106− simultaneously in multiple contexts; e.g. in main() and a signal
107− handler, or in many threads of a multithreaded application.
108−
109−Portable
110−
111− TRE is portable across multiple platforms. Here's a table of
112− platforms and compilers that have been successfully used to compile
113− and run TRE:
114−
115− Platform(s) | Compiler(s)
116− ----------------------------------+------------
117− AIX 4.3.2 - 5.3.0 | GCC, C for AIX compiler version 5
118− Compaq Tru64 UNIX V5.1A/B | Compaq C V6.4-014 - V6.5-011
119− Cygwin 1.3 - 1.5 | GCC
120− Digital UNIX V4.0 | DEC C V5.9-005
121− FreeBSD 4 and above | GCC
122− GNU/Linux systems on x86, x86_64, | GCC
123− ppc64, s390 |
124− HP-UX 10.20- 11.00 | GCC, HP C Compiler
125− IRIX 6.5 | GCC, MIPSpro Compilers 7.3.1.3m
126− Max OS X |
127− NetBSD 1.5 and above | GCC, egcs
128− OpenBSD 3.3 and above | GCC
129− Solaris 2.7-10 sparc/x86 | GCC, Sun Workshop 6 compilers
130− Windows 98 - XP | Microsoft Visual C++ 6.0
131−
132− TRE 0.7.5 should compile without changes on all of the above
133− platforms. Tell me if you are using TRE on a platform that is not
134− listed above, and I'll add it to the list. Also let me know if TRE
135− does not work on a listed platform.
136−
137− Depending on the platform, you may need to install libutf8 to get
138− wide character and multibyte character set support.
139−
140− Free
141−
142− TRE is released under a license which is essentially the same as
143− the "2 clause" BSD-style license used in NetBSD. See the file
144− LICENSE for details.
145−
146−Roadmap
147−
148− There are currently two features, both related to collating
149− elements, missing from 100% POSIX compliance. These are:
150−
151− * Support for collating elements (e.g. [[.<X>.]], where <X> is a
152− collating element). It is not possible to support
153− multi-character collating elements portably, since POSIX does
154− not define a way to determine whether a character sequence is a
155− multi-character collating element or not.
156−
157− * Support for equivalence classes, for example [[=<X>=]], where
158− <X> is a collating element. An equivalence class matches any
159− character which has the same primary collation weight as
160− <X>. Again, POSIX provides no portable mechanism for
161− determining the primary collation weight of a collating
162− element.
163−
164− Note that other portable regexp implementations don't support
165− collating elements either. The single exception is Regex++, which
166− comes with its own database for collating elements for different
167− locales. Support for collating elements and equivalence classes has
168− not been widely requested and is not very high on the TODO list at
169− the moment.
170−
171− These are other features I'm planning to implement real soon now:
172−
173− * All the missing GNU extensions enabled in GNU regex, such as
174− [[:<:]] and [[:>:]]
175−
176− * A REG_SHORTEST regexec() flag for returning the shortest match
177− instead of the longest match.
178−
179− * Perl-compatible syntax
180−
181− [:^class:]
182− Matches anything but the characters in class. Note that
183− [^[:class:]] works already, this would be just a
184− convenience shorthand.
185−
186− \A
187− Match only at beginning of string
188−
189− \Z
190− Match only at end of string, or before newline at the end
191−
192− \z
193− Match only at end of string
194−
195− \l
196− Lowercase next char (think vi)
197−
198− \u
199− Uppercase next char (think vi)
200−
201− \L
202− Lowercase till \E (think vi)
203−
204− \U
205− Uppercase till \E (think vi)
206−
207− (?=pattern)
208− Zero-width positive look-ahead assertions.
209−
210− (?!pattern)
211− Zero-width negative look-ahead assertions.
212−
213− (?<=pattern)
214− Zero-width positive look-behind assertions.
215−
216− (?<!pattern)
217− Zero-width negative look-behind assertions.
218−
219− Documentation especially for the nonstandard features of TRE, such
220− as approximate matching, is a work in progress (with "progress"
221− loosely defined...)
222−
223− Mailing lists
224−
225− tre-general@lists.laurikari.net
226− This list is for any discussion on the TRE software, including
227− reporting bugs, feature requests, requests for help, and other
228− things.
229−
230− tre-announce@lists.laurikari.net
231− Subscribe to this list to get announcements of new releases of
232− TRE. Alternatively, you can subscribe to the freshmeat.net
233− project and get similar announcements that way, if you prefer.
234−
235−Ville Laurikari <vl@iki.fi>
src/core/regex/config.h+0−186
@@ -1,186 +0,0 @@
1−/* config.h for Windows. */
2−
3−/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
4−systems. This function is required for `alloca.c' support on those systems.
5−*/
6−/* #undef CRAY_STACKSEG_END */
7−
8−/* Define to 1 if using `alloca.c'. */
9−/* #undef C_ALLOCA */
10−
11−/* Define to 1 if translation of program messages to the user's native
12−language is requested. */
13−/* #undef ENABLE_NLS */
14−
15−/* Define to 1 if you have `alloca', as a function or macro. */
16−#define HAVE_ALLOCA 1
17−
18−/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
19−*/
20−/* #undef HAVE_ALLOCA_H */
21−
22−/* Define to 1 if you have <malloc.h> and it should be used. */
23−#define HAVE_MALLOC_H 1
24−
25−/* Define if the GNU dcgettext() function is already present or preinstalled.
26−*/
27−/* #undef HAVE_DCGETTEXT */
28−
29−/* Define to 1 if you have the <dlfcn.h> header file. */
30−#undef HAVE_DLFCN_H
31−
32−/* Define to 1 if you have the <getopt.h> header file. */
33−#define HAVE_GETOPT_H 1
34−
35−/* Define to 1 if you have the `getopt_long' function. */
36−#define HAVE_GETOPT_LONG 1
37−
38−/* Define if the GNU gettext() function is already present or preinstalled. */
39−#undef HAVE_GETTEXT
40−
41−/* Define if you have the iconv() function. */
42−#undef HAVE_ICONV
43−
44−/* Define to 1 if you have the <inttypes.h> header file. */
45−#undef HAVE_INTTYPES_H
46−
47−/* Define to 1 if you have the `isascii' function. */
48−#define HAVE_ISASCII 1
49−
50−/* Define to 1 if you have the `isblank' function. */
51−/* #undef HAVE_ISBLANK */
52−
53−/* Define to 1 if you have the `iswctype' function. */
54−#define HAVE_ISWCTYPE 1
55−
56−/* Define to 1 if you have the `iswlower' function. */
57−#define HAVE_ISWLOWER 1
58−
59−/* Define to 1 if you have the `iswupper' function. */
60−#define HAVE_ISWUPPER 1
61−
62−/* Define to 1 if you have the `mbrtowc' function. */
63−#define HAVE_MBRTOWC 1
64−
65−/* Define to 1 if the system has the type `mbstate_t'. */
66−#define HAVE_MBSTATE_T 1
67−
68−/* Define to 1 if you have the `mbtowc' function. */
69−#define HAVE_MBTOWC 1
70−
71−/* Define to 1 if you have the <memory.h> header file. */
72−#undef HAVE_MEMORY_H
73−
74−/* Define to 1 if you have the <regex.h> header file. */
75−#undef HAVE_REGEX_H
76−/* Define to 1 if the system has the type `reg_errcode_t'. */
77−#undef HAVE_REG_ERRCODE_T
78−
79−/* Define to 1 if you have the <stdint.h> header file. */
80−#define HAVE_STDINT_H 1
81−
82−/* Define to 1 if you have the <stdlib.h> header file. */
83−#define HAVE_STDLIB_H 1
84−
85−/* Define to 1 if you have the <strings.h> header file. */
86−#define HAVE_STRINGS_H 1
87−
88−/* Define to 1 if you have the <string.h> header file. */
89−#define HAVE_STRING_H 1
90−
91−/* Define to 1 if you have the <sys/stat.h> header file. */
92−#define HAVE_SYS_STAT_H 1
93−
94−/* Define to 1 if you have the <sys/types.h> header file. */
95−#define HAVE_SYS_TYPES_H 1
96−
97−/* Define to 1 if you have the `towlower' function. */
98−#undef HAVE_TOWLOWER
99−
100−/* Define to 1 if you have the `towupper' function. */
101−#define HAVE_TOWUPPER 1
102−
103−/* Define to 1 if you have the <unistd.h> header file. */
104−/* #undef HAVE_UNISTD_H */
105−
106−/* Define to 1 if you have the <wchar.h> header file. */
107−#define HAVE_WCHAR_H 1
108−
109−/* Define to 1 if the system has the type `wchar_t'. */
110−#define HAVE_WCHAR_T 1
111−
112−/* Define to 1 if you have the `wcschr' function. */
113−#define HAVE_WCSCHR 1
114−
115−/* Define to 1 if you have the `wcscpy' function. */
116−#define HAVE_WCSCPY 1
117−
118−/* Define to 1 if you have the `wcslen' function. */
119−#define HAVE_WCSLEN 1
120−
121−/* Define to 1 if you have the `wcsncpy' function. */
122−#define HAVE_WCSNCPY 1
123−
124−/* Define to 1 if you have the `wcsrtombs' function. */
125−#define HAVE_WCSRTOMBS 1
126−
127−/* Define to 1 if you have the `wcstombs' function. */
128−/* #undef HAVE_WCSTOMBS */
129−
130−/* Define to 1 if you have the `wctype' function. */
131−#define HAVE_WCTYPE 1
132−
133−/* Define to 1 if you have the <wctype.h> header file. */
134−#define HAVE_WCTYPE_H 1
135−
136−/* Define if you want to disable debug assertions. */
137−/* #undef NDEBUG */
138−
139−/* Define to 1 if you have the ANSI C header files. */
140−#define STDC_HEADERS 1
141−
142−/* Define if you want to enable approximate matching functionality. */
143−#define TRE_APPROX 1
144−
145−/* Define if you want TRE to print debug messages to stdout. */
146−/* #undef TRE_DEBUG */
147−
148−/* Define to enable multibyte character set support. */
149−/* #define TRE_MULTIBYTE 1 */
150−
151−/* Define to a field in the regex_t struct where TRE should store a pointer to
152−the internal tre_tnfa_t structure */
153−#define TRE_REGEX_T_FIELD value
154−
155−/* Define to the absolute path to the system regex.h */
156−/* #undef TRE_SYSTEM_REGEX_H_PATH */
157−
158−/* Define to include the system regex.h from TRE regex.h */
159−/* #undef TRE_USE_SYSTEM_REGEX_H */
160−
161−/* Define to enable wide character (wchar_t) support. */
162−/* #define TRE_WCHAR 1 */
163−
164−/* Define to the maximum value of wchar_t if not already defined elsewhere */
165−/* #undef WCHAR_MAX */
166−
167−/* Define if wchar_t is signed */
168−/* #undef WCHAR_T_SIGNED */
169−
170−/* Define if wchar_t is unsigned */
171−#define WCHAR_T_UNSIGNED 1
172−
173−/* Define to empty if `const' does not conform to ANSI C. */
174−/* #undef const */
175−
176−/* Define as `__inline' if that's what the C compiler calls it, or to nothing
177−if it is not supported. */
178−#define inline __inline
179−
180−/* Avoid silly warnings about "insecure" functions. */
181−#define _CRT_SECURE_NO_DEPRECATE 1
182−
183−/* #define snprintf sprintf_s */
184−#ifndef __WINDOWS_MODERN__
185−#define snprintf _snprintf
186−#endif
src/core/regex/regcomp.c+0−129
@@ -1,129 +0,0 @@
1−/*
2− tre_regcomp.c - TRE POSIX compatible regex compilation functions.
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−#ifdef HAVE_CONFIG_H
10−#include <config.h>
11−#endif /* HAVE_CONFIG_H */
12−
13−#include <string.h>
14−#include <errno.h>
15−#include <stdlib.h>
16−
17−#include "tre.h"
18−#include "tre-internal.h"
19−#include "xmalloc.h"
20−
21−int
22−tre_regncomp(regex_t *preg, const char *regex, size_t n, int cflags)
23−{
24− int ret;
25−#if TRE_WCHAR
26− tre_char_t *wregex;
27− size_t wlen;
28−
29− wregex = xmalloc(sizeof(tre_char_t) * (n + 1));
30− if (wregex == NULL)
31− return REG_ESPACE;
32−
33− /* If the current locale uses the standard single byte encoding of
34− characters, we don't do a multibyte string conversion. If we did,
35− many applications which use the default locale would break since
36− the default "C" locale uses the 7-bit ASCII character set, and
37− all characters with the eighth bit set would be considered invalid. */
38−#if TRE_MULTIBYTE
39− if (TRE_MB_CUR_MAX == 1)
40−#endif /* TRE_MULTIBYTE */
41− {
42− unsigned int i;
43− const unsigned char *str = (const unsigned char *)regex;
44− tre_char_t *wstr = wregex;
45−
46− for (i = 0; i < n; i++)
47− *(wstr++) = *(str++);
48− wlen = n;
49− }
50−#if TRE_MULTIBYTE
51− else
52− {
53− int consumed;
54− tre_char_t *wcptr = wregex;
55−#ifdef HAVE_MBSTATE_T
56− mbstate_t state;
57− memset(&state, '\0', sizeof(state));
58−#endif /* HAVE_MBSTATE_T */
59− while (n > 0)
60− {
61− consumed = tre_mbrtowc(wcptr, regex, n, &state);
62−
63− switch (consumed)
64− {
65− case 0:
66− if (*regex == '\0')
67− consumed = 1;
68− else
69− {
70− xfree(wregex);
71− return REG_BADPAT;
72− }
73− break;
74− case -1:
75− DPRINT(("mbrtowc: error %d: %s.\n", errno, strerror(errno)));
76− xfree(wregex);
77− return REG_BADPAT;
78− case -2:
79− /* The last character wasn't complete. Let's not call it a
80− fatal error. */
81− consumed = n;
82− break;
83− }
84− regex += consumed;
85− n -= consumed;
86− wcptr++;
87− }
88− wlen = wcptr - wregex;
89− }
90−#endif /* TRE_MULTIBYTE */
91−
92− wregex[wlen] = L'\0';
93− ret = tre_compile(preg, wregex, wlen, cflags);
94− xfree(wregex);
95−#else /* !TRE_WCHAR */
96− ret = tre_compile(preg, (const tre_char_t *)regex, n, cflags);
97−#endif /* !TRE_WCHAR */
98−
99− return ret;
100−}
101−
102−int
103−tre_regcomp(regex_t *preg, const char *regex, int cflags)
104−{
105− return tre_regncomp(preg, regex, regex ? strlen(regex) : 0, cflags);
106−}
107−
108−
109−#ifdef TRE_WCHAR
110−int
111−tre_regwncomp(regex_t *preg, const wchar_t *regex, size_t n, int cflags)
112−{
113− return tre_compile(preg, regex, n, cflags);
114−}
115−
116−int
117−tre_regwcomp(regex_t *preg, const wchar_t *regex, int cflags)
118−{
119− return tre_compile(preg, regex, regex ? wcslen(regex) : 0, cflags);
120−}
121−#endif /* TRE_WCHAR */
122−
123−void
124−tre_regfree(regex_t *preg)
125−{
126− tre_free(preg);
127−}
128−
129−/* EOF */
src/core/regex/regerror.c+0−83
@@ -1,83 +0,0 @@
1−/*
2− tre_regerror.c - POSIX tre_regerror() implementation for TRE.
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−#ifdef HAVE_CONFIG_H
10−#include <config.h>
11−#endif /* HAVE_CONFIG_H */
12−
13−#include <string.h>
14−#ifdef HAVE_WCHAR_H
15−#include <wchar.h>
16−#endif /* HAVE_WCHAR_H */
17−#ifdef HAVE_WCTYPE_H
18−#include <wctype.h>
19−#endif /* HAVE_WCTYPE_H */
20−
21−#include "tre-internal.h"
22−#include "tre.h"
23−
24−#ifdef HAVE_GETTEXT
25−#include <libintl.h>
26−#else
27−#define dgettext(p, s) s
28−#define gettext(s) s
29−#endif
30−
31−#define _(String) dgettext(PACKAGE, String)
32−#define gettext_noop(String) String
33−
34−/* Error message strings for error codes listed in `tre.h'. This list
35− needs to be in sync with the codes listed there, naturally. */
36−static const char *tre_error_messages[] =
37− { gettext_noop("No error"), /* REG_OK */
38− gettext_noop("No match"), /* REG_NOMATCH */
39− gettext_noop("Invalid regexp"), /* REG_BADPAT */
40− gettext_noop("Unknown collating element"), /* REG_ECOLLATE */
41− gettext_noop("Unknown character class name"), /* REG_ECTYPE */
42− gettext_noop("Trailing backslash"), /* REG_EESCAPE */
43− gettext_noop("Invalid back reference"), /* REG_ESUBREG */
44− gettext_noop("Missing ']'"), /* REG_EBRACK */
45− gettext_noop("Missing ')'"), /* REG_EPAREN */
46− gettext_noop("Missing '}'"), /* REG_EBRACE */
47− gettext_noop("Invalid contents of {}"), /* REG_BADBR */
48− gettext_noop("Invalid character range"), /* REG_ERANGE */
49− gettext_noop("Out of memory"), /* REG_ESPACE */
50− gettext_noop("Invalid use of repetition operators") /* REG_BADRPT */
51− };
52−
53−size_t
54−tre_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
55−{
56− const char *err;
57− size_t err_len;
58−
59− /*LINTED*/(void)&preg;
60− if (errcode >= 0
61− && errcode < (int)(sizeof(tre_error_messages)
62− / sizeof(*tre_error_messages)))
63− err = gettext(tre_error_messages[errcode]);
64− else
65− err = gettext("Unknown error");
66−
67− err_len = strlen(err) + 1;
68− if (errbuf_size > 0 && errbuf != NULL)
69− {
70− if (err_len > errbuf_size)
71− {
72− strncpy(errbuf, err, errbuf_size - 1);
73− errbuf[errbuf_size - 1] = '\0';
74− }
75− else
76− {
77− strcpy(errbuf, err);
78− }
79− }
80− return err_len;
81−}
82−
83−/* EOF */
src/core/regex/regex.h+0−38
@@ -1,38 +0,0 @@
1−/*
2− regex.h - TRE legacy API
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7− This header is for source level compatibility with old code using
8− the <tre/regex.h> header which defined the TRE API functions without
9− a prefix. New code should include <tre/tre.h> instead.
10−
11−*/
12−
13−#ifndef TRE_REXEX_H
14−#define TRE_REGEX_H 1
15−
16−#include "tre.h"
17−
18−#ifndef TRE_USE_SYSTEM_REGEX_H
19−#define regcomp tre_regcomp
20−#define regerror tre_regerror
21−#define regexec tre_regexec
22−#define regfree tre_regfree
23−#endif /* TRE_USE_SYSTEM_REGEX_H */
24−
25−#define regacomp tre_regacomp
26−#define regaexec tre_regaexec
27−#define regancomp tre_regancomp
28−#define reganexec tre_reganexec
29−#define regawncomp tre_regawncomp
30−#define regawnexec tre_regawnexec
31−#define regncomp tre_regncomp
32−#define regnexec tre_regnexec
33−#define regwcomp tre_regwcomp
34−#define regwexec tre_regwexec
35−#define regwncomp tre_regwncomp
36−#define regwnexec tre_regwnexec
37−
38−#endif /* TRE_REGEX_H */
src/core/regex/regexec.c+0−348
@@ -1,348 +0,0 @@
1−/*
2− tre_regexec.c - TRE POSIX compatible matching functions (and more).
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−#ifdef HAVE_CONFIG_H
10−#include <config.h>
11−#endif /* HAVE_CONFIG_H */
12−
13−#ifdef TRE_USE_ALLOCA
14−/* AIX requires this to be the first thing in the file. */
15−#ifndef __GNUC__
16−# if HAVE_ALLOCA_H
17−# include <alloca.h>
18−# else
19−# ifdef _AIX
20− #pragma alloca
21−# else
22−# ifndef alloca /* predefined by HP cc +Olibcalls */
23−char *alloca ();
24−# endif
25−# endif
26−# endif
27−#endif
28−#endif /* TRE_USE_ALLOCA */
29−
30−#include <assert.h>
31−#include <stdlib.h>
32−#include <string.h>
33−#ifdef HAVE_WCHAR_H
34−#include <wchar.h>
35−#endif /* HAVE_WCHAR_H */
36−#ifdef HAVE_WCTYPE_H
37−#include <wctype.h>
38−#endif /* HAVE_WCTYPE_H */
39−#ifndef TRE_WCHAR
40−#include <ctype.h>
41−#endif /* !TRE_WCHAR */
42−#ifdef HAVE_MALLOC_H
43−#include <malloc.h>
44−#endif /* HAVE_MALLOC_H */
45−#include <limits.h>
46−
47−#include "tre-internal.h"
48−#include "tre.h"
49−#include "xmalloc.h"
50−
51−
52−/* Fills the POSIX.2 regmatch_t array according to the TNFA tag and match
53− endpoint values. */
54−void
55−tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags,
56− const tre_tnfa_t *tnfa, int *tags, int match_eo)
57−{
58− tre_submatch_data_t *submatch_data;
59− unsigned int i, j;
60− int *parents;
61−
62− i = 0;
63− if (match_eo >= 0 && !(cflags & REG_NOSUB))
64− {
65− /* Construct submatch offsets from the tags. */
66− DPRINT(("end tag = t%d = %d\n", tnfa->end_tag, match_eo));
67− submatch_data = tnfa->submatch_data;
68− while (i < tnfa->num_submatches && i < nmatch)
69− {
70− if (submatch_data[i].so_tag == tnfa->end_tag)
71− pmatch[i].rm_so = match_eo;
72− else
73− pmatch[i].rm_so = tags[submatch_data[i].so_tag];
74−
75− if (submatch_data[i].eo_tag == tnfa->end_tag)
76− pmatch[i].rm_eo = match_eo;
77− else
78− pmatch[i].rm_eo = tags[submatch_data[i].eo_tag];
79−
80− /* If either of the endpoints were not used, this submatch
81− was not part of the match. */
82− if (pmatch[i].rm_so == -1 || pmatch[i].rm_eo == -1)
83− pmatch[i].rm_so = pmatch[i].rm_eo = -1;
84−
85− DPRINT(("pmatch[%d] = {t%d = %d, t%d = %d}\n", i,
86− submatch_data[i].so_tag, pmatch[i].rm_so,
87− submatch_data[i].eo_tag, pmatch[i].rm_eo));
88− i++;
89− }
90− /* Reset all submatches that are not within all of their parent
91− submatches. */
92− i = 0;
93− while (i < tnfa->num_submatches && i < nmatch)
94− {
95− if (pmatch[i].rm_eo == -1)
96− assert(pmatch[i].rm_so == -1);
97− assert(pmatch[i].rm_so <= pmatch[i].rm_eo);
98−
99− parents = submatch_data[i].parents;
100− if (parents != NULL)
101− for (j = 0; parents[j] >= 0; j++)
102− {
103− DPRINT(("pmatch[%d] parent %d\n", i, parents[j]));
104− if (pmatch[i].rm_so < pmatch[parents[j]].rm_so
105− || pmatch[i].rm_eo > pmatch[parents[j]].rm_eo)
106− pmatch[i].rm_so = pmatch[i].rm_eo = -1;
107− }
108− i++;
109− }
110− }
111−
112− while (i < nmatch)
113− {
114− pmatch[i].rm_so = -1;
115− pmatch[i].rm_eo = -1;
116− i++;
117− }
118−}
119−
120−
121−/*
122− Wrapper functions for POSIX compatible regexp matching.
123−*/
124−
125−int
126−tre_have_backrefs(const regex_t *preg)
127−{
128− tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD;
129− return tnfa->have_backrefs;
130−}
131−
132−int
133−tre_have_approx(const regex_t *preg)
134−{
135− tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD;
136− return tnfa->have_approx;
137−}
138−
139−static int
140−tre_match(const tre_tnfa_t *tnfa, const void *string, size_t len,
141− tre_str_type_t type, size_t nmatch, regmatch_t pmatch[],
142− int eflags)
143−{
144− reg_errcode_t status;
145− int *tags = NULL, eo;
146− if (tnfa->num_tags > 0 && nmatch > 0)
147− {
148−#ifdef TRE_USE_ALLOCA
149− tags = alloca(sizeof(*tags) * tnfa->num_tags);
150−#else /* !TRE_USE_ALLOCA */
151− tags = xmalloc(sizeof(*tags) * tnfa->num_tags);
152−#endif /* !TRE_USE_ALLOCA */
153− if (tags == NULL)
154− return REG_ESPACE;
155− }
156−
157− /* Dispatch to the appropriate matcher. */
158− if (tnfa->have_backrefs || eflags & REG_BACKTRACKING_MATCHER)
159− {
160− /* The regex has back references, use the backtracking matcher. */
161− if (type == STR_USER)
162− {
163− const tre_str_source *source = string;
164− if (source->rewind == NULL || source->compare == NULL)
165− /* The backtracking matcher requires rewind and compare
166− capabilities from the input stream. */
167− return REG_BADPAT;
168− }
169− status = tre_tnfa_run_backtrack(tnfa, string, (int)len, type,
170− tags, eflags, &eo);
171− }
172−#ifdef TRE_APPROX
173− else if (tnfa->have_approx || eflags & REG_APPROX_MATCHER)
174− {
175− /* The regex uses approximate matching, use the approximate matcher. */
176− regamatch_t match;
177− regaparams_t params;
178− tre_regaparams_default(&params);
179− params.max_err = 0;
180− params.max_cost = 0;
181− status = tre_tnfa_run_approx(tnfa, string, (int)len, type, tags,
182− &match, params, eflags, &eo);
183− }
184−#endif /* TRE_APPROX */
185− else
186− {
187− /* Exact matching, no back references, use the parallel matcher. */
188− status = tre_tnfa_run_parallel(tnfa, string, (int)len, type,
189− tags, eflags, &eo);
190− }
191−
192− if (status == REG_OK)
193− /* A match was found, so fill the submatch registers. */
194− tre_fill_pmatch(nmatch, pmatch, tnfa->cflags, tnfa, tags, eo);
195−#ifndef TRE_USE_ALLOCA
196− if (tags)
197− xfree(tags);
198−#endif /* !TRE_USE_ALLOCA */
199− return status;
200−}
201−
202−int
203−tre_regnexec(const regex_t *preg, const char *str, size_t len,
204− size_t nmatch, regmatch_t pmatch[], int eflags)
205−{
206− tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD;
207− tre_str_type_t type = (TRE_MB_CUR_MAX == 1) ? STR_BYTE : STR_MBS;
208−
209− return tre_match(tnfa, str, len, type, nmatch, pmatch, eflags);
210−}
211−
212−int
213−tre_regexec(const regex_t *preg, const char *str,
214− size_t nmatch, regmatch_t pmatch[], int eflags)
215−{
216− return tre_regnexec(preg, str, (unsigned)-1, nmatch, pmatch, eflags);
217−}
218−
219−
220−#ifdef TRE_WCHAR
221−
222−int
223−tre_regwnexec(const regex_t *preg, const wchar_t *str, size_t len,
224− size_t nmatch, regmatch_t pmatch[], int eflags)
225−{
226− tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD;
227− return tre_match(tnfa, str, len, STR_WIDE, nmatch, pmatch, eflags);
228−}
229−
230−int
231−tre_regwexec(const regex_t *preg, const wchar_t *str,
232− size_t nmatch, regmatch_t pmatch[], int eflags)
233−{
234− return tre_regwnexec(preg, str, (unsigned)-1, nmatch, pmatch, eflags);
235−}
236−
237−#endif /* TRE_WCHAR */
238−
239−int
240−tre_reguexec(const regex_t *preg, const tre_str_source *str,
241− size_t nmatch, regmatch_t pmatch[], int eflags)
242−{
243− tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD;
244− return tre_match(tnfa, str, (unsigned)-1, STR_USER, nmatch, pmatch, eflags);
245−}
246−
247−
248−#ifdef TRE_APPROX
249−
250−/*
251− Wrapper functions for approximate regexp matching.
252−*/
253−
254−static int
255−tre_match_approx(const tre_tnfa_t *tnfa, const void *string, size_t len,
256− tre_str_type_t type, regamatch_t *match, regaparams_t params,
257− int eflags)
258−{
259− reg_errcode_t status;
260− int *tags = NULL, eo;
261−
262− /* If the regexp does not use approximate matching features, the
263− maximum cost is zero, and the approximate matcher isn't forced,
264− use the exact matcher instead. */
265− if (params.max_cost == 0 && !tnfa->have_approx
266− && !(eflags & REG_APPROX_MATCHER))
267− return tre_match(tnfa, string, len, type, match->nmatch, match->pmatch,
268− eflags);
269−
270− /* Back references are not supported by the approximate matcher. */
271− if (tnfa->have_backrefs)
272− return REG_BADPAT;
273−
274− if (tnfa->num_tags > 0 && match->nmatch > 0)
275− {
276−#if TRE_USE_ALLOCA
277− tags = alloca(sizeof(*tags) * tnfa->num_tags);
278−#else /* !TRE_USE_ALLOCA */
279− tags = xmalloc(sizeof(*tags) * tnfa->num_tags);
280−#endif /* !TRE_USE_ALLOCA */
281− if (tags == NULL)
282− return REG_ESPACE;
283− }
284− status = tre_tnfa_run_approx(tnfa, string, (int)len, type, tags,
285− match, params, eflags, &eo);
286− if (status == REG_OK)
287− tre_fill_pmatch(match->nmatch, match->pmatch, tnfa->cflags, tnfa, tags, eo);
288−#ifndef TRE_USE_ALLOCA
289− if (tags)
290− xfree(tags);
291−#endif /* !TRE_USE_ALLOCA */
292− return status;
293−}
294−
295−int
296−tre_reganexec(const regex_t *preg, const char *str, size_t len,
297− regamatch_t *match, regaparams_t params, int eflags)
298−{
299− tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD;
300− tre_str_type_t type = (TRE_MB_CUR_MAX == 1) ? STR_BYTE : STR_MBS;
301−
302− return tre_match_approx(tnfa, str, len, type, match, params, eflags);
303−}
304−
305−int
306−tre_regaexec(const regex_t *preg, const char *str,
307− regamatch_t *match, regaparams_t params, int eflags)
308−{
309− return tre_reganexec(preg, str, (unsigned)-1, match, params, eflags);
310−}
311−
312−#ifdef TRE_WCHAR
313−
314−int
315−tre_regawnexec(const regex_t *preg, const wchar_t *str, size_t len,
316− regamatch_t *match, regaparams_t params, int eflags)
317−{
318− tre_tnfa_t *tnfa = (void *)preg->TRE_REGEX_T_FIELD;
319− return tre_match_approx(tnfa, str, len, STR_WIDE,
320− match, params, eflags);
321−}
322−
323−int
324−tre_regawexec(const regex_t *preg, const wchar_t *str,
325− regamatch_t *match, regaparams_t params, int eflags)
326−{
327− return tre_regawnexec(preg, str, (unsigned)-1, match, params, eflags);
328−}
329−
330−#endif /* TRE_WCHAR */
331−
332−void
333−tre_regaparams_default(regaparams_t *params)
334−{
335− memset(params, 0, sizeof(*params));
336− params->cost_ins = 1;
337− params->cost_del = 1;
338− params->cost_subst = 1;
339− params->max_cost = INT_MAX;
340− params->max_ins = INT_MAX;
341− params->max_del = INT_MAX;
342− params->max_subst = INT_MAX;
343− params->max_err = INT_MAX;
344−}
345−
346−#endif /* TRE_APPROX */
347−
348−/* EOF */
src/core/regex/tre-ast.c+0−226
@@ -1,226 +0,0 @@
1−/*
2− tre-ast.c - Abstract syntax tree (AST) routines
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−#ifdef HAVE_CONFIG_H
10−#include <config.h>
11−#endif /* HAVE_CONFIG_H */
12−#include <assert.h>
13−
14−#include "tre-ast.h"
15−#include "tre-mem.h"
16−
17−tre_ast_node_t *
18−tre_ast_new_node(tre_mem_t mem, tre_ast_type_t type, size_t size)
19−{
20− tre_ast_node_t *node;
21−
22− node = tre_mem_calloc(mem, sizeof(*node));
23− if (!node)
24− return NULL;
25− node->obj = tre_mem_calloc(mem, size);
26− if (!node->obj)
27− return NULL;
28− node->type = type;
29− node->nullable = -1;
30− node->submatch_id = -1;
31−
32− return node;
33−}
34−
35−tre_ast_node_t *
36−tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position)
37−{
38− tre_ast_node_t *node;
39− tre_literal_t *lit;
40−
41− node = tre_ast_new_node(mem, LITERAL, sizeof(tre_literal_t));
42− if (!node)
43− return NULL;
44− lit = node->obj;
45− lit->code_min = code_min;
46− lit->code_max = code_max;
47− lit->position = position;
48−
49− return node;
50−}
51−
52−tre_ast_node_t *
53−tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max,
54− int minimal)
55−{
56− tre_ast_node_t *node;
57− tre_iteration_t *iter;
58−
59− node = tre_ast_new_node(mem, ITERATION, sizeof(tre_iteration_t));
60− if (!node)
61− return NULL;
62− iter = node->obj;
63− iter->arg = arg;
64− iter->min = min;
65− iter->max = max;
66− iter->minimal = minimal;
67− node->num_submatches = arg->num_submatches;
68−
69− return node;
70−}
71−
72−tre_ast_node_t *
73−tre_ast_new_union(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right)
74−{
75− tre_ast_node_t *node;
76−
77− node = tre_ast_new_node(mem, UNION, sizeof(tre_union_t));
78− if (node == NULL)
79− return NULL;
80− ((tre_union_t *)node->obj)->left = left;
81− ((tre_union_t *)node->obj)->right = right;
82− node->num_submatches = left->num_submatches + right->num_submatches;
83−
84− return node;
85−}
86−
87−tre_ast_node_t *
88−tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left,
89− tre_ast_node_t *right)
90−{
91− tre_ast_node_t *node;
92−
93− node = tre_ast_new_node(mem, CATENATION, sizeof(tre_catenation_t));
94− if (node == NULL)
95− return NULL;
96− ((tre_catenation_t *)node->obj)->left = left;
97− ((tre_catenation_t *)node->obj)->right = right;
98− node->num_submatches = left->num_submatches + right->num_submatches;
99−
100− return node;
101−}
102−
103−#ifdef TRE_DEBUG
104−
105−static void
106−tre_findent(FILE *stream, int i)
107−{
108− while (i-- > 0)
109− fputc(' ', stream);
110−}
111−
112−void
113−tre_print_params(int *params)
114−{
115− int i;
116− if (params)
117− {
118− DPRINT(("params ["));
119− for (i = 0; i < TRE_PARAM_LAST; i++)
120− {
121− if (params[i] == TRE_PARAM_UNSET)
122− DPRINT(("unset"));
123− else if (params[i] == TRE_PARAM_DEFAULT)
124− DPRINT(("default"));
125− else
126− DPRINT(("%d", params[i]));
127− if (i < TRE_PARAM_LAST - 1)
128− DPRINT((", "));
129− }
130− DPRINT(("]"));
131− }
132−}
133−
134−static void
135−tre_do_print(FILE *stream, tre_ast_node_t *ast, int indent)
136−{
137− int code_min, code_max, pos;
138− int num_tags = ast->num_tags;
139− tre_literal_t *lit;
140− tre_iteration_t *iter;
141−
142− tre_findent(stream, indent);
143− switch (ast->type)
144− {
145− case LITERAL:
146− lit = ast->obj;
147− code_min = lit->code_min;
148− code_max = lit->code_max;
149− pos = lit->position;
150− if (IS_EMPTY(lit))
151− {
152− fprintf(stream, "literal empty\n");
153− }
154− else if (IS_ASSERTION(lit))
155− {
156− int i;
157− char *assertions[] = { "bol", "eol", "ctype", "!ctype",
158− "bow", "eow", "wb", "!wb" };
159− if (code_max >= ASSERT_LAST << 1)
160− assert(0);
161− fprintf(stream, "assertions: ");
162− for (i = 0; (1 << i) <= ASSERT_LAST; i++)
163− if (code_max & (1 << i))
164− fprintf(stream, "%s ", assertions[i]);
165− fprintf(stream, "\n");
166− }
167− else if (IS_TAG(lit))
168− {
169− fprintf(stream, "tag %d\n", code_max);
170− }
171− else if (IS_BACKREF(lit))
172− {
173− fprintf(stream, "backref %d, pos %d\n", code_max, pos);
174− }
175− else if (IS_PARAMETER(lit))
176− {
177− tre_print_params(lit->u.params);
178− fprintf(stream, "\n");
179− }
180− else
181− {
182− fprintf(stream, "literal (%c, %c) (%d, %d), pos %d, sub %d, "
183− "%d tags\n", code_min, code_max, code_min, code_max, pos,
184− ast->submatch_id, num_tags);
185− }
186− break;
187− case ITERATION:
188− iter = ast->obj;
189− fprintf(stream, "iteration {%d, %d}, sub %d, %d tags, %s\n",
190− iter->min, iter->max, ast->submatch_id, num_tags,
191− iter->minimal ? "minimal" : "greedy");
192− tre_do_print(stream, iter->arg, indent + 2);
193− break;
194− case UNION:
195− fprintf(stream, "union, sub %d, %d tags\n", ast->submatch_id, num_tags);
196− tre_do_print(stream, ((tre_union_t *)ast->obj)->left, indent + 2);
197− tre_do_print(stream, ((tre_union_t *)ast->obj)->right, indent + 2);
198− break;
199− case CATENATION:
200− fprintf(stream, "catenation, sub %d, %d tags\n", ast->submatch_id,
201− num_tags);
202− tre_do_print(stream, ((tre_catenation_t *)ast->obj)->left, indent + 2);
203− tre_do_print(stream, ((tre_catenation_t *)ast->obj)->right, indent + 2);
204− break;
205− default:
206− assert(0);
207− break;
208− }
209−}
210−
211−static void
212−tre_ast_fprint(FILE *stream, tre_ast_node_t *ast)
213−{
214− tre_do_print(stream, ast, 0);
215−}
216−
217−void
218−tre_ast_print(tre_ast_node_t *tree)
219−{
220− printf("AST:\n");
221− tre_ast_fprint(stdout, tree);
222−}
223−
224−#endif /* TRE_DEBUG */
225−
226−/* EOF */
src/core/regex/tre-ast.h+0−128
@@ -1,128 +0,0 @@
1−/*
2− tre-ast.h - Abstract syntax tree (AST) definitions
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−
10−#ifndef TRE_AST_H
11−#define TRE_AST_H 1
12−
13−#include "tre-mem.h"
14−#include "tre-internal.h"
15−#include "tre-compile.h"
16−
17−/* The different AST node types. */
18−typedef enum {
19− LITERAL,
20− CATENATION,
21− ITERATION,
22− UNION
23−} tre_ast_type_t;
24−
25−/* Special subtypes of TRE_LITERAL. */
26−#define EMPTY -1 /* Empty leaf (denotes empty string). */
27−#define ASSERTION -2 /* Assertion leaf. */
28−#define TAG -3 /* Tag leaf. */
29−#define BACKREF -4 /* Back reference leaf. */
30−#define PARAMETER -5 /* Parameter. */
31−
32−#define IS_SPECIAL(x) ((x)->code_min < 0)
33−#define IS_EMPTY(x) ((x)->code_min == EMPTY)
34−#define IS_ASSERTION(x) ((x)->code_min == ASSERTION)
35−#define IS_TAG(x) ((x)->code_min == TAG)
36−#define IS_BACKREF(x) ((x)->code_min == BACKREF)
37−#define IS_PARAMETER(x) ((x)->code_min == PARAMETER)
38−
39−
40−/* A generic AST node. All AST nodes consist of this node on the top
41− level with `obj' pointing to the actual content. */
42−typedef struct {
43− tre_ast_type_t type; /* Type of the node. */
44− void *obj; /* Pointer to actual node. */
45− int nullable;
46− int submatch_id;
47− int num_submatches;
48− int num_tags;
49− tre_pos_and_tags_t *firstpos;
50− tre_pos_and_tags_t *lastpos;
51−} tre_ast_node_t;
52−
53−
54−/* A "literal" node. These are created for assertions, back references,
55− tags, matching parameter settings, and all expressions that match one
56− character. */
57−typedef struct {
58− long code_min;
59− long code_max;
60− int position;
61− union {
62− tre_ctype_t class;
63− int *params;
64− } u;
65− tre_ctype_t *neg_classes;
66−} tre_literal_t;
67−
68−/* A "catenation" node. These are created when two regexps are concatenated.
69− If there are more than one subexpressions in sequence, the `left' part
70− holds all but the last, and `right' part holds the last subexpression
71− (catenation is left associative). */
72−typedef struct {
73− tre_ast_node_t *left;
74− tre_ast_node_t *right;
75−} tre_catenation_t;
76−
77−/* An "iteration" node. These are created for the "*", "+", "?", and "{m,n}"
78− operators. */
79−typedef struct {
80− /* Subexpression to match. */
81− tre_ast_node_t *arg;
82− /* Minimum number of consecutive matches. */
83− int min;
84− /* Maximum number of consecutive matches. */
85− int max;
86− /* If 0, match as many characters as possible, if 1 match as few as
87− possible. Note that this does not always mean the same thing as
88− matching as many/few repetitions as possible. */
89− unsigned int minimal:1;
90− /* Approximate matching parameters (or NULL). */
91− int *params;
92−} tre_iteration_t;
93−
94−/* An "union" node. These are created for the "|" operator. */
95−typedef struct {
96− tre_ast_node_t *left;
97− tre_ast_node_t *right;
98−} tre_union_t;
99−
100−tre_ast_node_t *
101−tre_ast_new_node(tre_mem_t mem, tre_ast_type_t type, size_t size);
102−
103−tre_ast_node_t *
104−tre_ast_new_literal(tre_mem_t mem, int code_min, int code_max, int position);
105−
106−tre_ast_node_t *
107−tre_ast_new_iter(tre_mem_t mem, tre_ast_node_t *arg, int min, int max,
108− int minimal);
109−
110−tre_ast_node_t *
111−tre_ast_new_union(tre_mem_t mem, tre_ast_node_t *left, tre_ast_node_t *right);
112−
113−tre_ast_node_t *
114−tre_ast_new_catenation(tre_mem_t mem, tre_ast_node_t *left,
115− tre_ast_node_t *right);
116−
117−#ifdef TRE_DEBUG
118−void
119−tre_ast_print(tre_ast_node_t *tree);
120−
121−/* XXX - rethink AST printing API */
122−void
123−tre_print_params(int *params);
124−#endif /* TRE_DEBUG */
125−
126−#endif /* TRE_AST_H */
127−
128−/* EOF */
src/core/regex/tre-compile.c+0−2296
@@ -1,2296 +0,0 @@
1−/*
2− tre-compile.c - TRE regex compiler
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−/*
10− TODO:
11− - Fix tre_ast_to_tnfa() to recurse using a stack instead of recursive
12− function calls.
13−*/
14−
15−
16−#ifdef HAVE_CONFIG_H
17−#include <config.h>
18−#endif /* HAVE_CONFIG_H */
19−#include <stdio.h>
20−#include <assert.h>
21−#include <string.h>
22−
23−#include "tre-internal.h"
24−#include "tre-mem.h"
25−#include "tre-stack.h"
26−#include "tre-ast.h"
27−#include "tre-parse.h"
28−#include "tre-compile.h"
29−#include "tre.h"
30−#include "xmalloc.h"
31−
32−/*
33− Algorithms to setup tags so that submatch addressing can be done.
34−*/
35−
36−
37−/* Inserts a catenation node to the root of the tree given in `node'.
38− As the left child a new tag with number `tag_id' to `node' is added,
39− and the right child is the old root. */
40−static reg_errcode_t
41−tre_add_tag_left(tre_mem_t mem, tre_ast_node_t *node, int tag_id)
42−{
43− tre_catenation_t *c;
44−
45− DPRINT(("add_tag_left: tag %d\n", tag_id));
46−
47− c = tre_mem_alloc(mem, sizeof(*c));
48− if (c == NULL)
49− return REG_ESPACE;
50− c->left = tre_ast_new_literal(mem, TAG, tag_id, -1);
51− if (c->left == NULL)
52− return REG_ESPACE;
53− c->right = tre_mem_alloc(mem, sizeof(tre_ast_node_t));
54− if (c->right == NULL)
55− return REG_ESPACE;
56−
57− c->right->obj = node->obj;
58− c->right->type = node->type;
59− c->right->nullable = -1;
60− c->right->submatch_id = -1;
61− c->right->firstpos = NULL;
62− c->right->lastpos = NULL;
63− c->right->num_tags = 0;
64− node->obj = c;
65− node->type = CATENATION;
66− return REG_OK;
67−}
68−
69−/* Inserts a catenation node to the root of the tree given in `node'.
70− As the right child a new tag with number `tag_id' to `node' is added,
71− and the left child is the old root. */
72−static reg_errcode_t
73−tre_add_tag_right(tre_mem_t mem, tre_ast_node_t *node, int tag_id)
74−{
75− tre_catenation_t *c;
76−
77− DPRINT(("tre_add_tag_right: tag %d\n", tag_id));
78−
79− c = tre_mem_alloc(mem, sizeof(*c));
80− if (c == NULL)
81− return REG_ESPACE;
82− c->right = tre_ast_new_literal(mem, TAG, tag_id, -1);
83− if (c->right == NULL)
84− return REG_ESPACE;
85− c->left = tre_mem_alloc(mem, sizeof(tre_ast_node_t));
86− if (c->left == NULL)
87− return REG_ESPACE;
88−
89− c->left->obj = node->obj;
90− c->left->type = node->type;
91− c->left->nullable = -1;
92− c->left->submatch_id = -1;
93− c->left->firstpos = NULL;
94− c->left->lastpos = NULL;
95− c->left->num_tags = 0;
96− node->obj = c;
97− node->type = CATENATION;
98− return REG_OK;
99−}
100−
101−typedef enum {
102− ADDTAGS_RECURSE,
103− ADDTAGS_AFTER_ITERATION,
104− ADDTAGS_AFTER_UNION_LEFT,
105− ADDTAGS_AFTER_UNION_RIGHT,
106− ADDTAGS_AFTER_CAT_LEFT,
107− ADDTAGS_AFTER_CAT_RIGHT,
108− ADDTAGS_SET_SUBMATCH_END
109−} tre_addtags_symbol_t;
110−
111−
112−typedef struct {
113− int tag;
114− int next_tag;
115−} tre_tag_states_t;
116−
117−
118−/* Go through `regset' and set submatch data for submatches that are
119− using this tag. */
120−static void
121−tre_purge_regset(int *regset, tre_tnfa_t *tnfa, int tag)
122−{
123− int i;
124−
125− for (i = 0; regset[i] >= 0; i++)
126− {
127− int id = regset[i] / 2;
128− int start = !(regset[i] % 2);
129− DPRINT((" Using tag %d for %s offset of "
130− "submatch %d\n", tag,
131− start ? "start" : "end", id));
132− if (start)
133− tnfa->submatch_data[id].so_tag = tag;
134− else
135− tnfa->submatch_data[id].eo_tag = tag;
136− }
137− regset[0] = -1;
138−}
139−
140−
141−/* Adds tags to appropriate locations in the parse tree in `tree', so that
142− subexpressions marked for submatch addressing can be traced. */
143−static reg_errcode_t
144−tre_add_tags(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree,
145− tre_tnfa_t *tnfa)
146−{
147− reg_errcode_t status = REG_OK;
148− tre_addtags_symbol_t symbol;
149− tre_ast_node_t *node = tree; /* Tree node we are currently looking at. */
150− int bottom = tre_stack_num_objects(stack);
151− /* True for first pass (counting number of needed tags) */
152− int first_pass = (mem == NULL || tnfa == NULL);
153− int *regset, *orig_regset;
154− int num_tags = 0; /* Total number of tags. */
155− int num_minimals = 0; /* Number of special minimal tags. */
156− int tag = 0; /* The tag that is to be added next. */
157− int next_tag = 1; /* Next tag to use after this one. */
158− int *parents; /* Stack of submatches the current submatch is
159− contained in. */
160− int minimal_tag = -1; /* Tag that marks the beginning of a minimal match. */
161− tre_tag_states_t *saved_states;
162−
163− tre_tag_direction_t direction = TRE_TAG_MINIMIZE;
164− if (!first_pass)
165− {
166− tnfa->end_tag = 0;
167− tnfa->minimal_tags[0] = -1;
168− }
169−
170− regset = xmalloc(sizeof(*regset) * ((tnfa->num_submatches + 1) * 2));
171− if (regset == NULL)
172− return REG_ESPACE;
173− regset[0] = -1;
174− orig_regset = regset;
175−
176− parents = xmalloc(sizeof(*parents) * (tnfa->num_submatches + 1));
177− if (parents == NULL)
178− {
179− xfree(regset);
180− return REG_ESPACE;
181− }
182− parents[0] = -1;
183−
184− saved_states = xmalloc(sizeof(*saved_states) * (tnfa->num_submatches + 1));
185− if (saved_states == NULL)
186− {
187− xfree(regset);
188− xfree(parents);
189− return REG_ESPACE;
190− }
191− else
192− {
193− unsigned int i;
194− for (i = 0; i <= tnfa->num_submatches; i++)
195− saved_states[i].tag = -1;
196− }
197−
198− STACK_PUSH(stack, voidptr, node);
199− STACK_PUSH(stack, int, ADDTAGS_RECURSE);
200−
201− while (tre_stack_num_objects(stack) > bottom)
202− {
203− if (status != REG_OK)
204− break;
205−
206− symbol = (tre_addtags_symbol_t)tre_stack_pop_int(stack);
207− switch (symbol)
208− {
209−
210− case ADDTAGS_SET_SUBMATCH_END:
211− {
212− int id = tre_stack_pop_int(stack);
213− int i;
214−
215− /* Add end of this submatch to regset. */
216− for (i = 0; regset[i] >= 0; i++);
217− regset[i] = id * 2 + 1;
218− regset[i + 1] = -1;
219−
220− /* Pop this submatch from the parents stack. */
221− for (i = 0; parents[i] >= 0; i++);
222− parents[i - 1] = -1;
223− break;
224− }
225−
226− case ADDTAGS_RECURSE:
227− node = tre_stack_pop_voidptr(stack);
228−
229− if (node->submatch_id >= 0)
230− {
231− int id = node->submatch_id;
232− int i;
233−
234−
235− /* Add start of this submatch to regset. */
236− for (i = 0; regset[i] >= 0; i++);
237− regset[i] = id * 2;
238− regset[i + 1] = -1;
239−
240− if (!first_pass)
241− {
242− for (i = 0; parents[i] >= 0; i++);
243− tnfa->submatch_data[id].parents = NULL;
244− if (i > 0)
245− {
246− int *p = xmalloc(sizeof(*p) * (i + 1));
247− if (p == NULL)
248− {
249− status = REG_ESPACE;
250− break;
251− }
252− assert(tnfa->submatch_data[id].parents == NULL);
253− tnfa->submatch_data[id].parents = p;
254− for (i = 0; parents[i] >= 0; i++)
255− p[i] = parents[i];
256− p[i] = -1;
257− }
258− }
259−
260− /* Add end of this submatch to regset after processing this
261− node. */
262− STACK_PUSHX(stack, int, node->submatch_id);
263− STACK_PUSHX(stack, int, ADDTAGS_SET_SUBMATCH_END);
264− }
265−
266− switch (node->type)
267− {
268− case LITERAL:
269− {
270− tre_literal_t *lit = node->obj;
271−
272− if (!IS_SPECIAL(lit) || IS_BACKREF(lit))
273− {
274− int i;
275− DPRINT(("Literal %d-%d\n",
276− (int)lit->code_min, (int)lit->code_max));
277− if (regset[0] >= 0)
278− {
279− /* Regset is not empty, so add a tag before the
280− literal or backref. */
281− if (!first_pass)
282− {
283− status = tre_add_tag_left(mem, node, tag);
284− tnfa->tag_directions[tag] = direction;
285− if (minimal_tag >= 0)
286− {
287− DPRINT(("Minimal %d, %d\n", minimal_tag, tag));
288− for (i = 0; tnfa->minimal_tags[i] >= 0; i++);
289− tnfa->minimal_tags[i] = tag;
290− tnfa->minimal_tags[i + 1] = minimal_tag;
291− tnfa->minimal_tags[i + 2] = -1;
292− minimal_tag = -1;
293− num_minimals++;
294− }
295− tre_purge_regset(regset, tnfa, tag);
296− }
297− else
298− {
299− DPRINT((" num_tags = 1\n"));
300− node->num_tags = 1;
301− }
302−
303− DPRINT((" num_tags++\n"));
304− regset[0] = -1;
305− tag = next_tag;
306− num_tags++;
307− next_tag++;
308− }
309− }
310− else
311− {
312− assert(!IS_TAG(lit));
313− }
314− break;
315− }
316− case CATENATION:
317− {
318− tre_catenation_t *cat = node->obj;
319− tre_ast_node_t *left = cat->left;
320− tre_ast_node_t *right = cat->right;
321− int reserved_tag = -1;
322− DPRINT(("Catenation, next_tag = %d\n", next_tag));
323−
324−
325− /* After processing right child. */
326− STACK_PUSHX(stack, voidptr, node);
327− STACK_PUSHX(stack, int, ADDTAGS_AFTER_CAT_RIGHT);
328−
329− /* Process right child. */
330− STACK_PUSHX(stack, voidptr, right);
331− STACK_PUSHX(stack, int, ADDTAGS_RECURSE);
332−
333− /* After processing left child. */
334− STACK_PUSHX(stack, int, next_tag + left->num_tags);
335− DPRINT((" Pushing %d for after left\n",
336− next_tag + left->num_tags));
337− if (left->num_tags > 0 && right->num_tags > 0)
338− {
339− /* Reserve the next tag to the right child. */
340− DPRINT((" Reserving next_tag %d to right child\n",
341− next_tag));
342− reserved_tag = next_tag;
343− next_tag++;
344− }
345− STACK_PUSHX(stack, int, reserved_tag);
346− STACK_PUSHX(stack, int, ADDTAGS_AFTER_CAT_LEFT);
347−
348− /* Process left child. */
349− STACK_PUSHX(stack, voidptr, left);
350− STACK_PUSHX(stack, int, ADDTAGS_RECURSE);
351−
352− }
353− break;
354− case ITERATION:
355− {
356− tre_iteration_t *iter = node->obj;
357− DPRINT(("Iteration\n"));
358−
359− if (first_pass)
360− {
361− STACK_PUSHX(stack, int, regset[0] >= 0 || iter->minimal);
362− }
363− else
364− {
365− STACK_PUSHX(stack, int, tag);
366− STACK_PUSHX(stack, int, iter->minimal);
367− }
368− STACK_PUSHX(stack, voidptr, node);
369− STACK_PUSHX(stack, int, ADDTAGS_AFTER_ITERATION);
370−
371− STACK_PUSHX(stack, voidptr, iter->arg);
372− STACK_PUSHX(stack, int, ADDTAGS_RECURSE);
373−
374− /* Regset is not empty, so add a tag here. */
375− if (regset[0] >= 0 || iter->minimal)
376− {
377− if (!first_pass)
378− {
379− int i;
380− status = tre_add_tag_left(mem, node, tag);
381− if (iter->minimal)
382− tnfa->tag_directions[tag] = TRE_TAG_MAXIMIZE;
383− else
384− tnfa->tag_directions[tag] = direction;
385− if (minimal_tag >= 0)
386− {
387− DPRINT(("Minimal %d, %d\n", minimal_tag, tag));
388− for (i = 0; tnfa->minimal_tags[i] >= 0; i++);
389− tnfa->minimal_tags[i] = tag;
390− tnfa->minimal_tags[i + 1] = minimal_tag;
391− tnfa->minimal_tags[i + 2] = -1;
392− minimal_tag = -1;
393− num_minimals++;
394− }
395− tre_purge_regset(regset, tnfa, tag);
396− }
397−
398− DPRINT((" num_tags++\n"));
399− regset[0] = -1;
400− tag = next_tag;
401− num_tags++;
402− next_tag++;
403− }
404− direction = TRE_TAG_MINIMIZE;
405− }
406− break;
407− case UNION:
408− {
409− tre_union_t *uni = node->obj;
410− tre_ast_node_t *left = uni->left;
411− tre_ast_node_t *right = uni->right;
412− int left_tag;
413− int right_tag;
414−
415− if (regset[0] >= 0)
416− {
417− left_tag = next_tag;
418− right_tag = next_tag + 1;
419− }
420− else
421− {
422− left_tag = tag;
423− right_tag = next_tag;
424− }
425−
426− DPRINT(("Union\n"));
427−
428− /* After processing right child. */
429− STACK_PUSHX(stack, int, right_tag);
430− STACK_PUSHX(stack, int, left_tag);
431− STACK_PUSHX(stack, voidptr, regset);
432− STACK_PUSHX(stack, int, regset[0] >= 0);
433− STACK_PUSHX(stack, voidptr, node);
434− STACK_PUSHX(stack, voidptr, right);
435− STACK_PUSHX(stack, voidptr, left);
436− STACK_PUSHX(stack, int, ADDTAGS_AFTER_UNION_RIGHT);
437−
438− /* Process right child. */
439− STACK_PUSHX(stack, voidptr, right);
440− STACK_PUSHX(stack, int, ADDTAGS_RECURSE);
441−
442− /* After processing left child. */
443− STACK_PUSHX(stack, int, ADDTAGS_AFTER_UNION_LEFT);
444−
445− /* Process left child. */
446− STACK_PUSHX(stack, voidptr, left);
447− STACK_PUSHX(stack, int, ADDTAGS_RECURSE);
448−
449− /* Regset is not empty, so add a tag here. */
450− if (regset[0] >= 0)
451− {
452− if (!first_pass)
453− {
454− int i;
455− status = tre_add_tag_left(mem, node, tag);
456− tnfa->tag_directions[tag] = direction;
457− if (minimal_tag >= 0)
458− {
459− DPRINT(("Minimal %d, %d\n", minimal_tag, tag));
460− for (i = 0; tnfa->minimal_tags[i] >= 0; i++);
461− tnfa->minimal_tags[i] = tag;
462− tnfa->minimal_tags[i + 1] = minimal_tag;
463− tnfa->minimal_tags[i + 2] = -1;
464− minimal_tag = -1;
465− num_minimals++;
466− }
467− tre_purge_regset(regset, tnfa, tag);
468− }
469−
470− DPRINT((" num_tags++\n"));
471− regset[0] = -1;
472− tag = next_tag;
473− num_tags++;
474− next_tag++;
475− }
476−
477− if (node->num_submatches > 0)
478− {
479− /* The next two tags are reserved for markers. */
480− next_tag++;
481− tag = next_tag;
482− next_tag++;
483− }
484−
485− break;
486− }
487− }
488−
489− if (node->submatch_id >= 0)
490− {
491− int i;
492− /* Push this submatch on the parents stack. */
493− for (i = 0; parents[i] >= 0; i++);
494− parents[i] = node->submatch_id;
495− parents[i + 1] = -1;
496− }
497−
498− break; /* end case: ADDTAGS_RECURSE */
499−
500− case ADDTAGS_AFTER_ITERATION:
501− {
502− int minimal = 0;
503− int enter_tag;
504− node = tre_stack_pop_voidptr(stack);
505− if (first_pass)
506− {
507− node->num_tags = ((tre_iteration_t *)node->obj)->arg->num_tags
508− + tre_stack_pop_int(stack);
509− minimal_tag = -1;
510− }
511− else
512− {
513− minimal = tre_stack_pop_int(stack);
514− enter_tag = tre_stack_pop_int(stack);
515− if (minimal)
516− minimal_tag = enter_tag;
517− }
518−
519− DPRINT(("After iteration\n"));
520− if (!first_pass)
521− {
522− DPRINT((" Setting direction to %s\n",
523− minimal ? "minimize" : "maximize"));
524− if (minimal)
525− direction = TRE_TAG_MINIMIZE;
526− else
527− direction = TRE_TAG_MAXIMIZE;
528− }
529− break;
530− }
531−
532− case ADDTAGS_AFTER_CAT_LEFT:
533− {
534− int new_tag = tre_stack_pop_int(stack);
535− next_tag = tre_stack_pop_int(stack);
536− DPRINT(("After cat left, tag = %d, next_tag = %d\n",
537− tag, next_tag));
538− if (new_tag >= 0)
539− {
540− DPRINT((" Setting tag to %d\n", new_tag));
541− tag = new_tag;
542− }
543− break;
544− }
545−
546− case ADDTAGS_AFTER_CAT_RIGHT:
547− DPRINT(("After cat right\n"));
548− node = tre_stack_pop_voidptr(stack);
549− if (first_pass)
550− node->num_tags = ((tre_catenation_t *)node->obj)->left->num_tags
551− + ((tre_catenation_t *)node->obj)->right->num_tags;
552− break;
553−
554− case ADDTAGS_AFTER_UNION_LEFT:
555− DPRINT(("After union left\n"));
556− /* Lift the bottom of the `regset' array so that when processing
557− the right operand the items currently in the array are
558− invisible. The original bottom was saved at ADDTAGS_UNION and
559− will be restored at ADDTAGS_AFTER_UNION_RIGHT below. */
560− while (*regset >= 0)
561− regset++;
562− break;
563−
564− case ADDTAGS_AFTER_UNION_RIGHT:
565− {
566− int added_tags, tag_left, tag_right;
567− tre_ast_node_t *left = tre_stack_pop_voidptr(stack);
568− tre_ast_node_t *right = tre_stack_pop_voidptr(stack);
569− DPRINT(("After union right\n"));
570− node = tre_stack_pop_voidptr(stack);
571− added_tags = tre_stack_pop_int(stack);
572− if (first_pass)
573− {
574− node->num_tags = ((tre_union_t *)node->obj)->left->num_tags
575− + ((tre_union_t *)node->obj)->right->num_tags + added_tags
576− + ((node->num_submatches > 0) ? 2 : 0);
577− }
578− regset = tre_stack_pop_voidptr(stack);
579− tag_left = tre_stack_pop_int(stack);
580− tag_right = tre_stack_pop_int(stack);
581−
582− /* Add tags after both children, the left child gets a smaller
583− tag than the right child. This guarantees that we prefer
584− the left child over the right child. */
585− /* XXX - This is not always necessary (if the children have
586− tags which must be seen for every match of that child). */
587− /* XXX - Check if this is the only place where tre_add_tag_right
588− is used. If so, use tre_add_tag_left (putting the tag before
589− the child as opposed after the child) and throw away
590− tre_add_tag_right. */
591− if (node->num_submatches > 0)
592− {
593− if (!first_pass)
594− {
595− status = tre_add_tag_right(mem, left, tag_left);
596− tnfa->tag_directions[tag_left] = TRE_TAG_MAXIMIZE;
597− status = tre_add_tag_right(mem, right, tag_right);
598− tnfa->tag_directions[tag_right] = TRE_TAG_MAXIMIZE;
599− }
600− DPRINT((" num_tags += 2\n"));
601− num_tags += 2;
602− }
603− direction = TRE_TAG_MAXIMIZE;
604− break;
605− }
606−
607− default:
608− assert(0);
609− break;
610−
611− } /* end switch(symbol) */
612− } /* end while(tre_stack_num_objects(stack) > bottom) */
613−
614− if (!first_pass)
615− tre_purge_regset(regset, tnfa, tag);
616−
617− if (!first_pass && minimal_tag >= 0)
618− {
619− int i;
620− DPRINT(("Minimal %d, %d\n", minimal_tag, tag));
621− for (i = 0; tnfa->minimal_tags[i] >= 0; i++);
622− tnfa->minimal_tags[i] = tag;
623− tnfa->minimal_tags[i + 1] = minimal_tag;
624− tnfa->minimal_tags[i + 2] = -1;
625− minimal_tag = -1;
626− num_minimals++;
627− }
628−
629− DPRINT(("tre_add_tags: %s complete. Number of tags %d.\n",
630− first_pass? "First pass" : "Second pass", num_tags));
631−
632− assert(tree->num_tags == num_tags);
633− tnfa->end_tag = num_tags;
634− tnfa->num_tags = num_tags;
635− tnfa->num_minimals = num_minimals;
636− xfree(orig_regset);
637− xfree(parents);
638− xfree(saved_states);
639− return status;
640−}
641−
642−
643−
644−/*
645− AST to TNFA compilation routines.
646−*/
647−
648−typedef enum {
649− COPY_RECURSE,
650− COPY_SET_RESULT_PTR
651−} tre_copyast_symbol_t;
652−
653−/* Flags for tre_copy_ast(). */
654−#define COPY_REMOVE_TAGS 1
655−#define COPY_MAXIMIZE_FIRST_TAG 2
656−
657−static reg_errcode_t
658−tre_copy_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
659− int flags, int *pos_add, tre_tag_direction_t *tag_directions,
660− tre_ast_node_t **copy, int *max_pos)
661−{
662− reg_errcode_t status = REG_OK;
663− int bottom = tre_stack_num_objects(stack);
664− int num_copied = 0;
665− int first_tag = 1;
666− tre_ast_node_t **result = copy;
667− tre_copyast_symbol_t symbol;
668−
669− STACK_PUSH(stack, voidptr, ast);
670− STACK_PUSH(stack, int, COPY_RECURSE);
671−
672− while (status == REG_OK && tre_stack_num_objects(stack) > bottom)
673− {
674− tre_ast_node_t *node;
675− if (status != REG_OK)
676− break;
677−
678− symbol = (tre_copyast_symbol_t)tre_stack_pop_int(stack);
679− switch (symbol)
680− {
681− case COPY_SET_RESULT_PTR:
682− result = tre_stack_pop_voidptr(stack);
683− break;
684− case COPY_RECURSE:
685− node = tre_stack_pop_voidptr(stack);
686− switch (node->type)
687− {
688− case LITERAL:
689− {
690− tre_literal_t *lit = node->obj;
691− int pos = lit->position;
692− int min = lit->code_min;
693− int max = lit->code_max;
694− if (!IS_SPECIAL(lit) || IS_BACKREF(lit))
695− {
696− /* XXX - e.g. [ab] has only one position but two
697− nodes, so we are creating holes in the state space
698− here. Not fatal, just wastes memory. */
699− pos += *pos_add;
700− num_copied++;
701− }
702− else if (IS_TAG(lit) && (flags & COPY_REMOVE_TAGS))
703− {
704− /* Change this tag to empty. */
705− min = EMPTY;
706− max = pos = -1;
707− }
708− else if (IS_TAG(lit) && (flags & COPY_MAXIMIZE_FIRST_TAG)
709− && first_tag)
710− {
711− /* Maximize the first tag. */
712− tag_directions[max] = TRE_TAG_MAXIMIZE;
713− first_tag = 0;
714− }
715− *result = tre_ast_new_literal(mem, min, max, pos);
716− if (*result == NULL)
717− status = REG_ESPACE;
718−
719− if (pos > *max_pos)
720− *max_pos = pos;
721− break;
722− }
723− case UNION:
724− {
725− tre_union_t *uni = node->obj;
726− tre_union_t *tmp;
727− *result = tre_ast_new_union(mem, uni->left, uni->right);
728− if (*result == NULL)
729− {
730− status = REG_ESPACE;
731− break;
732− }
733− tmp = (*result)->obj;
734− result = &tmp->left;
735− STACK_PUSHX(stack, voidptr, uni->right);
736− STACK_PUSHX(stack, int, COPY_RECURSE);
737− STACK_PUSHX(stack, voidptr, &tmp->right);
738− STACK_PUSHX(stack, int, COPY_SET_RESULT_PTR);
739− STACK_PUSHX(stack, voidptr, uni->left);
740− STACK_PUSHX(stack, int, COPY_RECURSE);
741− break;
742− }
743− case CATENATION:
744− {
745− tre_catenation_t *cat = node->obj;
746− tre_catenation_t *tmp;
747− *result = tre_ast_new_catenation(mem, cat->left, cat->right);
748− if (*result == NULL)
749− {
750− status = REG_ESPACE;
751− break;
752− }
753− tmp = (*result)->obj;
754− tmp->left = NULL;
755− tmp->right = NULL;
756− result = &tmp->left;
757−
758− STACK_PUSHX(stack, voidptr, cat->right);
759− STACK_PUSHX(stack, int, COPY_RECURSE);
760− STACK_PUSHX(stack, voidptr, &tmp->right);
761− STACK_PUSHX(stack, int, COPY_SET_RESULT_PTR);
762− STACK_PUSHX(stack, voidptr, cat->left);
763− STACK_PUSHX(stack, int, COPY_RECURSE);
764− break;
765− }
766− case ITERATION:
767− {
768− tre_iteration_t *iter = node->obj;
769− STACK_PUSHX(stack, voidptr, iter->arg);
770− STACK_PUSHX(stack, int, COPY_RECURSE);
771− *result = tre_ast_new_iter(mem, iter->arg, iter->min,
772− iter->max, iter->minimal);
773− if (*result == NULL)
774− {
775− status = REG_ESPACE;
776− break;
777− }
778− iter = (*result)->obj;
779− result = &iter->arg;
780− break;
781− }
782− default:
783− assert(0);
784− break;
785− }
786− break;
787− }
788− }
789− *pos_add += num_copied;
790− return status;
791−}
792−
793−typedef enum {
794− EXPAND_RECURSE,
795− EXPAND_AFTER_ITER
796−} tre_expand_ast_symbol_t;
797−
798−/* Expands each iteration node that has a finite nonzero minimum or maximum
799− iteration count to a catenated sequence of copies of the node. */
800−static reg_errcode_t
801−tre_expand_ast(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *ast,
802− int *position, tre_tag_direction_t *tag_directions,
803− int *max_depth)
804−{
805− reg_errcode_t status = REG_OK;
806− int bottom = tre_stack_num_objects(stack);
807− int pos_add = 0;
808− int pos_add_total = 0;
809− int max_pos = 0;
810− /* Current approximate matching parameters. */
811− int params[TRE_PARAM_LAST];
812− /* Approximate parameter nesting level. */
813− int params_depth = 0;
814− int iter_depth = 0;
815− int i;
816−
817− for (i = 0; i < TRE_PARAM_LAST; i++)
818− params[i] = TRE_PARAM_DEFAULT;
819−
820− STACK_PUSHR(stack, voidptr, ast);
821− STACK_PUSHR(stack, int, EXPAND_RECURSE);
822− while (status == REG_OK && tre_stack_num_objects(stack) > bottom)
823− {
824− tre_ast_node_t *node;
825− tre_expand_ast_symbol_t symbol;
826−
827− if (status != REG_OK)
828− break;
829−
830− DPRINT(("pos_add %d\n", pos_add));
831−
832− symbol = (tre_expand_ast_symbol_t)tre_stack_pop_int(stack);
833− node = tre_stack_pop_voidptr(stack);
834− switch (symbol)
835− {
836− case EXPAND_RECURSE:
837− switch (node->type)
838− {
839− case LITERAL:
840− {
841− tre_literal_t *lit= node->obj;
842− if (!IS_SPECIAL(lit) || IS_BACKREF(lit))
843− {
844− lit->position += pos_add;
845− if (lit->position > max_pos)
846− max_pos = lit->position;
847− }
848− break;
849− }
850− case UNION:
851− {
852− tre_union_t *uni = node->obj;
853− STACK_PUSHX(stack, voidptr, uni->right);
854− STACK_PUSHX(stack, int, EXPAND_RECURSE);
855− STACK_PUSHX(stack, voidptr, uni->left);
856− STACK_PUSHX(stack, int, EXPAND_RECURSE);
857− break;
858− }
859− case CATENATION:
860− {
861− tre_catenation_t *cat = node->obj;
862− STACK_PUSHX(stack, voidptr, cat->right);
863− STACK_PUSHX(stack, int, EXPAND_RECURSE);
864− STACK_PUSHX(stack, voidptr, cat->left);
865− STACK_PUSHX(stack, int, EXPAND_RECURSE);
866− break;
867− }
868− case ITERATION:
869− {
870− tre_iteration_t *iter = node->obj;
871− STACK_PUSHX(stack, int, pos_add);
872− STACK_PUSHX(stack, voidptr, node);
873− STACK_PUSHX(stack, int, EXPAND_AFTER_ITER);
874− STACK_PUSHX(stack, voidptr, iter->arg);
875− STACK_PUSHX(stack, int, EXPAND_RECURSE);
876− /* If we are going to expand this node at EXPAND_AFTER_ITER
877− then don't increase the `pos' fields of the nodes now, it
878− will get done when expanding. */
879− if (iter->min > 1 || iter->max > 1)
880− pos_add = 0;
881− iter_depth++;
882− DPRINT(("iter\n"));
883− break;
884− }
885− default:
886− assert(0);
887− break;
888− }
889− break;
890− case EXPAND_AFTER_ITER:
891− {
892− tre_iteration_t *iter = node->obj;
893− int pos_add_last;
894− pos_add = tre_stack_pop_int(stack);
895− pos_add_last = pos_add;
896− if (iter->min > 1 || iter->max > 1)
897− {
898− tre_ast_node_t *seq1 = NULL, *seq2 = NULL;
899− int j;
900− int pos_add_save = pos_add;
901−
902− /* Create a catenated sequence of copies of the node. */
903− for (j = 0; j < iter->min; j++)
904− {
905− tre_ast_node_t *copy;
906− /* Remove tags from all but the last copy. */
907− int flags = ((j + 1 < iter->min)
908− ? COPY_REMOVE_TAGS
909− : COPY_MAXIMIZE_FIRST_TAG);
910− DPRINT((" pos_add %d\n", pos_add));
911− pos_add_save = pos_add;
912− status = tre_copy_ast(mem, stack, iter->arg, flags,
913− &pos_add, tag_directions, &copy,
914− &max_pos);
915− if (status != REG_OK)
916− return status;
917− if (seq1 != NULL)
918− seq1 = tre_ast_new_catenation(mem, seq1, copy);
919− else
920− seq1 = copy;
921− if (seq1 == NULL)
922− return REG_ESPACE;
923− }
924−
925− if (iter->max == -1)
926− {
927− /* No upper limit. */
928− pos_add_save = pos_add;
929− status = tre_copy_ast(mem, stack, iter->arg, 0,
930− &pos_add, NULL, &seq2, &max_pos);
931− if (status != REG_OK)
932− return status;
933− seq2 = tre_ast_new_iter(mem, seq2, 0, -1, 0);
934− if (seq2 == NULL)
935− return REG_ESPACE;
936− }
937− else
938− {
939− for (j = iter->min; j < iter->max; j++)
940− {
941− tre_ast_node_t *tmp, *copy;
942− pos_add_save = pos_add;
943− status = tre_copy_ast(mem, stack, iter->arg, 0,
944− &pos_add, NULL, &copy, &max_pos);
945− if (status != REG_OK)
946− return status;
947− if (seq2 != NULL)
948− seq2 = tre_ast_new_catenation(mem, copy, seq2);
949− else
950− seq2 = copy;
951− if (seq2 == NULL)
952− return REG_ESPACE;
953− tmp = tre_ast_new_literal(mem, EMPTY, -1, -1);
954− if (tmp == NULL)
955− return REG_ESPACE;
956− seq2 = tre_ast_new_union(mem, tmp, seq2);
957− if (seq2 == NULL)
958− return REG_ESPACE;
959− }
960− }
961−
962− pos_add = pos_add_save;
963− if (seq1 == NULL)
964− seq1 = seq2;
965− else if (seq2 != NULL)
966− seq1 = tre_ast_new_catenation(mem, seq1, seq2);
967− if (seq1 == NULL)
968− return REG_ESPACE;
969− node->obj = seq1->obj;
970− node->type = seq1->type;
971− }
972−
973− iter_depth--;
974− pos_add_total += pos_add - pos_add_last;
975− if (iter_depth == 0)
976− pos_add = pos_add_total;
977−
978− /* If approximate parameters are specified, surround the result
979− with two parameter setting nodes. The one on the left sets
980− the specified parameters, and the one on the right restores
981− the old parameters. */
982− if (iter->params)
983− {
984− tre_ast_node_t *tmp_l, *tmp_r, *tmp_node, *node_copy;
985− int *old_params;
986−
987− tmp_l = tre_ast_new_literal(mem, PARAMETER, 0, -1);
988− if (!tmp_l)
989− return REG_ESPACE;
990− ((tre_literal_t *)tmp_l->obj)->u.params = iter->params;
991− iter->params[TRE_PARAM_DEPTH] = params_depth + 1;
992− tmp_r = tre_ast_new_literal(mem, PARAMETER, 0, -1);
993− if (!tmp_r)
994− return REG_ESPACE;
995− old_params = tre_mem_alloc(mem, sizeof(*old_params)
996− * TRE_PARAM_LAST);
997− if (!old_params)
998− return REG_ESPACE;
999− for (i = 0; i < TRE_PARAM_LAST; i++)
1000− old_params[i] = params[i];
1001− ((tre_literal_t *)tmp_r->obj)->u.params = old_params;
1002− old_params[TRE_PARAM_DEPTH] = params_depth;
1003− /* XXX - this is the only place where ast_new_node is
1004− needed -- should be moved inside AST module. */
1005− node_copy = tre_ast_new_node(mem, ITERATION,
1006− sizeof(tre_iteration_t));
1007− if (!node_copy)
1008− return REG_ESPACE;
1009− node_copy->obj = node->obj;
1010− tmp_node = tre_ast_new_catenation(mem, tmp_l, node_copy);
1011− if (!tmp_node)
1012− return REG_ESPACE;
1013− tmp_node = tre_ast_new_catenation(mem, tmp_node, tmp_r);
1014− if (!tmp_node)
1015− return REG_ESPACE;
1016− /* Replace the contents of `node' with `tmp_node'. */
1017− memcpy(node, tmp_node, sizeof(*node));
1018− node->obj = tmp_node->obj;
1019− node->type = tmp_node->type;
1020− params_depth++;
1021− if (params_depth > *max_depth)
1022− *max_depth = params_depth;
1023− }
1024− break;
1025− }
1026− default:
1027− assert(0);
1028− break;
1029− }
1030− }
1031−
1032− *position += pos_add_total;
1033−
1034− /* `max_pos' should never be larger than `*position' if the above
1035− code works, but just an extra safeguard let's make sure
1036− `*position' is set large enough so enough memory will be
1037− allocated for the transition table. */
1038− if (max_pos > *position)
1039− *position = max_pos;
1040−
1041−#ifdef TRE_DEBUG
1042− DPRINT(("Expanded AST:\n"));
1043− tre_ast_print(ast);
1044− DPRINT(("*position %d, max_pos %d\n", *position, max_pos));
1045−#endif
1046−
1047− return status;
1048−}
1049−
1050−static tre_pos_and_tags_t *
1051−tre_set_empty(tre_mem_t mem)
1052−{
1053− tre_pos_and_tags_t *new_set;
1054−
1055− new_set = tre_mem_calloc(mem, sizeof(*new_set));
1056− if (new_set == NULL)
1057− return NULL;
1058−
1059− new_set[0].position = -1;
1060− new_set[0].code_min = -1;
1061− new_set[0].code_max = -1;
1062−
1063− return new_set;
1064−}
1065−
1066−static tre_pos_and_tags_t *
1067−tre_set_one(tre_mem_t mem, int position, int code_min, int code_max,
1068− tre_ctype_t class, tre_ctype_t *neg_classes, int backref)
1069−{
1070− tre_pos_and_tags_t *new_set;
1071−
1072− new_set = tre_mem_calloc(mem, sizeof(*new_set) * 2);
1073− if (new_set == NULL)
1074− return NULL;
1075−
1076− new_set[0].position = position;
1077− new_set[0].code_min = code_min;
1078− new_set[0].code_max = code_max;
1079− new_set[0].class = class;
1080− new_set[0].neg_classes = neg_classes;
1081− new_set[0].backref = backref;
1082− new_set[1].position = -1;
1083− new_set[1].code_min = -1;
1084− new_set[1].code_max = -1;
1085−
1086− return new_set;
1087−}
1088−
1089−static tre_pos_and_tags_t *
1090−tre_set_union(tre_mem_t mem, tre_pos_and_tags_t *set1, tre_pos_and_tags_t *set2,
1091− int *tags, int assertions, int *params)
1092−{
1093− int s1, s2, i, j;
1094− tre_pos_and_tags_t *new_set;
1095− int *new_tags;
1096− int num_tags;
1097−
1098− for (num_tags = 0; tags != NULL && tags[num_tags] >= 0; num_tags++);
1099− for (s1 = 0; set1[s1].position >= 0; s1++);
1100− for (s2 = 0; set2[s2].position >= 0; s2++);
1101− new_set = tre_mem_calloc(mem, sizeof(*new_set) * (s1 + s2 + 1));
1102− if (!new_set )
1103− return NULL;
1104−
1105− for (s1 = 0; set1[s1].position >= 0; s1++)
1106− {
1107− new_set[s1].position = set1[s1].position;
1108− new_set[s1].code_min = set1[s1].code_min;
1109− new_set[s1].code_max = set1[s1].code_max;
1110− new_set[s1].assertions = set1[s1].assertions | assertions;
1111− new_set[s1].class = set1[s1].class;
1112− new_set[s1].neg_classes = set1[s1].neg_classes;
1113− new_set[s1].backref = set1[s1].backref;
1114− if (set1[s1].tags == NULL && tags == NULL)
1115− new_set[s1].tags = NULL;
1116− else
1117− {
1118− for (i = 0; set1[s1].tags != NULL && set1[s1].tags[i] >= 0; i++);
1119− new_tags = tre_mem_alloc(mem, (sizeof(*new_tags)
1120− * (i + num_tags + 1)));
1121− if (new_tags == NULL)
1122− return NULL;
1123− for (j = 0; j < i; j++)
1124− new_tags[j] = set1[s1].tags[j];
1125− for (i = 0; i < num_tags; i++)
1126− new_tags[j + i] = tags[i];
1127− new_tags[j + i] = -1;
1128− new_set[s1].tags = new_tags;
1129− }
1130− if (set1[s1].params)
1131− new_set[s1].params = set1[s1].params;
1132− if (params)
1133− {
1134− if (!new_set[s1].params)
1135− new_set[s1].params = params;
1136− else
1137− {
1138− new_set[s1].params = tre_mem_alloc(mem, sizeof(*params) *
1139− TRE_PARAM_LAST);
1140− if (!new_set[s1].params)
1141− return NULL;
1142− for (i = 0; i < TRE_PARAM_LAST; i++)
1143− if (params[i] != TRE_PARAM_UNSET)
1144− new_set[s1].params[i] = params[i];
1145− }
1146− }
1147− }
1148−
1149− for (s2 = 0; set2[s2].position >= 0; s2++)
1150− {
1151− new_set[s1 + s2].position = set2[s2].position;
1152− new_set[s1 + s2].code_min = set2[s2].code_min;
1153− new_set[s1 + s2].code_max = set2[s2].code_max;
1154− /* XXX - why not | assertions here as well? */
1155− new_set[s1 + s2].assertions = set2[s2].assertions;
1156− new_set[s1 + s2].class = set2[s2].class;
1157− new_set[s1 + s2].neg_classes = set2[s2].neg_classes;
1158− new_set[s1 + s2].backref = set2[s2].backref;
1159− if (set2[s2].tags == NULL)
1160− new_set[s1 + s2].tags = NULL;
1161− else
1162− {
1163− for (i = 0; set2[s2].tags[i] >= 0; i++);
1164− new_tags = tre_mem_alloc(mem, sizeof(*new_tags) * (i + 1));
1165− if (new_tags == NULL)
1166− return NULL;
1167− for (j = 0; j < i; j++)
1168− new_tags[j] = set2[s2].tags[j];
1169− new_tags[j] = -1;
1170− new_set[s1 + s2].tags = new_tags;
1171− }
1172− if (set2[s2].params)
1173− new_set[s1 + s2].params = set2[s2].params;
1174− if (params)
1175− {
1176− if (!new_set[s1 + s2].params)
1177− new_set[s1 + s2].params = params;
1178− else
1179− {
1180− new_set[s1 + s2].params = tre_mem_alloc(mem, sizeof(*params) *
1181− TRE_PARAM_LAST);
1182− if (!new_set[s1 + s2].params)
1183− return NULL;
1184− for (i = 0; i < TRE_PARAM_LAST; i++)
1185− if (params[i] != TRE_PARAM_UNSET)
1186− new_set[s1 + s2].params[i] = params[i];
1187− }
1188− }
1189− }
1190− new_set[s1 + s2].position = -1;
1191− return new_set;
1192−}
1193−
1194−/* Finds the empty path through `node' which is the one that should be
1195− taken according to POSIX.2 rules, and adds the tags on that path to
1196− `tags'. `tags' may be NULL. If `num_tags_seen' is not NULL, it is
1197− set to the number of tags seen on the path. */
1198−static reg_errcode_t
1199−tre_match_empty(tre_stack_t *stack, tre_ast_node_t *node, int *tags,
1200− int *assertions, int *params, int *num_tags_seen,
1201− int *params_seen)
1202−{
1203− tre_literal_t *lit;
1204− tre_union_t *uni;
1205− tre_catenation_t *cat;
1206− tre_iteration_t *iter;
1207− int i;
1208− int bottom = tre_stack_num_objects(stack);
1209− reg_errcode_t status = REG_OK;
1210− if (num_tags_seen)
1211− *num_tags_seen = 0;
1212− if (params_seen)
1213− *params_seen = 0;
1214−
1215− status = tre_stack_push_voidptr(stack, node);
1216−
1217− /* Walk through the tree recursively. */
1218− while (status == REG_OK && tre_stack_num_objects(stack) > bottom)
1219− {
1220− node = tre_stack_pop_voidptr(stack);
1221−
1222− switch (node->type)
1223− {
1224− case LITERAL:
1225− lit = (tre_literal_t *)node->obj;
1226− switch (lit->code_min)
1227− {
1228− case TAG:
1229− if (lit->code_max >= 0)
1230− {
1231− if (tags != NULL)
1232− {
1233− /* Add the tag to `tags'. */
1234− for (i = 0; tags[i] >= 0; i++)
1235− if (tags[i] == lit->code_max)
1236− break;
1237− if (tags[i] < 0)
1238− {
1239− tags[i] = lit->code_max;
1240− tags[i + 1] = -1;
1241− }
1242− }
1243− if (num_tags_seen)
1244− (*num_tags_seen)++;
1245− }
1246− break;
1247− case ASSERTION:
1248− assert(lit->code_max >= 1
1249− || lit->code_max <= ASSERT_LAST);
1250− if (assertions != NULL)
1251− *assertions |= lit->code_max;
1252− break;
1253− case PARAMETER:
1254− if (params != NULL)
1255− for (i = 0; i < TRE_PARAM_LAST; i++)
1256− params[i] = lit->u.params[i];
1257− if (params_seen != NULL)
1258− *params_seen = 1;
1259− break;
1260− case EMPTY:
1261− break;
1262− default:
1263− assert(0);
1264− break;
1265− }
1266− break;
1267−
1268− case UNION:
1269− /* Subexpressions starting earlier take priority over ones
1270− starting later, so we prefer the left subexpression over the
1271− right subexpression. */
1272− uni = (tre_union_t *)node->obj;
1273− if (uni->left->nullable)
1274− STACK_PUSHX(stack, voidptr, uni->left)
1275− else if (uni->right->nullable)
1276− STACK_PUSHX(stack, voidptr, uni->right)
1277− else
1278− assert(0);
1279− break;
1280−
1281− case CATENATION:
1282− /* The path must go through both children. */
1283− cat = (tre_catenation_t *)node->obj;
1284− assert(cat->left->nullable);
1285− assert(cat->right->nullable);
1286− STACK_PUSHX(stack, voidptr, cat->left);
1287− STACK_PUSHX(stack, voidptr, cat->right);
1288− break;
1289−
1290− case ITERATION:
1291− /* A match with an empty string is preferred over no match at
1292− all, so we go through the argument if possible. */
1293− iter = (tre_iteration_t *)node->obj;
1294− if (iter->arg->nullable)
1295− STACK_PUSHX(stack, voidptr, iter->arg);
1296− break;
1297−
1298− default:
1299− assert(0);
1300− break;
1301− }
1302− }
1303−
1304− return status;
1305−}
1306−
1307−
1308−typedef enum {
1309− NFL_RECURSE,
1310− NFL_POST_UNION,
1311− NFL_POST_CATENATION,
1312− NFL_POST_ITERATION
1313−} tre_nfl_stack_symbol_t;
1314−
1315−
1316−/* Computes and fills in the fields `nullable', `firstpos', and `lastpos' for
1317− the nodes of the AST `tree'. */
1318−static reg_errcode_t
1319−tre_compute_nfl(tre_mem_t mem, tre_stack_t *stack, tre_ast_node_t *tree)
1320−{
1321− int bottom = tre_stack_num_objects(stack);
1322−
1323− STACK_PUSHR(stack, voidptr, tree);
1324− STACK_PUSHR(stack, int, NFL_RECURSE);
1325−
1326− while (tre_stack_num_objects(stack) > bottom)
1327− {
1328− tre_nfl_stack_symbol_t symbol;
1329− tre_ast_node_t *node;
1330−
1331− symbol = (tre_nfl_stack_symbol_t)tre_stack_pop_int(stack);
1332− node = tre_stack_pop_voidptr(stack);
1333− switch (symbol)
1334− {
1335− case NFL_RECURSE:
1336− switch (node->type)
1337− {
1338− case LITERAL:
1339− {
1340− tre_literal_t *lit = (tre_literal_t *)node->obj;
1341− if (IS_BACKREF(lit))
1342− {
1343− /* Back references: nullable = false, firstpos = {i},
1344− lastpos = {i}. */
1345− node->nullable = 0;
1346− node->firstpos = tre_set_one(mem, lit->position, 0,
1347− TRE_CHAR_MAX, 0, NULL, -1);
1348− if (!node->firstpos)
1349− return REG_ESPACE;
1350− node->lastpos = tre_set_one(mem, lit->position, 0,
1351− TRE_CHAR_MAX, 0, NULL,
1352− (int)lit->code_max);
1353− if (!node->lastpos)
1354− return REG_ESPACE;
1355− }
1356− else if (lit->code_min < 0)
1357− {
1358− /* Tags, empty strings, params, and zero width assertions:
1359− nullable = true, firstpos = {}, and lastpos = {}. */
1360− node->nullable = 1;
1361− node->firstpos = tre_set_empty(mem);
1362− if (!node->firstpos)
1363− return REG_ESPACE;
1364− node->lastpos = tre_set_empty(mem);
1365− if (!node->lastpos)
1366− return REG_ESPACE;
1367− }
1368− else
1369− {
1370− /* Literal at position i: nullable = false, firstpos = {i},
1371− lastpos = {i}. */
1372− node->nullable = 0;
1373− node->firstpos =
1374− tre_set_one(mem, lit->position, (int)lit->code_min,
1375− (int)lit->code_max, 0, NULL, -1);
1376− if (!node->firstpos)
1377− return REG_ESPACE;
1378− node->lastpos = tre_set_one(mem, lit->position,
1379− (int)lit->code_min,
1380− (int)lit->code_max,
1381− lit->u.class, lit->neg_classes,
1382− -1);
1383− if (!node->lastpos)
1384− return REG_ESPACE;
1385− }
1386− break;
1387− }
1388−
1389− case UNION:
1390− /* Compute the attributes for the two subtrees, and after that
1391− for this node. */
1392− STACK_PUSHR(stack, voidptr, node);
1393− STACK_PUSHR(stack, int, NFL_POST_UNION);
1394− STACK_PUSHR(stack, voidptr, ((tre_union_t *)node->obj)->right);
1395− STACK_PUSHR(stack, int, NFL_RECURSE);
1396− STACK_PUSHR(stack, voidptr, ((tre_union_t *)node->obj)->left);
1397− STACK_PUSHR(stack, int, NFL_RECURSE);
1398− break;
1399−
1400− case CATENATION:
1401− /* Compute the attributes for the two subtrees, and after that
1402− for this node. */
1403− STACK_PUSHR(stack, voidptr, node);
1404− STACK_PUSHR(stack, int, NFL_POST_CATENATION);
1405− STACK_PUSHR(stack, voidptr, ((tre_catenation_t *)node->obj)->right);
1406− STACK_PUSHR(stack, int, NFL_RECURSE);
1407− STACK_PUSHR(stack, voidptr, ((tre_catenation_t *)node->obj)->left);
1408− STACK_PUSHR(stack, int, NFL_RECURSE);
1409− break;
1410−
1411− case ITERATION:
1412− /* Compute the attributes for the subtree, and after that for
1413− this node. */
1414− STACK_PUSHR(stack, voidptr, node);
1415− STACK_PUSHR(stack, int, NFL_POST_ITERATION);
1416− STACK_PUSHR(stack, voidptr, ((tre_iteration_t *)node->obj)->arg);
1417− STACK_PUSHR(stack, int, NFL_RECURSE);
1418− break;
1419− }
1420− break; /* end case: NFL_RECURSE */
1421−
1422− case NFL_POST_UNION:
1423− {
1424− tre_union_t *uni = (tre_union_t *)node->obj;
1425− node->nullable = uni->left->nullable || uni->right->nullable;
1426− node->firstpos = tre_set_union(mem, uni->left->firstpos,
1427− uni->right->firstpos, NULL, 0, NULL);
1428− if (!node->firstpos)
1429− return REG_ESPACE;
1430− node->lastpos = tre_set_union(mem, uni->left->lastpos,
1431− uni->right->lastpos, NULL, 0, NULL);
1432− if (!node->lastpos)
1433− return REG_ESPACE;
1434− break;
1435− }
1436−
1437− case NFL_POST_ITERATION:
1438− {
1439− tre_iteration_t *iter = (tre_iteration_t *)node->obj;
1440−
1441− if (iter->min == 0 || iter->arg->nullable)
1442− node->nullable = 1;
1443− else
1444− node->nullable = 0;
1445− node->firstpos = iter->arg->firstpos;
1446− node->lastpos = iter->arg->lastpos;
1447− break;
1448− }
1449−
1450− case NFL_POST_CATENATION:
1451− {
1452− int num_tags, *tags, assertions, params_seen;
1453− int *params;
1454− reg_errcode_t status;
1455− tre_catenation_t *cat = node->obj;
1456− node->nullable = cat->left->nullable && cat->right->nullable;
1457−
1458− /* Compute firstpos. */
1459− if (cat->left->nullable)
1460− {
1461− /* The left side matches the empty string. Make a first pass
1462− with tre_match_empty() to get the number of tags and
1463− parameters. */
1464− status = tre_match_empty(stack, cat->left,
1465− NULL, NULL, NULL, &num_tags,
1466− &params_seen);
1467− if (status != REG_OK)
1468− return status;
1469− /* Allocate arrays for the tags and parameters. */
1470− tags = xmalloc(sizeof(*tags) * (num_tags + 1));
1471− if (!tags)
1472− return REG_ESPACE;
1473− tags[0] = -1;
1474− assertions = 0;
1475− params = NULL;
1476− if (params_seen)
1477− {
1478− params = tre_mem_alloc(mem, sizeof(*params)
1479− * TRE_PARAM_LAST);
1480− if (!params)
1481− {
1482− xfree(tags);
1483− return REG_ESPACE;
1484− }
1485− }
1486− /* Second pass with tre_mach_empty() to get the list of
1487− tags and parameters. */
1488− status = tre_match_empty(stack, cat->left, tags,
1489− &assertions, params, NULL, NULL);
1490− if (status != REG_OK)
1491− {
1492− xfree(tags);
1493− return status;
1494− }
1495− node->firstpos =
1496− tre_set_union(mem, cat->right->firstpos, cat->left->firstpos,
1497− tags, assertions, params);
1498− xfree(tags);
1499− if (!node->firstpos)
1500− return REG_ESPACE;
1501− }
1502− else
1503− {
1504− node->firstpos = cat->left->firstpos;
1505− }
1506−
1507− /* Compute lastpos. */
1508− if (cat->right->nullable)
1509− {
1510− /* The right side matches the empty string. Make a first pass
1511− with tre_match_empty() to get the number of tags and
1512− parameters. */
1513− status = tre_match_empty(stack, cat->right,
1514− NULL, NULL, NULL, &num_tags,
1515− &params_seen);
1516− if (status != REG_OK)
1517− return status;
1518− /* Allocate arrays for the tags and parameters. */
1519− tags = xmalloc(sizeof(int) * (num_tags + 1));
1520− if (!tags)
1521− return REG_ESPACE;
1522− tags[0] = -1;
1523− assertions = 0;
1524− params = NULL;
1525− if (params_seen)
1526− {
1527− params = tre_mem_alloc(mem, sizeof(*params)
1528− * TRE_PARAM_LAST);
1529− if (!params)
1530− {
1531− xfree(tags);
1532− return REG_ESPACE;
1533− }
1534− }
1535− /* Second pass with tre_mach_empty() to get the list of
1536− tags and parameters. */
1537− status = tre_match_empty(stack, cat->right, tags,
1538− &assertions, params, NULL, NULL);
1539− if (status != REG_OK)
1540− {
1541− xfree(tags);
1542− return status;
1543− }
1544− node->lastpos =
1545− tre_set_union(mem, cat->left->lastpos, cat->right->lastpos,
1546− tags, assertions, params);
1547− xfree(tags);
1548− if (!node->lastpos)
1549− return REG_ESPACE;
1550− }
1551− else
1552− {
1553− node->lastpos = cat->right->lastpos;
1554− }
1555− break;
1556− }
1557−
1558− default:
1559− assert(0);
1560− break;
1561− }
1562− }
1563−
1564− return REG_OK;
1565−}
1566−
1567−
1568−/* Adds a transition from each position in `p1' to each position in `p2'. */
1569−static reg_errcode_t
1570−tre_make_trans(tre_pos_and_tags_t *p1, tre_pos_and_tags_t *p2,
1571− tre_tnfa_transition_t *transitions,
1572− int *counts, int *offs)
1573−{
1574− tre_pos_and_tags_t *orig_p2 = p2;
1575− tre_tnfa_transition_t *trans;
1576− int i, j, k, l, dup, prev_p2_pos;
1577−
1578− if (transitions != NULL)
1579− while (p1->position >= 0)
1580− {
1581− p2 = orig_p2;
1582− prev_p2_pos = -1;
1583− while (p2->position >= 0)
1584− {
1585− /* Optimization: if this position was already handled, skip it. */
1586− if (p2->position == prev_p2_pos)
1587− {
1588− p2++;
1589− continue;
1590− }
1591− prev_p2_pos = p2->position;
1592− /* Set `trans' to point to the next unused transition from
1593− position `p1->position'. */
1594− trans = transitions + offs[p1->position];
1595− while (trans->state != NULL)
1596− {
1597−#if 0
1598− /* If we find a previous transition from `p1->position' to
1599− `p2->position', it is overwritten. This can happen only
1600− if there are nested loops in the regexp, like in "((a)*)*".
1601− In POSIX.2 repetition using the outer loop is always
1602− preferred over using the inner loop. Therefore the
1603− transition for the inner loop is useless and can be thrown
1604− away. */
1605− /* XXX - The same position is used for all nodes in a bracket
1606− expression, so this optimization cannot be used (it will
1607− break bracket expressions) unless I figure out a way to
1608− detect it here. */
1609− if (trans->state_id == p2->position)
1610− {
1611− DPRINT(("*"));
1612− break;
1613− }
1614−#endif
1615− trans++;
1616− }
1617−
1618− if (trans->state == NULL)
1619− (trans + 1)->state = NULL;
1620− /* Use the character ranges, assertions, etc. from `p1' for
1621− the transition from `p1' to `p2'. */
1622− trans->code_min = p1->code_min;
1623− trans->code_max = p1->code_max;
1624− trans->state = transitions + offs[p2->position];
1625− trans->state_id = p2->position;
1626− trans->assertions = p1->assertions | p2->assertions
1627− | (p1->class ? ASSERT_CHAR_CLASS : 0)
1628− | (p1->neg_classes != NULL ? ASSERT_CHAR_CLASS_NEG : 0);
1629− if (p1->backref >= 0)
1630− {
1631− assert((trans->assertions & ASSERT_CHAR_CLASS) == 0);
1632− assert(p2->backref < 0);
1633− trans->u.backref = p1->backref;
1634− trans->assertions |= ASSERT_BACKREF;
1635− }
1636− else
1637− trans->u.class = p1->class;
1638− if (p1->neg_classes != NULL)
1639− {
1640− for (i = 0; p1->neg_classes[i] != (tre_ctype_t)0; i++);
1641− trans->neg_classes =
1642− xmalloc(sizeof(*trans->neg_classes) * (i + 1));
1643− if (trans->neg_classes == NULL)
1644− return REG_ESPACE;
1645− for (i = 0; p1->neg_classes[i] != (tre_ctype_t)0; i++)
1646− trans->neg_classes[i] = p1->neg_classes[i];
1647− trans->neg_classes[i] = (tre_ctype_t)0;
1648− }
1649− else
1650− trans->neg_classes = NULL;
1651−
1652− /* Find out how many tags this transition has. */
1653− i = 0;
1654− if (p1->tags != NULL)
1655− while(p1->tags[i] >= 0)
1656− i++;
1657− j = 0;
1658− if (p2->tags != NULL)
1659− while(p2->tags[j] >= 0)
1660− j++;
1661−
1662− /* If we are overwriting a transition, free the old tag array. */
1663− if (trans->tags != NULL)
1664− xfree(trans->tags);
1665− trans->tags = NULL;
1666−
1667− /* If there were any tags, allocate an array and fill it. */
1668− if (i + j > 0)
1669− {
1670− trans->tags = xmalloc(sizeof(*trans->tags) * (i + j + 1));
1671− if (!trans->tags)
1672− return REG_ESPACE;
1673− i = 0;
1674− if (p1->tags != NULL)
1675− while(p1->tags[i] >= 0)
1676− {
1677− trans->tags[i] = p1->tags[i];
1678− i++;
1679− }
1680− l = i;
1681− j = 0;
1682− if (p2->tags != NULL)
1683− while (p2->tags[j] >= 0)
1684− {
1685− /* Don't add duplicates. */
1686− dup = 0;
1687− for (k = 0; k < i; k++)
1688− if (trans->tags[k] == p2->tags[j])
1689− {
1690− dup = 1;
1691− break;
1692− }
1693− if (!dup)
1694− trans->tags[l++] = p2->tags[j];
1695− j++;
1696− }
1697− trans->tags[l] = -1;
1698− }
1699−
1700− /* Set the parameter array. If both `p2' and `p1' have same
1701− parameters, the values in `p2' override those in `p1'. */
1702− if (p1->params || p2->params)
1703− {
1704− if (!trans->params)
1705− trans->params = xmalloc(sizeof(*trans->params)
1706− * TRE_PARAM_LAST);
1707− if (!trans->params)
1708− return REG_ESPACE;
1709− for (i = 0; i < TRE_PARAM_LAST; i++)
1710− {
1711− trans->params[i] = TRE_PARAM_UNSET;
1712− if (p1->params && p1->params[i] != TRE_PARAM_UNSET)
1713− trans->params[i] = p1->params[i];
1714− if (p2->params && p2->params[i] != TRE_PARAM_UNSET)
1715− trans->params[i] = p2->params[i];
1716− }
1717− }
1718− else
1719− {
1720− if (trans->params)
1721− xfree(trans->params);
1722− trans->params = NULL;
1723− }
1724−
1725−
1726−#ifdef TRE_DEBUG
1727− {
1728− int *tags;
1729−
1730− DPRINT((" %2d -> %2d on %3d", p1->position, p2->position,
1731− p1->code_min));
1732− if (p1->code_max != p1->code_min)
1733− DPRINT(("-%3d", p1->code_max));
1734− tags = trans->tags;
1735− if (tags)
1736− {
1737− DPRINT((", tags ["));
1738− while (*tags >= 0)
1739− {
1740− DPRINT(("%d", *tags));
1741− tags++;
1742− if (*tags >= 0)
1743− DPRINT((","));
1744− }
1745− DPRINT(("]"));
1746− }
1747− if (trans->assertions)
1748− DPRINT((", assert %d", trans->assertions));
1749− if (trans->assertions & ASSERT_BACKREF)
1750− DPRINT((", backref %d", trans->u.backref));
1751− else if (trans->u.class)
1752− DPRINT((", class %ld", (long)trans->u.class));
1753− if (trans->neg_classes)
1754− DPRINT((", neg_classes %p", trans->neg_classes));
1755− if (trans->params)
1756− {
1757− DPRINT((", "));
1758− tre_print_params(trans->params);
1759− }
1760− DPRINT(("\n"));
1761− }
1762−#endif /* TRE_DEBUG */
1763− p2++;
1764− }
1765− p1++;
1766− }
1767− else
1768− /* Compute a maximum limit for the number of transitions leaving
1769− from each state. */
1770− while (p1->position >= 0)
1771− {
1772− p2 = orig_p2;
1773− while (p2->position >= 0)
1774− {
1775− counts[p1->position]++;
1776− p2++;
1777− }
1778− p1++;
1779− }
1780− return REG_OK;
1781−}
1782−
1783−/* Converts the syntax tree to a TNFA. All the transitions in the TNFA are
1784− labelled with one character range (there are no transitions on empty
1785− strings). The TNFA takes O(n^2) space in the worst case, `n' is size of
1786− the regexp. */
1787−static reg_errcode_t
1788−tre_ast_to_tnfa(tre_ast_node_t *node, tre_tnfa_transition_t *transitions,
1789− int *counts, int *offs)
1790−{
1791− tre_union_t *uni;
1792− tre_catenation_t *cat;
1793− tre_iteration_t *iter;
1794− reg_errcode_t errcode = REG_OK;
1795−
1796− /* XXX - recurse using a stack!. */
1797− switch (node->type)
1798− {
1799− case LITERAL:
1800− break;
1801− case UNION:
1802− uni = (tre_union_t *)node->obj;
1803− errcode = tre_ast_to_tnfa(uni->left, transitions, counts, offs);
1804− if (errcode != REG_OK)
1805− return errcode;
1806− errcode = tre_ast_to_tnfa(uni->right, transitions, counts, offs);
1807− break;
1808−
1809− case CATENATION:
1810− cat = (tre_catenation_t *)node->obj;
1811− /* Add a transition from each position in cat->left->lastpos
1812− to each position in cat->right->firstpos. */
1813− errcode = tre_make_trans(cat->left->lastpos, cat->right->firstpos,
1814− transitions, counts, offs);
1815− if (errcode != REG_OK)
1816− return errcode;
1817− errcode = tre_ast_to_tnfa(cat->left, transitions, counts, offs);
1818− if (errcode != REG_OK)
1819− return errcode;
1820− errcode = tre_ast_to_tnfa(cat->right, transitions, counts, offs);
1821− break;
1822−
1823− case ITERATION:
1824− iter = (tre_iteration_t *)node->obj;
1825− assert(iter->max == -1 || iter->max == 1);
1826−
1827− if (iter->max == -1)
1828− {
1829− assert(iter->min == 0 || iter->min == 1);
1830− /* Add a transition from each last position in the iterated
1831− expression to each first position. */
1832− errcode = tre_make_trans(iter->arg->lastpos, iter->arg->firstpos,
1833− transitions, counts, offs);
1834− if (errcode != REG_OK)
1835− return errcode;
1836− }
1837− errcode = tre_ast_to_tnfa(iter->arg, transitions, counts, offs);
1838− break;
1839− }
1840− return errcode;
1841−}
1842−
1843−
1844−#define ERROR_EXIT(err) \
1845− do \
1846− { \
1847− errcode = err; \
1848− if (/*CONSTCOND*/1) \
1849− goto error_exit; \
1850− } \
1851− while (/*CONSTCOND*/0)
1852−
1853−
1854−int
1855−tre_compile(regex_t *preg, const tre_char_t *regex, size_t n, int cflags)
1856−{
1857− tre_stack_t *stack;
1858− tre_ast_node_t *tree, *tmp_ast_l, *tmp_ast_r;
1859− tre_pos_and_tags_t *p;
1860− int *counts = NULL, *offs = NULL;
1861− int i, add = 0;
1862− tre_tnfa_transition_t *transitions, *initial;
1863− tre_tnfa_t *tnfa = NULL;
1864− tre_submatch_data_t *submatch_data;
1865− tre_tag_direction_t *tag_directions = NULL;
1866− reg_errcode_t errcode;
1867− tre_mem_t mem;
1868−
1869− /* Parse context. */
1870− tre_parse_ctx_t parse_ctx;
1871−
1872− /* Allocate a stack used throughout the compilation process for various
1873− purposes. */
1874− stack = tre_stack_new(512, 10240, 128);
1875− if (!stack)
1876− return REG_ESPACE;
1877− /* Allocate a fast memory allocator. */
1878− mem = tre_mem_new();
1879− if (!mem)
1880− {
1881− tre_stack_destroy(stack);
1882− return REG_ESPACE;
1883− }
1884−
1885− /* Parse the regexp. */
1886− memset(&parse_ctx, 0, sizeof(parse_ctx));
1887− parse_ctx.mem = mem;
1888− parse_ctx.stack = stack;
1889− parse_ctx.re = regex;
1890− parse_ctx.len = (int)n; // 1.4.1.1 (ge) added cast to get rid of win64 warning
1891− parse_ctx.cflags = cflags;
1892− parse_ctx.max_backref = -1;
1893− DPRINT(("tre_compile: parsing '%.*" STRF "'\n", (int)n, regex));
1894− errcode = tre_parse(&parse_ctx);
1895− if (errcode != REG_OK)
1896− ERROR_EXIT(errcode);
1897− preg->re_nsub = parse_ctx.submatch_id - 1;
1898− tree = parse_ctx.result;
1899−
1900− /* Back references and approximate matching cannot currently be used
1901− in the same regexp. */
1902− if (parse_ctx.max_backref >= 0 && parse_ctx.have_approx)
1903− ERROR_EXIT(REG_BADPAT);
1904−
1905−#ifdef TRE_DEBUG
1906− tre_ast_print(tree);
1907−#endif /* TRE_DEBUG */
1908−
1909− /* Referring to nonexistent subexpressions is illegal. */
1910− if (parse_ctx.max_backref > (int)preg->re_nsub)
1911− ERROR_EXIT(REG_ESUBREG);
1912−
1913− /* Allocate the TNFA struct. */
1914− tnfa = xcalloc(1, sizeof(tre_tnfa_t));
1915− if (tnfa == NULL)
1916− ERROR_EXIT(REG_ESPACE);
1917− tnfa->have_backrefs = parse_ctx.max_backref >= 0;
1918− tnfa->have_approx = parse_ctx.have_approx;
1919− tnfa->num_submatches = parse_ctx.submatch_id;
1920−
1921− /* Set up tags for submatch addressing. If REG_NOSUB is set and the
1922− regexp does not have back references, this can be skipped. */
1923− if (tnfa->have_backrefs || !(cflags & REG_NOSUB))
1924− {
1925− DPRINT(("tre_compile: setting up tags\n"));
1926−
1927− /* Figure out how many tags we will need. */
1928− errcode = tre_add_tags(NULL, stack, tree, tnfa);
1929− if (errcode != REG_OK)
1930− ERROR_EXIT(errcode);
1931−#ifdef TRE_DEBUG
1932− tre_ast_print(tree);
1933−#endif /* TRE_DEBUG */
1934−
1935− if (tnfa->num_tags > 0)
1936− {
1937− tag_directions = xmalloc(sizeof(*tag_directions)
1938− * (tnfa->num_tags + 1));
1939− if (tag_directions == NULL)
1940− ERROR_EXIT(REG_ESPACE);
1941− tnfa->tag_directions = tag_directions;
1942− memset(tag_directions, -1,
1943− sizeof(*tag_directions) * (tnfa->num_tags + 1));
1944− }
1945− tnfa->minimal_tags = xcalloc((unsigned)tnfa->num_tags * 2 + 1,
1946− sizeof(tnfa->minimal_tags));
1947− if (tnfa->minimal_tags == NULL)
1948− ERROR_EXIT(REG_ESPACE);
1949−
1950− submatch_data = xcalloc((unsigned)parse_ctx.submatch_id,
1951− sizeof(*submatch_data));
1952− if (submatch_data == NULL)
1953− ERROR_EXIT(REG_ESPACE);
1954− tnfa->submatch_data = submatch_data;
1955−
1956− errcode = tre_add_tags(mem, stack, tree, tnfa);
1957− if (errcode != REG_OK)
1958− ERROR_EXIT(errcode);
1959−
1960−#ifdef TRE_DEBUG
1961− for (i = 0; i < parse_ctx.submatch_id; i++)
1962− DPRINT(("pmatch[%d] = {t%d, t%d}\n",
1963− i, submatch_data[i].so_tag, submatch_data[i].eo_tag));
1964− for (i = 0; i < tnfa->num_tags; i++)
1965− DPRINT(("t%d is %s\n", i,
1966− tag_directions[i] == TRE_TAG_MINIMIZE ?
1967− "minimized" : "maximized"));
1968−#endif /* TRE_DEBUG */
1969− }
1970−
1971− /* Expand iteration nodes. */
1972− errcode = tre_expand_ast(mem, stack, tree, &parse_ctx.position,
1973− tag_directions, &tnfa->params_depth);
1974− if (errcode != REG_OK)
1975− ERROR_EXIT(errcode);
1976−
1977− /* Add a dummy node for the final state.
1978− XXX - For certain patterns this dummy node can be optimized away,
1979− for example "a*" or "ab*". Figure out a simple way to detect
1980− this possibility. */
1981− tmp_ast_l = tree;
1982− tmp_ast_r = tre_ast_new_literal(mem, 0, 0, parse_ctx.position++);
1983− if (tmp_ast_r == NULL)
1984− ERROR_EXIT(REG_ESPACE);
1985−
1986− tree = tre_ast_new_catenation(mem, tmp_ast_l, tmp_ast_r);
1987− if (tree == NULL)
1988− ERROR_EXIT(REG_ESPACE);
1989−
1990−#ifdef TRE_DEBUG
1991− tre_ast_print(tree);
1992− DPRINT(("Number of states: %d\n", parse_ctx.position));
1993−#endif /* TRE_DEBUG */
1994−
1995− errcode = tre_compute_nfl(mem, stack, tree);
1996− if (errcode != REG_OK)
1997− ERROR_EXIT(errcode);
1998−
1999− counts = xmalloc(sizeof(int) * parse_ctx.position);
2000− if (counts == NULL)
2001− ERROR_EXIT(REG_ESPACE);
2002−
2003− offs = xmalloc(sizeof(int) * parse_ctx.position);
2004− if (offs == NULL)
2005− ERROR_EXIT(REG_ESPACE);
2006−
2007− for (i = 0; i < parse_ctx.position; i++)
2008− counts[i] = 0;
2009− tre_ast_to_tnfa(tree, NULL, counts, NULL);
2010−
2011− add = 0;
2012− for (i = 0; i < parse_ctx.position; i++)
2013− {
2014− offs[i] = add;
2015− add += counts[i] + 1;
2016− counts[i] = 0;
2017− }
2018− transitions = xcalloc((unsigned)add + 1, sizeof(*transitions));
2019− if (transitions == NULL)
2020− ERROR_EXIT(REG_ESPACE);
2021− tnfa->transitions = transitions;
2022− tnfa->num_transitions = add;
2023−
2024− DPRINT(("Converting to TNFA:\n"));
2025− errcode = tre_ast_to_tnfa(tree, transitions, counts, offs);
2026− if (errcode != REG_OK)
2027− ERROR_EXIT(errcode);
2028−
2029− /* If in eight bit mode, compute a table of characters that can be the
2030− first character of a match. */
2031− tnfa->first_char = -1;
2032− if (TRE_MB_CUR_MAX == 1 && !tmp_ast_l->nullable)
2033− {
2034− int count = 0;
2035− tre_cint_t k;
2036− DPRINT(("Characters that can start a match:"));
2037− tnfa->firstpos_chars = xcalloc(256, sizeof(char));
2038− if (tnfa->firstpos_chars == NULL)
2039− ERROR_EXIT(REG_ESPACE);
2040− for (p = tree->firstpos; p->position >= 0; p++)
2041− {
2042− tre_tnfa_transition_t *j = transitions + offs[p->position];
2043− while (j->state != NULL)
2044− {
2045− for (k = j->code_min; k <= j->code_max && k < 256; k++)
2046− {
2047− DPRINT((" %d", k));
2048− tnfa->firstpos_chars[k] = 1;
2049− count++;
2050− }
2051− j++;
2052− }
2053− }
2054− DPRINT(("\n"));
2055−#define TRE_OPTIMIZE_FIRST_CHAR 1
2056−#if TRE_OPTIMIZE_FIRST_CHAR
2057− if (count == 1)
2058− {
2059− for (k = 0; k < 256; k++)
2060− if (tnfa->firstpos_chars[k])
2061− {
2062− DPRINT(("first char must be %d\n", k));
2063− tnfa->first_char = k;
2064− xfree(tnfa->firstpos_chars);
2065− tnfa->firstpos_chars = NULL;
2066− break;
2067− }
2068− }
2069−#endif
2070−
2071− }
2072− else
2073− tnfa->firstpos_chars = NULL;
2074−
2075−
2076− p = tree->firstpos;
2077− i = 0;
2078− while (p->position >= 0)
2079− {
2080− i++;
2081−
2082−#ifdef TRE_DEBUG
2083− {
2084− int *tags;
2085− DPRINT(("initial: %d", p->position));
2086− tags = p->tags;
2087− if (tags != NULL)
2088− {
2089− if (*tags >= 0)
2090− DPRINT(("/"));
2091− while (*tags >= 0)
2092− {
2093− DPRINT(("%d", *tags));
2094− tags++;
2095− if (*tags >= 0)
2096− DPRINT((","));
2097− }
2098− }
2099− DPRINT((", assert %d", p->assertions));
2100− if (p->params)
2101− {
2102− DPRINT((", "));
2103− tre_print_params(p->params);
2104− }
2105− DPRINT(("\n"));
2106− }
2107−#endif /* TRE_DEBUG */
2108−
2109− p++;
2110− }
2111−
2112− initial = xcalloc((unsigned)i + 1, sizeof(tre_tnfa_transition_t));
2113− if (initial == NULL)
2114− ERROR_EXIT(REG_ESPACE);
2115− tnfa->initial = initial;
2116−
2117− i = 0;
2118− for (p = tree->firstpos; p->position >= 0; p++)
2119− {
2120− initial[i].state = transitions + offs[p->position];
2121− initial[i].state_id = p->position;
2122− initial[i].tags = NULL;
2123− /* Copy the arrays p->tags, and p->params, they are allocated
2124− from a tre_mem object. */
2125− if (p->tags)
2126− {
2127− int j;
2128− for (j = 0; p->tags[j] >= 0; j++);
2129− initial[i].tags = xmalloc(sizeof(*p->tags) * (j + 1));
2130− if (!initial[i].tags)
2131− ERROR_EXIT(REG_ESPACE);
2132− memcpy(initial[i].tags, p->tags, sizeof(*p->tags) * (j + 1));
2133− }
2134− initial[i].params = NULL;
2135− if (p->params)
2136− {
2137− initial[i].params = xmalloc(sizeof(*p->params) * TRE_PARAM_LAST);
2138− if (!initial[i].params)
2139− ERROR_EXIT(REG_ESPACE);
2140− memcpy(initial[i].params, p->params,
2141− sizeof(*p->params) * TRE_PARAM_LAST);
2142− }
2143− initial[i].assertions = p->assertions;
2144− i++;
2145− }
2146− initial[i].state = NULL;
2147−
2148− tnfa->num_transitions = add;
2149− tnfa->final = transitions + offs[tree->lastpos[0].position];
2150− tnfa->num_states = parse_ctx.position;
2151− tnfa->cflags = cflags;
2152−
2153− DPRINT(("final state %p\n", (void *)tnfa->final));
2154−
2155− tre_mem_destroy(mem);
2156− tre_stack_destroy(stack);
2157− xfree(counts);
2158− xfree(offs);
2159−
2160− preg->TRE_REGEX_T_FIELD = (void *)tnfa;
2161− return REG_OK;
2162−
2163− error_exit:
2164− /* Free everything that was allocated and return the error code. */
2165− tre_mem_destroy(mem);
2166− if (stack != NULL)
2167− tre_stack_destroy(stack);
2168− if (counts != NULL)
2169− xfree(counts);
2170− if (offs != NULL)
2171− xfree(offs);
2172− preg->TRE_REGEX_T_FIELD = (void *)tnfa;
2173− tre_free(preg);
2174− return errcode;
2175−}
2176−
2177−
2178−
2179−
2180−void
2181−tre_free(regex_t *preg)
2182−{
2183− tre_tnfa_t *tnfa;
2184− unsigned int i;
2185− tre_tnfa_transition_t *trans;
2186−
2187− tnfa = (void *)preg->TRE_REGEX_T_FIELD;
2188− if (!tnfa)
2189− return;
2190−
2191− for (i = 0; i < tnfa->num_transitions; i++)
2192− if (tnfa->transitions[i].state)
2193− {
2194− if (tnfa->transitions[i].tags)
2195− xfree(tnfa->transitions[i].tags);
2196− if (tnfa->transitions[i].neg_classes)
2197− xfree(tnfa->transitions[i].neg_classes);
2198− if (tnfa->transitions[i].params)
2199− xfree(tnfa->transitions[i].params);
2200− }
2201− if (tnfa->transitions)
2202− xfree(tnfa->transitions);
2203−
2204− if (tnfa->initial)
2205− {
2206− for (trans = tnfa->initial; trans->state; trans++)
2207− {
2208− if (trans->tags)
2209− xfree(trans->tags);
2210− if (trans->params)
2211− xfree(trans->params);
2212− }
2213− xfree(tnfa->initial);
2214− }
2215−
2216− if (tnfa->submatch_data)
2217− {
2218− for (i = 0; i < tnfa->num_submatches; i++)
2219− if (tnfa->submatch_data[i].parents)
2220− xfree(tnfa->submatch_data[i].parents);
2221− xfree(tnfa->submatch_data);
2222− }
2223−
2224− if (tnfa->tag_directions)
2225− xfree(tnfa->tag_directions);
2226− if (tnfa->firstpos_chars)
2227− xfree(tnfa->firstpos_chars);
2228− if (tnfa->minimal_tags)
2229− xfree(tnfa->minimal_tags);
2230− xfree(tnfa);
2231−}
2232−
2233−char *
2234−tre_version(void)
2235−{
2236− static char str[256];
2237− char *version;
2238−
2239− if (str[0] == 0)
2240− {
2241− (void) tre_config(TRE_CONFIG_VERSION, &version);
2242− (void) snprintf(str, sizeof(str), "TRE %s (BSD)", version);
2243− }
2244− return str;
2245−}
2246−
2247−int
2248−tre_config(int query, void *result)
2249−{
2250− int *int_result = result;
2251− const char **string_result = result;
2252−
2253− switch (query)
2254− {
2255− case TRE_CONFIG_APPROX:
2256−#ifdef TRE_APPROX
2257− *int_result = 1;
2258−#else /* !TRE_APPROX */
2259− *int_result = 0;
2260−#endif /* !TRE_APPROX */
2261− return REG_OK;
2262−
2263− case TRE_CONFIG_WCHAR:
2264−#ifdef TRE_WCHAR
2265− *int_result = 1;
2266−#else /* !TRE_WCHAR */
2267− *int_result = 0;
2268−#endif /* !TRE_WCHAR */
2269− return REG_OK;
2270−
2271− case TRE_CONFIG_MULTIBYTE:
2272−#ifdef TRE_MULTIBYTE
2273− *int_result = 1;
2274−#else /* !TRE_MULTIBYTE */
2275− *int_result = 0;
2276−#endif /* !TRE_MULTIBYTE */
2277− return REG_OK;
2278−
2279− case TRE_CONFIG_SYSTEM_ABI:
2280−#ifdef TRE_CONFIG_SYSTEM_ABI
2281− *int_result = 1;
2282−#else /* !TRE_CONFIG_SYSTEM_ABI */
2283− *int_result = 0;
2284−#endif /* !TRE_CONFIG_SYSTEM_ABI */
2285− return REG_OK;
2286−
2287− case TRE_CONFIG_VERSION:
2288− *string_result = TRE_VERSION;
2289− return REG_OK;
2290− }
2291−
2292− return REG_NOMATCH;
2293−}
2294−
2295−
2296−/* EOF */
src/core/regex/tre-compile.h+0−27
@@ -1,27 +0,0 @@
1−/*
2− tre-compile.h: Regex compilation definitions
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−
10−#ifndef TRE_COMPILE_H
11−#define TRE_COMPILE_H 1
12−
13−typedef struct {
14− int position;
15− int code_min;
16− int code_max;
17− int *tags;
18− int assertions;
19− tre_ctype_t class;
20− tre_ctype_t *neg_classes;
21− int backref;
22− int *params;
23−} tre_pos_and_tags_t;
24−
25−#endif /* TRE_COMPILE_H */
26−
27−/* EOF */
src/core/regex/tre-config.h+0−52
@@ -1,52 +0,0 @@
1−/* tre-config.h. This file defines all compile time definitions
2− that are needed in `regex.h' for Win32. */
3−
4−/* Define to 1 if you have `alloca', as a function or macro. */
5−#define HAVE_ALLOCA 1
6−
7−/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
8− */
9−#define HAVE_ALLOCA_H 1
10−
11−/* Define to 1 if you have the <libutf8.h> header file. */
12−/* #undef HAVE_LIBUTF8_H */
13−
14−/* Define to 1 if the system has the type `reg_errcode_t'. */
15−/* #undef HAVE_REG_ERRCODE_T */
16−
17−/* Define to 1 if you have the <sys/types.h> header file. */
18−#define HAVE_SYS_TYPES_H 1
19−
20−/* Define to 1 if you have the <wchar.h> header file. */
21−#define HAVE_WCHAR_H 1
22−
23−/* Define if you want to enable approximate matching functionality. */
24−#define TRE_APPROX 1
25−
26−/* Define to enable multibyte character set support. */
27−/* #define TRE_MULTIBYTE 1 */
28−
29−/* Define to the absolute path to the system regex.h */
30−/* #undef TRE_SYSTEM_REGEX_H_PATH */
31−
32−/* Define if you want TRE to use alloca() instead of malloc() when allocating
33− memory needed for regexec operations. */
34−#define TRE_USE_ALLOCA 1
35−
36−/* Define to include the system regex.h from TRE regex.h */
37−/* #undef TRE_USE_SYSTEM_REGEX_H */
38−
39−/* Define to enable wide character (wchar_t) support. */
40−/* #define TRE_WCHAR 1 */
41−
42−/* TRE version string. */
43−#define TRE_VERSION "@TRE_VERSION@"
44−
45−/* TRE version level 1. */
46−#define TRE_VERSION_1 @TRE_VERSION_1@
47−
48−/* TRE version level 2. */
49−#define TRE_VERSION_2 @TRE_VERSION_2@
50−
51−/* TRE version level 3. */
52−#define TRE_VERSION_3 @TRE_VERSION_3@
src/core/regex/tre-filter.c+0−73
@@ -1,73 +0,0 @@
1−/*
2− tre-filter.c: Histogram filter to quickly find regexp match candidates
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−/* The idea of this filter is quite simple. First, let's assume the
10− search pattern is a simple string. In order for a substring of a
11− longer string to match the search pattern, it must have the same
12− numbers of different characters as the pattern, and those
13− characters must occur in the same order as they occur in pattern. */
14−
15−#ifdef HAVE_CONFIG_H
16−#include <config.h>
17−#endif /* HAVE_CONFIG_H */
18−#include <stdio.h>
19−#include "tre-internal.h"
20−#include "tre-filter.h"
21−
22−int
23−tre_filter_find(const unsigned char *str, size_t len, tre_filter_t *filter)
24−{
25− unsigned short counts[256];
26− unsigned int i;
27− unsigned int window_len = filter->window_len;
28− tre_filter_profile_t *profile = filter->profile;
29− const unsigned char *str_orig = str;
30−
31− DPRINT(("tre_filter_find: %.*s\n", len, str));
32−
33− for (i = 0; i < elementsof(counts); i++)
34− counts[i] = 0;
35−
36− i = 0;
37− while (*str && i < window_len && i < len)
38− {
39− counts[*str]++;
40− i++;
41− str++;
42− len--;
43− }
44−
45− while (len > 0)
46− {
47− tre_filter_profile_t *p;
48− counts[*str]++;
49− counts[*(str - window_len)]--;
50−
51− p = profile;
52− while (p->ch)
53− {
54− if (counts[p->ch] < p->count)
55− break;
56− p++;
57− }
58− if (!p->ch)
59− {
60− DPRINT(("Found possible match at %d\n",
61− str - str_orig));
62− return (int)(str - str_orig); // 1.4.1.1 (ge) added cast to get rid of win64 warning
63− }
64− else
65− {
66− DPRINT(("No match so far...\n"));
67− }
68− len--;
69− str++;
70− }
71− DPRINT(("This string cannot match.\n"));
72− return -1;
73−}
src/core/regex/tre-filter.h+0−19
@@ -1,19 +0,0 @@
1−
2−
3−
4−
5−typedef struct {
6− unsigned char ch;
7− unsigned char count;
8−} tre_filter_profile_t;
9−
10−typedef struct {
11− /* Length of the window where the character counts are kept. */
12− int window_len;
13− /* Required character counts table. */
14− tre_filter_profile_t *profile;
15−} tre_filter_t;
16−
17−
18−int
19−tre_filter_find(const unsigned char *str, size_t len, tre_filter_t *filter);
src/core/regex/tre-internal.h+0−287
@@ -1,287 +0,0 @@
1−/*
2− tre-internal.h - TRE internal definitions
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−#ifndef TRE_INTERNAL_H
10−#define TRE_INTERNAL_H 1
11−
12−#ifdef HAVE_WCHAR_H
13−#include <wchar.h>
14−#endif /* HAVE_WCHAR_H */
15−
16−#ifdef HAVE_WCTYPE_H
17−#include <wctype.h>
18−#endif /* !HAVE_WCTYPE_H */
19−
20−#include <ctype.h>
21−#include "tre.h"
22−
23−#ifdef TRE_DEBUG
24−#include <stdio.h>
25−#define DPRINT(msg) do {printf msg; fflush(stdout);} while(/*CONSTCOND*/0)
26−#else /* !TRE_DEBUG */
27−#define DPRINT(msg) do { } while(/*CONSTCOND*/0)
28−#endif /* !TRE_DEBUG */
29−
30−#define elementsof(x) ( sizeof(x) / sizeof(x[0]) )
31−
32−#ifdef HAVE_MBRTOWC
33−#define tre_mbrtowc(pwc, s, n, ps) (mbrtowc((pwc), (s), (n), (ps)))
34−#else /* !HAVE_MBRTOWC */
35−#ifdef HAVE_MBTOWC
36−#define tre_mbrtowc(pwc, s, n, ps) (mbtowc((pwc), (s), (n)))
37−#endif /* HAVE_MBTOWC */
38−#endif /* !HAVE_MBRTOWC */
39−
40−#ifdef TRE_MULTIBYTE
41−#ifdef HAVE_MBSTATE_T
42−#define TRE_MBSTATE
43−#endif /* TRE_MULTIBYTE */
44−#endif /* HAVE_MBSTATE_T */
45−
46−/* Define the character types and functions. */
47−#ifdef TRE_WCHAR
48−
49−/* Wide characters. */
50−typedef wint_t tre_cint_t;
51−#define TRE_CHAR_MAX WCHAR_MAX
52−
53−#ifdef TRE_MULTIBYTE
54−#define TRE_MB_CUR_MAX MB_CUR_MAX
55−#else /* !TRE_MULTIBYTE */
56−#define TRE_MB_CUR_MAX 1
57−#endif /* !TRE_MULTIBYTE */
58−
59−#define tre_isalnum iswalnum
60−#define tre_isalpha iswalpha
61−#ifdef HAVE_ISWBLANK
62−#define tre_isblank iswblank
63−#endif /* HAVE_ISWBLANK */
64−#define tre_iscntrl iswcntrl
65−#define tre_isdigit iswdigit
66−#define tre_isgraph iswgraph
67−#define tre_islower iswlower
68−#define tre_isprint iswprint
69−#define tre_ispunct iswpunct
70−#define tre_isspace iswspace
71−#define tre_isupper iswupper
72−#define tre_isxdigit iswxdigit
73−
74−#define tre_tolower towlower
75−#define tre_toupper towupper
76−#define tre_strlen wcslen
77−
78−#else /* !TRE_WCHAR */
79−
80−/* 8 bit characters. */
81−typedef short tre_cint_t;
82−#define TRE_CHAR_MAX 255
83−#define TRE_MB_CUR_MAX 1
84−
85−#define tre_isalnum isalnum
86−#define tre_isalpha isalpha
87−#ifdef HAVE_ISASCII
88−#define tre_isascii isascii
89−#endif /* HAVE_ISASCII */
90−#ifdef HAVE_ISBLANK
91−#define tre_isblank isblank
92−#endif /* HAVE_ISBLANK */
93−#define tre_iscntrl iscntrl
94−#define tre_isdigit isdigit
95−#define tre_isgraph isgraph
96−#define tre_islower islower
97−#define tre_isprint isprint
98−#define tre_ispunct ispunct
99−#define tre_isspace isspace
100−#define tre_isupper isupper
101−#define tre_isxdigit isxdigit
102−
103−#define tre_tolower(c) (tre_cint_t)(tolower(c))
104−#define tre_toupper(c) (tre_cint_t)(toupper(c))
105−#define tre_strlen(s) (strlen((const char*)s))
106−
107−#endif /* !TRE_WCHAR */
108−
109−#if defined(TRE_WCHAR) && defined(HAVE_ISWCTYPE) && defined(HAVE_WCTYPE)
110−#define TRE_USE_SYSTEM_WCTYPE 1
111−#endif
112−
113−#ifdef TRE_USE_SYSTEM_WCTYPE
114−/* Use system provided iswctype() and wctype(). */
115−typedef wctype_t tre_ctype_t;
116−#define tre_isctype iswctype
117−#define tre_ctype wctype
118−#else /* !TRE_USE_SYSTEM_WCTYPE */
119−/* Define our own versions of iswctype() and wctype(). */
120−typedef int (*tre_ctype_t)(tre_cint_t);
121−#define tre_isctype(c, type) ( (type)(c) )
122−tre_ctype_t tre_ctype(const char *name);
123−#endif /* !TRE_USE_SYSTEM_WCTYPE */
124−
125−typedef enum { STR_WIDE, STR_BYTE, STR_MBS, STR_USER } tre_str_type_t;
126−
127−/* Returns number of bytes to add to (char *)ptr to make it
128− properly aligned for the type. */
129−#define ALIGN(ptr, type) \
130− ((((long)ptr) % sizeof(type)) \
131− ? (sizeof(type) - (((long)ptr) % sizeof(type))) \
132− : 0)
133−
134−#undef MAX
135−#undef MIN
136−#define MAX(a, b) (((a) >= (b)) ? (a) : (b))
137−#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
138−
139−/* Define STRF to the correct printf formatter for strings. */
140−#ifdef TRE_WCHAR
141−#define STRF "ls"
142−#else /* !TRE_WCHAR */
143−#define STRF "s"
144−#endif /* !TRE_WCHAR */
145−
146−/* TNFA transition type. A TNFA state is an array of transitions,
147− the terminator is a transition with NULL `state'. */
148−typedef struct tnfa_transition tre_tnfa_transition_t;
149−
150−struct tnfa_transition {
151− /* Range of accepted characters. */
152− tre_cint_t code_min;
153− tre_cint_t code_max;
154− /* Pointer to the destination state. */
155− tre_tnfa_transition_t *state;
156− /* ID number of the destination state. */
157− int state_id;
158− /* -1 terminated array of tags (or NULL). */
159− int *tags;
160− /* Matching parameters settings (or NULL). */
161− int *params;
162− /* Assertion bitmap. */
163− int assertions;
164− /* Assertion parameters. */
165− union {
166− /* Character class assertion. */
167− tre_ctype_t class;
168− /* Back reference assertion. */
169− int backref;
170− } u;
171− /* Negative character class assertions. */
172− tre_ctype_t *neg_classes;
173−};
174−
175−
176−/* Assertions. */
177−#define ASSERT_AT_BOL 1 /* Beginning of line. */
178−#define ASSERT_AT_EOL 2 /* End of line. */
179−#define ASSERT_CHAR_CLASS 4 /* Character class in `class'. */
180−#define ASSERT_CHAR_CLASS_NEG 8 /* Character classes in `neg_classes'. */
181−#define ASSERT_AT_BOW 16 /* Beginning of word. */
182−#define ASSERT_AT_EOW 32 /* End of word. */
183−#define ASSERT_AT_WB 64 /* Word boundary. */
184−#define ASSERT_AT_WB_NEG 128 /* Not a word boundary. */
185−#define ASSERT_BACKREF 256 /* A back reference in `backref'. */
186−#define ASSERT_LAST 256
187−
188−/* Tag directions. */
189−typedef enum {
190− TRE_TAG_MINIMIZE = 0,
191− TRE_TAG_MAXIMIZE = 1
192−} tre_tag_direction_t;
193−
194−/* Parameters that can be changed dynamically while matching. */
195−typedef enum {
196− TRE_PARAM_COST_INS = 0,
197− TRE_PARAM_COST_DEL = 1,
198− TRE_PARAM_COST_SUBST = 2,
199− TRE_PARAM_COST_MAX = 3,
200− TRE_PARAM_MAX_INS = 4,
201− TRE_PARAM_MAX_DEL = 5,
202− TRE_PARAM_MAX_SUBST = 6,
203− TRE_PARAM_MAX_ERR = 7,
204− TRE_PARAM_DEPTH = 8,
205− TRE_PARAM_LAST = 9
206−} tre_param_t;
207−
208−/* Unset matching parameter */
209−#define TRE_PARAM_UNSET -1
210−
211−/* Signifies the default matching parameter value. */
212−#define TRE_PARAM_DEFAULT -2
213−
214−/* Instructions to compute submatch register values from tag values
215− after a successful match. */
216−struct tre_submatch_data {
217− /* Tag that gives the value for rm_so (submatch start offset). */
218− int so_tag;
219− /* Tag that gives the value for rm_eo (submatch end offset). */
220− int eo_tag;
221− /* List of submatches this submatch is contained in. */
222− int *parents;
223−};
224−
225−typedef struct tre_submatch_data tre_submatch_data_t;
226−
227−
228−/* TNFA definition. */
229−typedef struct tnfa tre_tnfa_t;
230−
231−struct tnfa {
232− tre_tnfa_transition_t *transitions;
233− unsigned int num_transitions;
234− tre_tnfa_transition_t *initial;
235− tre_tnfa_transition_t *final;
236− tre_submatch_data_t *submatch_data;
237− char *firstpos_chars;
238− int first_char;
239− unsigned int num_submatches;
240− tre_tag_direction_t *tag_directions;
241− int *minimal_tags;
242− int num_tags;
243− int num_minimals;
244− int end_tag;
245− int num_states;
246− int cflags;
247− int have_backrefs;
248− int have_approx;
249− int params_depth;
250−};
251−
252−int
253−tre_compile(regex_t *preg, const tre_char_t *regex, size_t n, int cflags);
254−
255−void
256−tre_free(regex_t *preg);
257−
258−void
259−tre_fill_pmatch(size_t nmatch, regmatch_t pmatch[], int cflags,
260− const tre_tnfa_t *tnfa, int *tags, int match_eo);
261−
262−reg_errcode_t
263−tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string, int len,
264− tre_str_type_t type, int *match_tags, int eflags,
265− int *match_end_ofs);
266−
267−reg_errcode_t
268−tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string, int len,
269− tre_str_type_t type, int *match_tags, int eflags,
270− int *match_end_ofs);
271−
272−reg_errcode_t
273−tre_tnfa_run_backtrack(const tre_tnfa_t *tnfa, const void *string,
274− int len, tre_str_type_t type, int *match_tags,
275− int eflags, int *match_end_ofs);
276−
277−#ifdef TRE_APPROX
278−reg_errcode_t
279−tre_tnfa_run_approx(const tre_tnfa_t *tnfa, const void *string, int len,
280− tre_str_type_t type, int *match_tags,
281− regamatch_t *match, regaparams_t params,
282− int eflags, int *match_end_ofs);
283−#endif /* TRE_APPROX */
284−
285−#endif /* TRE_INTERNAL_H */
286−
287−/* EOF */
src/core/regex/tre-match-approx.c+0−812
@@ -1,812 +0,0 @@
1−/*
2− tre-match-approx.c - TRE approximate regex matching engine
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−#ifdef HAVE_CONFIG_H
10−#include <config.h>
11−#endif /* HAVE_CONFIG_H */
12−
13−/* AIX requires this to be the first thing in the file. */
14−#ifdef TRE_USE_ALLOCA
15−#ifndef __GNUC__
16−# if HAVE_ALLOCA_H
17−# include <alloca.h>
18−# else
19−# ifdef _AIX
20− #pragma alloca
21−# else
22−# ifndef alloca /* predefined by HP cc +Olibcalls */
23−char *alloca ();
24−# endif
25−# endif
26−# endif
27−#endif
28−#endif /* TRE_USE_ALLOCA */
29−
30−#define __USE_STRING_INLINES
31−#undef __NO_INLINE__
32−
33−#include <assert.h>
34−#include <stdlib.h>
35−#include <string.h>
36−#include <limits.h>
37−#ifdef HAVE_WCHAR_H
38−#include <wchar.h>
39−#endif /* HAVE_WCHAR_H */
40−#ifdef HAVE_WCTYPE_H
41−#include <wctype.h>
42−#endif /* HAVE_WCTYPE_H */
43−#ifndef TRE_WCHAR
44−#include <ctype.h>
45−#endif /* !TRE_WCHAR */
46−#ifdef HAVE_MALLOC_H
47−#include <malloc.h>
48−#endif /* HAVE_MALLOC_H */
49−
50−#include "tre-internal.h"
51−#include "tre-match-utils.h"
52−#include "tre.h"
53−#include "xmalloc.h"
54−
55−#define TRE_M_COST 0
56−#define TRE_M_NUM_INS 1
57−#define TRE_M_NUM_DEL 2
58−#define TRE_M_NUM_SUBST 3
59−#define TRE_M_NUM_ERR 4
60−#define TRE_M_LAST 5
61−
62−#define TRE_M_MAX_DEPTH 3
63−
64−typedef struct {
65− /* State in the TNFA transition table. */
66− tre_tnfa_transition_t *state;
67− /* Position in input string. */
68− int pos;
69− /* Tag values. */
70− int *tags;
71− /* Matching parameters. */
72− regaparams_t params;
73− /* Nesting depth of parameters. This is used as an index in
74− the `costs' array. */
75− int depth;
76− /* Costs and counter values for different parameter nesting depths. */
77− int costs[TRE_M_MAX_DEPTH + 1][TRE_M_LAST];
78−} tre_tnfa_approx_reach_t;
79−
80−
81−#ifdef TRE_DEBUG
82−/* Prints the `reach' array in a readable fashion with DPRINT. */
83−static void
84−tre_print_reach(const tre_tnfa_t *tnfa, tre_tnfa_approx_reach_t *reach,
85− int pos, int num_tags)
86−{
87− int id;
88−
89− /* Print each state on one line. */
90− DPRINT((" reach:\n"));
91− for (id = 0; id < tnfa->num_states; id++)
92− {
93− int i, j;
94− if (reach[id].pos < pos)
95− continue; /* Not reached. */
96− DPRINT((" %03d, costs ", id));
97− for (i = 0; i <= reach[id].depth; i++)
98− {
99− DPRINT(("["));
100− for (j = 0; j < TRE_M_LAST; j++)
101− {
102− DPRINT(("%2d", reach[id].costs[i][j]));
103− if (j + 1 < TRE_M_LAST)
104− DPRINT((","));
105− }
106− DPRINT(("]"));
107− if (i + 1 <= reach[id].depth)
108− DPRINT((", "));
109− }
110− DPRINT(("\n tags "));
111− for (i = 0; i < num_tags; i++)
112− {
113− DPRINT(("%02d", reach[id].tags[i]));
114− if (i + 1 < num_tags)
115− DPRINT((","));
116− }
117− DPRINT(("\n"));
118− }
119− DPRINT(("\n"));
120−}
121−#endif /* TRE_DEBUG */
122−
123−
124−/* Sets the matching parameters in `reach' to the ones defined in the `pa'
125− array. If `pa' specifies default values, they are taken from
126− `default_params'. */
127−inline static void
128−tre_set_params(tre_tnfa_approx_reach_t *reach,
129− int *pa, regaparams_t default_params)
130−{
131− int value;
132−
133− /* If depth is increased reset costs and counters to zero for the
134− new levels. */
135− value = pa[TRE_PARAM_DEPTH];
136− assert(value <= TRE_M_MAX_DEPTH);
137− if (value > reach->depth)
138− {
139− int i, j;
140− for (i = reach->depth + 1; i <= value; i++)
141− for (j = 0; j < TRE_M_LAST; j++)
142− reach->costs[i][j] = 0;
143− }
144− reach->depth = value;
145−
146− /* Set insert cost. */
147− value = pa[TRE_PARAM_COST_INS];
148− if (value == TRE_PARAM_DEFAULT)
149− reach->params.cost_ins = default_params.cost_ins;
150− else if (value != TRE_PARAM_UNSET)
151− reach->params.cost_ins = value;
152−
153− /* Set delete cost. */
154− value = pa[TRE_PARAM_COST_DEL];
155− if (value == TRE_PARAM_DEFAULT)
156− reach->params.cost_del = default_params.cost_del;
157− else if (value != TRE_PARAM_UNSET)
158− reach->params.cost_del = value;
159−
160− /* Set substitute cost. */
161− value = pa[TRE_PARAM_COST_SUBST];
162− if (value == TRE_PARAM_DEFAULT)
163− reach->params.cost_subst = default_params.cost_subst;
164− else
165− reach->params.cost_subst = value;
166−
167− /* Set maximum cost. */
168− value = pa[TRE_PARAM_COST_MAX];
169− if (value == TRE_PARAM_DEFAULT)
170− reach->params.max_cost = default_params.max_cost;
171− else if (value != TRE_PARAM_UNSET)
172− reach->params.max_cost = value;
173−
174− /* Set maximum inserts. */
175− value = pa[TRE_PARAM_MAX_INS];
176− if (value == TRE_PARAM_DEFAULT)
177− reach->params.max_ins = default_params.max_ins;
178− else if (value != TRE_PARAM_UNSET)
179− reach->params.max_ins = value;
180−
181− /* Set maximum deletes. */
182− value = pa[TRE_PARAM_MAX_DEL];
183− if (value == TRE_PARAM_DEFAULT)
184− reach->params.max_del = default_params.max_del;
185− else if (value != TRE_PARAM_UNSET)
186− reach->params.max_del = value;
187−
188− /* Set maximum substitutes. */
189− value = pa[TRE_PARAM_MAX_SUBST];
190− if (value == TRE_PARAM_DEFAULT)
191− reach->params.max_subst = default_params.max_subst;
192− else if (value != TRE_PARAM_UNSET)
193− reach->params.max_subst = value;
194−
195− /* Set maximum number of errors. */
196− value = pa[TRE_PARAM_MAX_ERR];
197− if (value == TRE_PARAM_DEFAULT)
198− reach->params.max_err = default_params.max_err;
199− else if (value != TRE_PARAM_UNSET)
200− reach->params.max_err = value;
201−}
202−
203−reg_errcode_t
204−tre_tnfa_run_approx(const tre_tnfa_t *tnfa, const void *string, int len,
205− tre_str_type_t type, int *match_tags,
206− regamatch_t *match, regaparams_t default_params,
207− int eflags, int *match_end_ofs)
208−{
209− /* State variables required by GET_NEXT_WCHAR. */
210− tre_char_t prev_c = 0, next_c = 0;
211− const char *str_byte = string;
212− int pos = -1;
213− unsigned int pos_add_next = 1;
214−#ifdef TRE_WCHAR
215− const wchar_t *str_wide = string;
216−#ifdef TRE_MBSTATE
217− mbstate_t mbstate;
218−#endif /* !TRE_WCHAR */
219−#endif /* TRE_WCHAR */
220− int reg_notbol = eflags & REG_NOTBOL;
221− int reg_noteol = eflags & REG_NOTEOL;
222− int reg_newline = tnfa->cflags & REG_NEWLINE;
223− int str_user_end = 0;
224−
225− int prev_pos;
226−
227− /* Number of tags. */
228− int num_tags;
229− /* The reach tables. */
230− tre_tnfa_approx_reach_t *reach, *reach_next;
231− /* Tag array for temporary use. */
232− int *tmp_tags;
233−
234− /* End offset of best match so far, or -1 if no match found yet. */
235− int match_eo = -1;
236− /* Costs of the match. */
237− int match_costs[TRE_M_LAST];
238−
239− /* Space for temporary data required for matching. */
240− unsigned char *buf;
241−
242− int i, id;
243−
244− if (!match_tags)
245− num_tags = 0;
246− else
247− num_tags = tnfa->num_tags;
248−
249−#ifdef TRE_MBSTATE
250− memset(&mbstate, '\0', sizeof(mbstate));
251−#endif /* TRE_MBSTATE */
252−
253− DPRINT(("tre_tnfa_run_approx, input type %d, len %d, eflags %d, "
254− "match_tags %p\n",
255− type, len, eflags,
256− match_tags));
257− DPRINT(("max cost %d, ins %d, del %d, subst %d\n",
258− default_params.max_cost,
259− default_params.cost_ins,
260− default_params.cost_del,
261− default_params.cost_subst));
262−
263− /* Allocate memory for temporary data required for matching. This needs to
264− be done for every matching operation to be thread safe. This allocates
265− everything in a single large block from the stack frame using alloca()
266− or with malloc() if alloca is unavailable. */
267− {
268− unsigned char *buf_cursor;
269− /* Space needed for one array of tags. */
270− int tag_bytes = sizeof(*tmp_tags) * num_tags;
271− /* Space needed for one reach table. */
272− int reach_bytes = sizeof(*reach_next) * tnfa->num_states;
273− /* Total space needed. */
274− int total_bytes = reach_bytes * 2 + (tnfa->num_states * 2 + 1 ) * tag_bytes;
275− /* Add some extra to make sure we can align the pointers. The multiplier
276− used here must be equal to the number of ALIGN calls below. */
277− total_bytes += (sizeof(long) - 1) * 3;
278−
279− /* Allocate the memory. */
280−#ifdef TRE_USE_ALLOCA
281− buf = alloca(total_bytes);
282−#else /* !TRE_USE_ALLOCA */
283− buf = xmalloc((unsigned)total_bytes);
284−#endif /* !TRE_USE_ALLOCA */
285− if (!buf)
286− return REG_ESPACE;
287− memset(buf, 0, (size_t)total_bytes);
288−
289− /* Allocate `tmp_tags' from `buf'. */
290− tmp_tags = (void *)buf;
291− buf_cursor = buf + tag_bytes;
292− buf_cursor += ALIGN(buf_cursor, long);
293−
294− /* Allocate `reach' from `buf'. */
295− reach = (void *)buf_cursor;
296− buf_cursor += reach_bytes;
297− buf_cursor += ALIGN(buf_cursor, long);
298−
299− /* Allocate `reach_next' from `buf'. */
300− reach_next = (void *)buf_cursor;
301− buf_cursor += reach_bytes;
302− buf_cursor += ALIGN(buf_cursor, long);
303−
304− /* Allocate tag arrays for `reach' and `reach_next' from `buf'. */
305− for (i = 0; i < tnfa->num_states; i++)
306− {
307− reach[i].tags = (void *)buf_cursor;
308− buf_cursor += tag_bytes;
309− reach_next[i].tags = (void *)buf_cursor;
310− buf_cursor += tag_bytes;
311− }
312− assert(buf_cursor <= buf + total_bytes);
313− }
314−
315− for (i = 0; i < TRE_M_LAST; i++)
316− match_costs[i] = INT_MAX;
317−
318− /* Mark the reach arrays empty. */
319− for (i = 0; i < tnfa->num_states; i++)
320− reach[i].pos = reach_next[i].pos = -2;
321−
322− prev_pos = pos;
323− GET_NEXT_WCHAR();
324− pos = 0;
325−
326− while (/*CONSTCOND*/1)
327− {
328− DPRINT(("%03d:%2lc/%05d\n", pos, (tre_cint_t)next_c, (int)next_c));
329−
330− /* Add initial states to `reach_next' if an exact match has not yet
331− been found. */
332− if (match_costs[TRE_M_COST] > 0)
333− {
334− tre_tnfa_transition_t *trans;
335− DPRINT((" init"));
336− for (trans = tnfa->initial; trans->state; trans++)
337− {
338− int stateid = trans->state_id;
339−
340− /* If this state is not currently in `reach_next', add it
341− there. */
342− if (reach_next[stateid].pos < pos)
343− {
344− if (trans->assertions && CHECK_ASSERTIONS(trans->assertions))
345− {
346− /* Assertions failed, don't add this state. */
347− DPRINT((" !%d (assert)", stateid));
348− continue;
349− }
350− DPRINT((" %d", stateid));
351− reach_next[stateid].state = trans->state;
352− reach_next[stateid].pos = pos;
353−
354− /* Compute tag values after this transition. */
355− for (i = 0; i < num_tags; i++)
356− reach_next[stateid].tags[i] = -1;
357−
358− if (trans->tags)
359− for (i = 0; trans->tags[i] >= 0; i++)
360− if (trans->tags[i] < num_tags)
361− reach_next[stateid].tags[trans->tags[i]] = pos;
362−
363− /* Set the parameters, depth, and costs. */
364− reach_next[stateid].params = default_params;
365− reach_next[stateid].depth = 0;
366− for (i = 0; i < TRE_M_LAST; i++)
367− reach_next[stateid].costs[0][i] = 0;
368− if (trans->params)
369− tre_set_params(&reach_next[stateid], trans->params,
370− default_params);
371−
372− /* If this is the final state, mark the exact match. */
373− if (trans->state == tnfa->final)
374− {
375− match_eo = pos;
376− for (i = 0; i < num_tags; i++)
377− match_tags[i] = reach_next[stateid].tags[i];
378− for (i = 0; i < TRE_M_LAST; i++)
379− match_costs[i] = 0;
380− }
381− }
382− }
383− DPRINT(("\n"));
384− }
385−
386−
387− /* Handle inserts. This is done by pretending there's an epsilon
388− transition from each state in `reach' back to the same state.
389− We don't need to worry about the final state here; this will never
390− give a better match than what we already have. */
391− for (id = 0; id < tnfa->num_states; id++)
392− {
393− int depth;
394− int cost, cost0;
395−
396− if (reach[id].pos != prev_pos)
397− {
398− DPRINT((" insert: %d not reached\n", id));
399− continue; /* Not reached. */
400− }
401−
402− depth = reach[id].depth;
403−
404− /* Compute and check cost at current depth. */
405− cost = reach[id].costs[depth][TRE_M_COST];
406− if (reach[id].params.cost_ins != TRE_PARAM_UNSET)
407− cost += reach[id].params.cost_ins;
408− if (cost > reach[id].params.max_cost)
409− continue; /* Cost too large. */
410−
411− /* Check number of inserts at current depth. */
412− if (reach[id].costs[depth][TRE_M_NUM_INS] + 1
413− > reach[id].params.max_ins)
414− continue; /* Too many inserts. */
415−
416− /* Check total number of errors at current depth. */
417− if (reach[id].costs[depth][TRE_M_NUM_ERR] + 1
418− > reach[id].params.max_err)
419− continue; /* Too many errors. */
420−
421− /* Compute overall cost. */
422− cost0 = cost;
423− if (depth > 0)
424− {
425− cost0 = reach[id].costs[0][TRE_M_COST];
426− if (reach[id].params.cost_ins != TRE_PARAM_UNSET)
427− cost0 += reach[id].params.cost_ins;
428− else
429− cost0 += default_params.cost_ins;
430− }
431−
432− DPRINT((" insert: from %d to %d, cost %d: ", id, id,
433− reach[id].costs[depth][TRE_M_COST]));
434− if (reach_next[id].pos == pos
435− && (cost0 >= reach_next[id].costs[0][TRE_M_COST]))
436− {
437− DPRINT(("lose\n"));
438− continue;
439− }
440− DPRINT(("win\n"));
441−
442− /* Copy state, position, tags, parameters, and depth. */
443− reach_next[id].state = reach[id].state;
444− reach_next[id].pos = pos;
445− for (i = 0; i < num_tags; i++)
446− reach_next[id].tags[i] = reach[id].tags[i];
447− reach_next[id].params = reach[id].params;
448− reach_next[id].depth = reach[id].depth;
449−
450− /* Set the costs after this transition. */
451− memcpy(reach_next[id].costs, reach[id].costs,
452− sizeof(reach_next[id].costs[0][0])
453− * TRE_M_LAST * (depth + 1));
454− reach_next[id].costs[depth][TRE_M_COST] = cost;
455− reach_next[id].costs[depth][TRE_M_NUM_INS]++;
456− reach_next[id].costs[depth][TRE_M_NUM_ERR]++;
457− if (depth > 0)
458− {
459− reach_next[id].costs[0][TRE_M_COST] = cost0;
460− reach_next[id].costs[0][TRE_M_NUM_INS]++;
461− reach_next[id].costs[0][TRE_M_NUM_ERR]++;
462− }
463−
464− }
465−
466−
467− /* Handle deletes. This is done by traversing through the whole TNFA
468− pretending that all transitions are epsilon transitions, until
469− no more states can be reached with better costs. */
470− {
471− /* XXX - dynamic ringbuffer size */
472− tre_tnfa_approx_reach_t *ringbuffer[512];
473− tre_tnfa_approx_reach_t **deque_start, **deque_end;
474−
475− deque_start = deque_end = ringbuffer;
476−
477− /* Add all states in `reach_next' to the deque. */
478− for (id = 0; id < tnfa->num_states; id++)
479− {
480− if (reach_next[id].pos != pos)
481− continue;
482− *deque_end = &reach_next[id];
483− deque_end++;
484− assert(deque_end != deque_start);
485− }
486−
487− /* Repeat until the deque is empty. */
488− while (deque_end != deque_start)
489− {
490− tre_tnfa_approx_reach_t *reach_p;
491− int depth;
492− int cost, cost0;
493− tre_tnfa_transition_t *trans;
494−
495− /* Pop the first item off the deque. */
496− reach_p = *deque_start;
497− id = reach_p - reach_next;
498− depth = reach_p->depth;
499−
500− /* Compute cost at current depth. */
501− cost = reach_p->costs[depth][TRE_M_COST];
502− if (reach_p->params.cost_del != TRE_PARAM_UNSET)
503− cost += reach_p->params.cost_del;
504−
505− /* Check cost, number of deletes, and total number of errors
506− at current depth. */
507− if (cost > reach_p->params.max_cost
508− || (reach_p->costs[depth][TRE_M_NUM_DEL] + 1
509− > reach_p->params.max_del)
510− || (reach_p->costs[depth][TRE_M_NUM_ERR] + 1
511− > reach_p->params.max_err))
512− {
513− /* Too many errors or cost too large. */
514− DPRINT((" delete: from %03d: cost too large\n", id));
515− deque_start++;
516− if (deque_start >= (ringbuffer + 512))
517− deque_start = ringbuffer;
518− continue;
519− }
520−
521− /* Compute overall cost. */
522− cost0 = cost;
523− if (depth > 0)
524− {
525− cost0 = reach_p->costs[0][TRE_M_COST];
526− if (reach_p->params.cost_del != TRE_PARAM_UNSET)
527− cost0 += reach_p->params.cost_del;
528− else
529− cost0 += default_params.cost_del;
530− }
531−
532− for (trans = reach_p->state; trans->state; trans++)
533− {
534− int dest_id = trans->state_id;
535− DPRINT((" delete: from %03d to %03d, cost %d (%d): ",
536− id, dest_id, cost0, reach_p->params.max_cost));
537−
538− if (trans->assertions && CHECK_ASSERTIONS(trans->assertions))
539− {
540− DPRINT(("assertion failed\n"));
541− continue;
542− }
543−
544− /* Compute tag values after this transition. */
545− for (i = 0; i < num_tags; i++)
546− tmp_tags[i] = reach_p->tags[i];
547− if (trans->tags)
548− for (i = 0; trans->tags[i] >= 0; i++)
549− if (trans->tags[i] < num_tags)
550− tmp_tags[trans->tags[i]] = pos;
551−
552− /* If another path has also reached this state, choose the one
553− with the smallest cost or best tags if costs are equal. */
554− if (reach_next[dest_id].pos == pos
555− && (cost0 > reach_next[dest_id].costs[0][TRE_M_COST]
556− || (cost0 == reach_next[dest_id].costs[0][TRE_M_COST]
557− && (!match_tags
558− || !tre_tag_order(num_tags,
559− tnfa->tag_directions,
560− tmp_tags,
561− reach_next[dest_id].tags)))))
562− {
563− DPRINT(("lose, cost0 %d, have %d\n",
564− cost0, reach_next[dest_id].costs[0][TRE_M_COST]));
565− continue;
566− }
567− DPRINT(("win\n"));
568−
569− /* Set state, position, tags, parameters, depth, and costs. */
570− reach_next[dest_id].state = trans->state;
571− reach_next[dest_id].pos = pos;
572− for (i = 0; i < num_tags; i++)
573− reach_next[dest_id].tags[i] = tmp_tags[i];
574−
575− reach_next[dest_id].params = reach_p->params;
576− if (trans->params)
577− tre_set_params(&reach_next[dest_id], trans->params,
578− default_params);
579−
580− reach_next[dest_id].depth = reach_p->depth;
581− memcpy(&reach_next[dest_id].costs,
582− reach_p->costs,
583− sizeof(reach_p->costs[0][0])
584− * TRE_M_LAST * (depth + 1));
585− reach_next[dest_id].costs[depth][TRE_M_COST] = cost;
586− reach_next[dest_id].costs[depth][TRE_M_NUM_DEL]++;
587− reach_next[dest_id].costs[depth][TRE_M_NUM_ERR]++;
588− if (depth > 0)
589− {
590− reach_next[dest_id].costs[0][TRE_M_COST] = cost0;
591− reach_next[dest_id].costs[0][TRE_M_NUM_DEL]++;
592− reach_next[dest_id].costs[0][TRE_M_NUM_ERR]++;
593− }
594−
595− if (trans->state == tnfa->final
596− && (match_eo < 0
597− || match_costs[TRE_M_COST] > cost0
598− || (match_costs[TRE_M_COST] == cost0
599− && (num_tags > 0
600− && tmp_tags[0] <= match_tags[0]))))
601− {
602− DPRINT((" setting new match at %d, cost %d\n",
603− pos, cost0));
604− match_eo = pos;
605− memcpy(match_costs, reach_next[dest_id].costs[0],
606− sizeof(match_costs[0]) * TRE_M_LAST);
607− for (i = 0; i < num_tags; i++)
608− match_tags[i] = tmp_tags[i];
609− }
610−
611− /* Add to the end of the deque. */
612− *deque_end = &reach_next[dest_id];
613− deque_end++;
614− if (deque_end >= (ringbuffer + 512))
615− deque_end = ringbuffer;
616− assert(deque_end != deque_start);
617− }
618− deque_start++;
619− if (deque_start >= (ringbuffer + 512))
620− deque_start = ringbuffer;
621− }
622−
623− }
624−
625−#ifdef TRE_DEBUG
626− tre_print_reach(tnfa, reach_next, pos, num_tags);
627−#endif /* TRE_DEBUG */
628−
629− /* Check for end of string. */
630− if (len < 0)
631− {
632− if (type == STR_USER)
633− {
634− if (str_user_end)
635− break;
636− }
637− else if (next_c == L'\0')
638− break;
639− }
640− else
641− {
642− if (pos >= len)
643− break;
644− }
645−
646− prev_pos = pos;
647− GET_NEXT_WCHAR();
648−
649− /* Swap `reach' and `reach_next'. */
650− {
651− tre_tnfa_approx_reach_t *tmp;
652− tmp = reach;
653− reach = reach_next;
654− reach_next = tmp;
655− }
656−
657− /* Handle exact matches and substitutions. */
658− for (id = 0; id < tnfa->num_states; id++)
659− {
660− tre_tnfa_transition_t *trans;
661−
662− if (reach[id].pos < prev_pos)
663− continue; /* Not reached. */
664− for (trans = reach[id].state; trans->state; trans++)
665− {
666− int dest_id;
667− int depth;
668− int cost, cost0, err;
669−
670− if (trans->assertions
671− && (CHECK_ASSERTIONS(trans->assertions)
672− || CHECK_CHAR_CLASSES(trans, tnfa, eflags)))
673− {
674− DPRINT((" exact, from %d: assert failed\n", id));
675− continue;
676− }
677−
678− depth = reach[id].depth;
679− dest_id = trans->state_id;
680−
681− cost = reach[id].costs[depth][TRE_M_COST];
682− cost0 = reach[id].costs[0][TRE_M_COST];
683− err = 0;
684−
685− if (trans->code_min > (tre_cint_t)prev_c
686− || trans->code_max < (tre_cint_t)prev_c)
687− {
688− /* Handle substitutes. The required character was not in
689− the string, so match it in place of whatever was supposed
690− to be there and increase costs accordingly. */
691− err = 1;
692−
693− /* Compute and check cost at current depth. */
694− cost = reach[id].costs[depth][TRE_M_COST];
695− if (reach[id].params.cost_subst != TRE_PARAM_UNSET)
696− cost += reach[id].params.cost_subst;
697− if (cost > reach[id].params.max_cost)
698− continue; /* Cost too large. */
699−
700− /* Check number of substitutes at current depth. */
701− if (reach[id].costs[depth][TRE_M_NUM_SUBST] + 1
702− > reach[id].params.max_subst)
703− continue; /* Too many substitutes. */
704−
705− /* Check total number of errors at current depth. */
706− if (reach[id].costs[depth][TRE_M_NUM_ERR] + 1
707− > reach[id].params.max_err)
708− continue; /* Too many errors. */
709−
710− /* Compute overall cost. */
711− cost0 = cost;
712− if (depth > 0)
713− {
714− cost0 = reach[id].costs[0][TRE_M_COST];
715− if (reach[id].params.cost_subst != TRE_PARAM_UNSET)
716− cost0 += reach[id].params.cost_subst;
717− else
718− cost0 += default_params.cost_subst;
719− }
720− DPRINT((" subst, from %03d to %03d, cost %d: ",
721− id, dest_id, cost0));
722− }
723− else
724− DPRINT((" exact, from %03d to %03d, cost %d: ",
725− id, dest_id, cost0));
726−
727− /* Compute tag values after this transition. */
728− for (i = 0; i < num_tags; i++)
729− tmp_tags[i] = reach[id].tags[i];
730− if (trans->tags)
731− for (i = 0; trans->tags[i] >= 0; i++)
732− if (trans->tags[i] < num_tags)
733− tmp_tags[trans->tags[i]] = pos;
734−
735− /* If another path has also reached this state, choose the
736− one with the smallest cost or best tags if costs are equal. */
737− if (reach_next[dest_id].pos == pos
738− && (cost0 > reach_next[dest_id].costs[0][TRE_M_COST]
739− || (cost0 == reach_next[dest_id].costs[0][TRE_M_COST]
740− && !tre_tag_order(num_tags, tnfa->tag_directions,
741− tmp_tags,
742− reach_next[dest_id].tags))))
743− {
744− DPRINT(("lose\n"));
745− continue;
746− }
747− DPRINT(("win %d %d\n",
748− reach_next[dest_id].pos,
749− reach_next[dest_id].costs[0][TRE_M_COST]));
750−
751− /* Set state, position, tags, and depth. */
752− reach_next[dest_id].state = trans->state;
753− reach_next[dest_id].pos = pos;
754− for (i = 0; i < num_tags; i++)
755− reach_next[dest_id].tags[i] = tmp_tags[i];
756− reach_next[dest_id].depth = reach[id].depth;
757−
758− /* Set parameters. */
759− reach_next[dest_id].params = reach[id].params;
760− if (trans->params)
761− tre_set_params(&reach_next[dest_id], trans->params,
762− default_params);
763−
764− /* Set the costs after this transition. */
765− memcpy(&reach_next[dest_id].costs,
766− reach[id].costs,
767− sizeof(reach[id].costs[0][0])
768− * TRE_M_LAST * (depth + 1));
769− reach_next[dest_id].costs[depth][TRE_M_COST] = cost;
770− reach_next[dest_id].costs[depth][TRE_M_NUM_SUBST] += err;
771− reach_next[dest_id].costs[depth][TRE_M_NUM_ERR] += err;
772− if (depth > 0)
773− {
774− reach_next[dest_id].costs[0][TRE_M_COST] = cost0;
775− reach_next[dest_id].costs[0][TRE_M_NUM_SUBST] += err;
776− reach_next[dest_id].costs[0][TRE_M_NUM_ERR] += err;
777− }
778−
779− if (trans->state == tnfa->final
780− && (match_eo < 0
781− || cost0 < match_costs[TRE_M_COST]
782− || (cost0 == match_costs[TRE_M_COST]
783− && num_tags > 0 && tmp_tags[0] <= match_tags[0])))
784− {
785− DPRINT((" setting new match at %d, cost %d\n",
786− pos, cost0));
787− match_eo = pos;
788− for (i = 0; i < TRE_M_LAST; i++)
789− match_costs[i] = reach_next[dest_id].costs[0][i];
790− for (i = 0; i < num_tags; i++)
791− match_tags[i] = tmp_tags[i];
792− }
793− }
794− }
795− }
796−
797− DPRINT(("match end offset = %d, match cost = %d\n", match_eo,
798− match_costs[TRE_M_COST]));
799−
800−#ifndef TRE_USE_ALLOCA
801− if (buf)
802− xfree(buf);
803−#endif /* !TRE_USE_ALLOCA */
804−
805− match->cost = match_costs[TRE_M_COST];
806− match->num_ins = match_costs[TRE_M_NUM_INS];
807− match->num_del = match_costs[TRE_M_NUM_DEL];
808− match->num_subst = match_costs[TRE_M_NUM_SUBST];
809− *match_end_ofs = match_eo;
810−
811− return match_eo >= 0 ? REG_OK : REG_NOMATCH;
812−}
src/core/regex/tre-match-backtrack.c+0−666
@@ -1,666 +0,0 @@
1−/*
2− tre-match-backtrack.c - TRE backtracking regex matching engine
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−/*
10− This matcher is for regexps that use back referencing. Regexp matching
11− with back referencing is an NP-complete problem on the number of back
12− references. The easiest way to match them is to use a backtracking
13− routine which basically goes through all possible paths in the TNFA
14− and chooses the one which results in the best (leftmost and longest)
15− match. This can be spectacularly expensive and may run out of stack
16− space, but there really is no better known generic algorithm. Quoting
17− Henry Spencer from comp.compilers:
18− <URL: http://compilers.iecc.com/comparch/article/93-03-102>
19−
20− POSIX.2 REs require longest match, which is really exciting to
21− implement since the obsolete ("basic") variant also includes
22− \<digit>. I haven't found a better way of tackling this than doing
23− a preliminary match using a DFA (or simulation) on a modified RE
24− that just replicates subREs for \<digit>, and then doing a
25− backtracking match to determine whether the subRE matches were
26− right. This can be rather slow, but I console myself with the
27− thought that people who use \<digit> deserve very slow execution.
28− (Pun unintentional but very appropriate.)
29−
30−*/
31−
32−
33−#ifdef HAVE_CONFIG_H
34−#include <config.h>
35−#endif /* HAVE_CONFIG_H */
36−
37−#ifdef TRE_USE_ALLOCA
38−/* AIX requires this to be the first thing in the file. */
39−#ifndef __GNUC__
40−# if HAVE_ALLOCA_H
41−# include <alloca.h>
42−# else
43−# ifdef _AIX
44− #pragma alloca
45−# else
46−# ifndef alloca /* predefined by HP cc +Olibcalls */
47−char *alloca ();
48−# endif
49−# endif
50−# endif
51−#endif
52−#endif /* TRE_USE_ALLOCA */
53−
54−#include <assert.h>
55−#include <stdlib.h>
56−#include <string.h>
57−#ifdef HAVE_WCHAR_H
58−#include <wchar.h>
59−#endif /* HAVE_WCHAR_H */
60−#ifdef HAVE_WCTYPE_H
61−#include <wctype.h>
62−#endif /* HAVE_WCTYPE_H */
63−#ifndef TRE_WCHAR
64−#include <ctype.h>
65−#endif /* !TRE_WCHAR */
66−#ifdef HAVE_MALLOC_H
67−#include <malloc.h>
68−#endif /* HAVE_MALLOC_H */
69−
70−#include "tre-internal.h"
71−#include "tre-mem.h"
72−#include "tre-match-utils.h"
73−#include "tre.h"
74−#include "xmalloc.h"
75−
76−typedef struct {
77− int pos;
78− const char *str_byte;
79−#ifdef TRE_WCHAR
80− const wchar_t *str_wide;
81−#endif /* TRE_WCHAR */
82− tre_tnfa_transition_t *state;
83− int state_id;
84− int next_c;
85− int *tags;
86−#ifdef TRE_MBSTATE
87− mbstate_t mbstate;
88−#endif /* TRE_MBSTATE */
89−} tre_backtrack_item_t;
90−
91−typedef struct tre_backtrack_struct {
92− tre_backtrack_item_t item;
93− struct tre_backtrack_struct *prev;
94− struct tre_backtrack_struct *next;
95−} *tre_backtrack_t;
96−
97−#ifdef TRE_WCHAR
98−#define BT_STACK_WIDE_IN(_str_wide) stack->item.str_wide = (_str_wide)
99−#define BT_STACK_WIDE_OUT (str_wide) = stack->item.str_wide
100−#else /* !TRE_WCHAR */
101−#define BT_STACK_WIDE_IN(_str_wide)
102−#define BT_STACK_WIDE_OUT
103−#endif /* !TRE_WCHAR */
104−
105−#ifdef TRE_MBSTATE
106−#define BT_STACK_MBSTATE_IN stack->item.mbstate = (mbstate)
107−#define BT_STACK_MBSTATE_OUT (mbstate) = stack->item.mbstate
108−#else /* !TRE_MBSTATE */
109−#define BT_STACK_MBSTATE_IN
110−#define BT_STACK_MBSTATE_OUT
111−#endif /* !TRE_MBSTATE */
112−
113−
114−#ifdef TRE_USE_ALLOCA
115−#define tre_bt_mem_new tre_mem_newa
116−#define tre_bt_mem_alloc tre_mem_alloca
117−#define tre_bt_mem_destroy(obj) do { } while (0)
118−#else /* !TRE_USE_ALLOCA */
119−#define tre_bt_mem_new tre_mem_new
120−#define tre_bt_mem_alloc tre_mem_alloc
121−#define tre_bt_mem_destroy tre_mem_destroy
122−#endif /* !TRE_USE_ALLOCA */
123−
124−
125−#define BT_STACK_PUSH(_pos, _str_byte, _str_wide, _state, _state_id, _next_c, _tags, _mbstate) \
126− do \
127− { \
128− int i; \
129− if (!stack->next) \
130− { \
131− tre_backtrack_t s; \
132− s = tre_bt_mem_alloc(mem, sizeof(*s)); \
133− if (!s) \
134− { \
135− tre_bt_mem_destroy(mem); \
136− if (tags) \
137− xfree(tags); \
138− if (pmatch) \
139− xfree(pmatch); \
140− if (states_seen) \
141− xfree(states_seen); \
142− return REG_ESPACE; \
143− } \
144− s->prev = stack; \
145− s->next = NULL; \
146− s->item.tags = tre_bt_mem_alloc(mem, \
147− sizeof(*tags) * tnfa->num_tags); \
148− if (!s->item.tags) \
149− { \
150− tre_bt_mem_destroy(mem); \
151− if (tags) \
152− xfree(tags); \
153− if (pmatch) \
154− xfree(pmatch); \
155− if (states_seen) \
156− xfree(states_seen); \
157− return REG_ESPACE; \
158− } \
159− stack->next = s; \
160− stack = s; \
161− } \
162− else \
163− stack = stack->next; \
164− stack->item.pos = (_pos); \
165− stack->item.str_byte = (_str_byte); \
166− BT_STACK_WIDE_IN(_str_wide); \
167− stack->item.state = (_state); \
168− stack->item.state_id = (_state_id); \
169− stack->item.next_c = (_next_c); \
170− for (i = 0; i < tnfa->num_tags; i++) \
171− stack->item.tags[i] = (_tags)[i]; \
172− BT_STACK_MBSTATE_IN; \
173− } \
174− while (/*CONSTCOND*/0)
175−
176−#define BT_STACK_POP() \
177− do \
178− { \
179− int i; \
180− assert(stack->prev); \
181− pos = stack->item.pos; \
182− if (type == STR_USER) \
183− str_source->rewind(pos + pos_add_next, str_source->context); \
184− str_byte = stack->item.str_byte; \
185− BT_STACK_WIDE_OUT; \
186− state = stack->item.state; \
187− next_c = stack->item.next_c; \
188− for (i = 0; i < tnfa->num_tags; i++) \
189− tags[i] = stack->item.tags[i]; \
190− BT_STACK_MBSTATE_OUT; \
191− stack = stack->prev; \
192− } \
193− while (/*CONSTCOND*/0)
194−
195−#undef MIN
196−#define MIN(a, b) ((a) <= (b) ? (a) : (b))
197−
198−reg_errcode_t
199−tre_tnfa_run_backtrack(const tre_tnfa_t *tnfa, const void *string,
200− int len, tre_str_type_t type, int *match_tags,
201− int eflags, int *match_end_ofs)
202−{
203− /* State variables required by GET_NEXT_WCHAR. */
204− tre_char_t prev_c = 0, next_c = 0;
205− const char *str_byte = string;
206− int pos = 0;
207− unsigned int pos_add_next = 1;
208−#ifdef TRE_WCHAR
209− const wchar_t *str_wide = string;
210−#ifdef TRE_MBSTATE
211− mbstate_t mbstate;
212−#endif /* TRE_MBSTATE */
213−#endif /* TRE_WCHAR */
214− int reg_notbol = eflags & REG_NOTBOL;
215− int reg_noteol = eflags & REG_NOTEOL;
216− int reg_newline = tnfa->cflags & REG_NEWLINE;
217− int str_user_end = 0;
218−
219− /* These are used to remember the necessary values of the above
220− variables to return to the position where the current search
221− started from. */
222− int next_c_start;
223− const char *str_byte_start;
224− int pos_start = -1;
225−#ifdef TRE_WCHAR
226− const wchar_t *str_wide_start;
227−#endif /* TRE_WCHAR */
228−#ifdef TRE_MBSTATE
229− mbstate_t mbstate_start;
230−#endif /* TRE_MBSTATE */
231−
232− /* End offset of best match so far, or -1 if no match found yet. */
233− int match_eo = -1;
234− /* Tag arrays. */
235− int *next_tags, *tags = NULL;
236− /* Current TNFA state. */
237− tre_tnfa_transition_t *state;
238− int *states_seen = NULL;
239−
240− /* Memory allocator to for allocating the backtracking stack. */
241− tre_mem_t mem = tre_bt_mem_new();
242−
243− /* The backtracking stack. */
244− tre_backtrack_t stack;
245−
246− tre_tnfa_transition_t *trans_i;
247− regmatch_t *pmatch = NULL;
248− int ret;
249−
250−#ifdef TRE_MBSTATE
251− memset(&mbstate, '\0', sizeof(mbstate));
252−#endif /* TRE_MBSTATE */
253−
254− if (!mem)
255− return REG_ESPACE;
256− stack = tre_bt_mem_alloc(mem, sizeof(*stack));
257− if (!stack)
258− {
259− ret = REG_ESPACE;
260− goto error_exit;
261− }
262− stack->prev = NULL;
263− stack->next = NULL;
264−
265− DPRINT(("tnfa_execute_backtrack, input type %d\n", type));
266− DPRINT(("len = %d\n", len));
267−
268−#ifdef TRE_USE_ALLOCA
269− tags = alloca(sizeof(*tags) * tnfa->num_tags);
270− pmatch = alloca(sizeof(*pmatch) * tnfa->num_submatches);
271− states_seen = alloca(sizeof(*states_seen) * tnfa->num_states);
272−#else /* !TRE_USE_ALLOCA */
273− if (tnfa->num_tags)
274− {
275− tags = xmalloc(sizeof(*tags) * tnfa->num_tags);
276− if (!tags)
277− {
278− ret = REG_ESPACE;
279− goto error_exit;
280− }
281− }
282− if (tnfa->num_submatches)
283− {
284− pmatch = xmalloc(sizeof(*pmatch) * tnfa->num_submatches);
285− if (!pmatch)
286− {
287− ret = REG_ESPACE;
288− goto error_exit;
289− }
290− }
291− if (tnfa->num_states)
292− {
293− states_seen = xmalloc(sizeof(*states_seen) * tnfa->num_states);
294− if (!states_seen)
295− {
296− ret = REG_ESPACE;
297− goto error_exit;
298− }
299− }
300−#endif /* !TRE_USE_ALLOCA */
301−
302− retry:
303− {
304− int i;
305− for (i = 0; i < tnfa->num_tags; i++)
306− {
307− tags[i] = -1;
308− if (match_tags)
309− match_tags[i] = -1;
310− }
311− for (i = 0; i < tnfa->num_states; i++)
312− states_seen[i] = 0;
313− }
314−
315− state = NULL;
316− pos = pos_start;
317− if (type == STR_USER)
318− str_source->rewind(pos + pos_add_next, str_source->context);
319− GET_NEXT_WCHAR();
320− pos_start = pos;
321− next_c_start = next_c;
322− str_byte_start = str_byte;
323−#ifdef TRE_WCHAR
324− str_wide_start = str_wide;
325−#endif /* TRE_WCHAR */
326−#ifdef TRE_MBSTATE
327− mbstate_start = mbstate;
328−#endif /* TRE_MBSTATE */
329−
330− /* Handle initial states. */
331− next_tags = NULL;
332− for (trans_i = tnfa->initial; trans_i->state; trans_i++)
333− {
334− DPRINT(("> init %p, prev_c %lc\n", trans_i->state, (tre_cint_t)prev_c));
335− if (trans_i->assertions && CHECK_ASSERTIONS(trans_i->assertions))
336− {
337− DPRINT(("assert failed\n"));
338− continue;
339− }
340− if (state == NULL)
341− {
342− /* Start from this state. */
343− state = trans_i->state;
344− next_tags = trans_i->tags;
345− }
346− else
347− {
348− /* Backtrack to this state. */
349− DPRINT(("saving state %d for backtracking\n", trans_i->state_id));
350− BT_STACK_PUSH(pos, str_byte, str_wide, trans_i->state,
351− trans_i->state_id, next_c, tags, mbstate);
352− {
353− int *tmp = trans_i->tags;
354− if (tmp)
355− while (*tmp >= 0)
356− stack->item.tags[*tmp++] = pos;
357− }
358− }
359− }
360−
361− if (next_tags)
362− for (; *next_tags >= 0; next_tags++)
363− tags[*next_tags] = pos;
364−
365−
366− DPRINT(("entering match loop, pos %d, str_byte %p\n", pos, str_byte));
367− DPRINT(("pos:chr/code | state and tags\n"));
368− DPRINT(("-------------+------------------------------------------------\n"));
369−
370− if (state == NULL)
371− goto backtrack;
372−
373− while (/*CONSTCOND*/1)
374− {
375− tre_tnfa_transition_t *next_state;
376− int empty_br_match;
377−
378− DPRINT(("start loop\n"));
379− if (state == tnfa->final)
380− {
381− DPRINT((" match found, %d %d\n", match_eo, pos));
382− if (match_eo < pos
383− || (match_eo == pos
384− && match_tags
385− && tre_tag_order(tnfa->num_tags, tnfa->tag_directions,
386− tags, match_tags)))
387− {
388− int i;
389− /* This match wins the previous match. */
390− DPRINT((" win previous\n"));
391− match_eo = pos;
392− if (match_tags)
393− for (i = 0; i < tnfa->num_tags; i++)
394− match_tags[i] = tags[i];
395− }
396− /* Our TNFAs never have transitions leaving from the final state,
397− so we jump right to backtracking. */
398− goto backtrack;
399− }
400−
401−#ifdef TRE_DEBUG
402− DPRINT(("%3d:%2lc/%05d | %p ", pos, (tre_cint_t)next_c, (int)next_c,
403− state));
404− {
405− int i;
406− for (i = 0; i < tnfa->num_tags; i++)
407− DPRINT(("%d%s", tags[i], i < tnfa->num_tags - 1 ? ", " : ""));
408− DPRINT(("\n"));
409− }
410−#endif /* TRE_DEBUG */
411−
412− /* Go to the next character in the input string. */
413− empty_br_match = 0;
414− trans_i = state;
415− if (trans_i->state && trans_i->assertions & ASSERT_BACKREF)
416− {
417− /* This is a back reference state. All transitions leaving from
418− this state have the same back reference "assertion". Instead
419− of reading the next character, we match the back reference. */
420− int so, eo, bt = trans_i->u.backref;
421− int bt_len;
422− int result;
423−
424− DPRINT((" should match back reference %d\n", bt));
425− /* Get the substring we need to match against. Remember to
426− turn off REG_NOSUB temporarily. */
427− tre_fill_pmatch(bt + 1, pmatch, tnfa->cflags & /*LINTED*/!REG_NOSUB,
428− tnfa, tags, pos);
429− so = pmatch[bt].rm_so;
430− eo = pmatch[bt].rm_eo;
431− bt_len = eo - so;
432−
433−#ifdef TRE_DEBUG
434− {
435− int slen;
436− if (len < 0)
437− slen = bt_len;
438− else
439− slen = MIN(bt_len, len - pos);
440−
441− if (type == STR_BYTE)
442− {
443− DPRINT((" substring (len %d) is [%d, %d[: '%.*s'\n",
444− bt_len, so, eo, bt_len, (char*)string + so));
445− DPRINT((" current string is '%.*s'\n", slen, str_byte - 1));
446− }
447−#ifdef TRE_WCHAR
448− else if (type == STR_WIDE)
449− {
450− DPRINT((" substring (len %d) is [%d, %d[: '%.*" STRF "'\n",
451− bt_len, so, eo, bt_len, (wchar_t*)string + so));
452− DPRINT((" current string is '%.*" STRF "'\n",
453− slen, str_wide - 1));
454− }
455−#endif /* TRE_WCHAR */
456− }
457−#endif
458−
459− if (len < 0)
460− {
461− if (type == STR_USER)
462− result = str_source->compare((unsigned)so, (unsigned)pos,
463− (unsigned)bt_len,
464− str_source->context);
465−#ifdef TRE_WCHAR
466− else if (type == STR_WIDE)
467− result = wcsncmp((const wchar_t*)string + so, str_wide - 1,
468− (size_t)bt_len);
469−#endif /* TRE_WCHAR */
470− else
471− result = strncmp((const char*)string + so, str_byte - 1,
472− (size_t)bt_len);
473− }
474− else if (len - pos < bt_len)
475− result = 1;
476−#ifdef TRE_WCHAR
477− else if (type == STR_WIDE)
478− result = wmemcmp((const wchar_t*)string + so, str_wide - 1,
479− (size_t)bt_len);
480−#endif /* TRE_WCHAR */
481− else
482− result = memcmp((const char*)string + so, str_byte - 1,
483− (size_t)bt_len);
484−
485− if (result == 0)
486− {
487− /* Back reference matched. Check for infinite loop. */
488− if (bt_len == 0)
489− empty_br_match = 1;
490− if (empty_br_match && states_seen[trans_i->state_id])
491− {
492− DPRINT((" avoid loop\n"));
493− goto backtrack;
494− }
495−
496− states_seen[trans_i->state_id] = empty_br_match;
497−
498− /* Advance in input string and resync `prev_c', `next_c'
499− and pos. */
500− DPRINT((" back reference matched\n"));
501− str_byte += bt_len - 1;
502−#ifdef TRE_WCHAR
503− str_wide += bt_len - 1;
504−#endif /* TRE_WCHAR */
505− pos += bt_len - 1;
506− GET_NEXT_WCHAR();
507− DPRINT((" pos now %d\n", pos));
508− }
509− else
510− {
511− DPRINT((" back reference did not match\n"));
512− goto backtrack;
513− }
514− }
515− else
516− {
517− /* Check for end of string. */
518− if (len < 0)
519− {
520− if (type == STR_USER)
521− {
522− if (str_user_end)
523− goto backtrack;
524− }
525− else if (next_c == L'\0')
526− goto backtrack;
527− }
528− else
529− {
530− if (pos >= len)
531− goto backtrack;
532− }
533−
534− /* Read the next character. */
535− GET_NEXT_WCHAR();
536− }
537−
538− next_state = NULL;
539− for (trans_i = state; trans_i->state; trans_i++)
540− {
541− DPRINT((" transition %d-%d (%c-%c) %d to %d\n",
542− trans_i->code_min, trans_i->code_max,
543− trans_i->code_min, trans_i->code_max,
544− trans_i->assertions, trans_i->state_id));
545− if (trans_i->code_min <= (tre_cint_t)prev_c
546− && trans_i->code_max >= (tre_cint_t)prev_c)
547− {
548− if (trans_i->assertions
549− && (CHECK_ASSERTIONS(trans_i->assertions)
550− || CHECK_CHAR_CLASSES(trans_i, tnfa, eflags)))
551− {
552− DPRINT((" assertion failed\n"));
553− continue;
554− }
555−
556− if (next_state == NULL)
557− {
558− /* First matching transition. */
559− DPRINT((" Next state is %d\n", trans_i->state_id));
560− next_state = trans_i->state;
561− next_tags = trans_i->tags;
562− }
563− else
564− {
565− /* Second matching transition. We may need to backtrack here
566− to take this transition instead of the first one, so we
567− push this transition in the backtracking stack so we can
568− jump back here if needed. */
569− DPRINT((" saving state %d for backtracking\n",
570− trans_i->state_id));
571− BT_STACK_PUSH(pos, str_byte, str_wide, trans_i->state,
572− trans_i->state_id, next_c, tags, mbstate);
573− {
574− int *tmp;
575− for (tmp = trans_i->tags; tmp && *tmp >= 0; tmp++)
576− stack->item.tags[*tmp] = pos;
577− }
578−#if 0 /* XXX - it's important not to look at all transitions here to keep
579− the stack small! */
580− break;
581−#endif
582− }
583− }
584− }
585−
586− if (next_state != NULL)
587− {
588− /* Matching transitions were found. Take the first one. */
589− state = next_state;
590−
591− /* Update the tag values. */
592− if (next_tags)
593− while (*next_tags >= 0)
594− tags[*next_tags++] = pos;
595− }
596− else
597− {
598− backtrack:
599− /* A matching transition was not found. Try to backtrack. */
600− if (stack->prev)
601− {
602− DPRINT((" backtracking\n"));
603− if (stack->item.state->assertions && ASSERT_BACKREF)
604− {
605− DPRINT((" states_seen[%d] = 0\n",
606− stack->item.state_id));
607− states_seen[stack->item.state_id] = 0;
608− }
609−
610− BT_STACK_POP();
611− }
612− else if (match_eo < 0)
613− {
614− /* Try starting from a later position in the input string. */
615− /* Check for end of string. */
616− if (len < 0)
617− {
618− if (next_c == L'\0')
619− {
620− DPRINT(("end of string.\n"));
621− break;
622− }
623− }
624− else
625− {
626− if (pos >= len)
627− {
628− DPRINT(("end of string.\n"));
629− break;
630− }
631− }
632− DPRINT(("restarting from next start position\n"));
633− next_c = next_c_start;
634−#ifdef TRE_MBSTATE
635− mbstate = mbstate_start;
636−#endif /* TRE_MBSTATE */
637− str_byte = str_byte_start;
638−#ifdef TRE_WCHAR
639− str_wide = str_wide_start;
640−#endif /* TRE_WCHAR */
641− goto retry;
642− }
643− else
644− {
645− DPRINT(("finished\n"));
646− break;
647− }
648− }
649− }
650−
651− ret = match_eo >= 0 ? REG_OK : REG_NOMATCH;
652− *match_end_ofs = match_eo;
653−
654− error_exit:
655− tre_bt_mem_destroy(mem);
656−#ifndef TRE_USE_ALLOCA
657− if (tags)
658− xfree(tags);
659− if (pmatch)
660− xfree(pmatch);
661− if (states_seen)
662− xfree(states_seen);
663−#endif /* !TRE_USE_ALLOCA */
664−
665− return ret;
666−}
src/core/regex/tre-match-parallel.c+0−501
@@ -1,501 +0,0 @@
1−/*
2− tre-match-parallel.c - TRE parallel regex matching engine
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−/*
10− This algorithm searches for matches basically by reading characters
11− in the searched string one by one, starting at the beginning. All
12− matching paths in the TNFA are traversed in parallel. When two or
13− more paths reach the same state, exactly one is chosen according to
14− tag ordering rules; if returning submatches is not required it does
15− not matter which path is chosen.
16−
17− The worst case time required for finding the leftmost and longest
18− match, or determining that there is no match, is always linearly
19− dependent on the length of the text being searched.
20−
21− This algorithm cannot handle TNFAs with back referencing nodes.
22− See `tre-match-backtrack.c'.
23−*/
24−
25−
26−#ifdef HAVE_CONFIG_H
27−#include "config.h"
28−#endif /* HAVE_CONFIG_H */
29−
30−#ifdef TRE_USE_ALLOCA
31−/* AIX requires this to be the first thing in the file. */
32−#ifndef __GNUC__
33−# if HAVE_ALLOCA_H
34−# include <alloca.h>
35−# else
36−# ifdef _AIX
37− #pragma alloca
38−# else
39−# ifndef alloca /* predefined by HP cc +Olibcalls */
40−char *alloca ();
41−# endif
42−# endif
43−# endif
44−#endif
45−#endif /* TRE_USE_ALLOCA */
46−
47−#include <assert.h>
48−#include <stdlib.h>
49−#include <string.h>
50−#ifdef HAVE_WCHAR_H
51−#include <wchar.h>
52−#endif /* HAVE_WCHAR_H */
53−#ifdef HAVE_WCTYPE_H
54−#include <wctype.h>
55−#endif /* HAVE_WCTYPE_H */
56−#ifndef TRE_WCHAR
57−#include <ctype.h>
58−#endif /* !TRE_WCHAR */
59−#ifdef HAVE_MALLOC_H
60−#include <malloc.h>
61−#endif /* HAVE_MALLOC_H */
62−
63−#include "tre-internal.h"
64−#include "tre-match-utils.h"
65−#include "tre.h"
66−#include "xmalloc.h"
67−
68−
69−
70−typedef struct {
71− tre_tnfa_transition_t *state;
72− int *tags;
73−} tre_tnfa_reach_t;
74−
75−typedef struct {
76− int pos;
77− int **tags;
78−} tre_reach_pos_t;
79−
80−
81−#ifdef TRE_DEBUG
82−static void
83−tre_print_reach(const tre_tnfa_t *tnfa, tre_tnfa_reach_t *reach, int num_tags)
84−{
85− int i;
86−
87− while (reach->state != NULL)
88− {
89− DPRINT((" %p", (void *)reach->state));
90− if (num_tags > 0)
91− {
92− DPRINT(("/"));
93− for (i = 0; i < num_tags; i++)
94− {
95− DPRINT(("%d:%d", i, reach->tags[i]));
96− if (i < (num_tags-1))
97− DPRINT((","));
98− }
99− }
100− reach++;
101− }
102− DPRINT(("\n"));
103−
104−}
105−#endif /* TRE_DEBUG */
106−
107−reg_errcode_t
108−tre_tnfa_run_parallel(const tre_tnfa_t *tnfa, const void *string, int len,
109− tre_str_type_t type, int *match_tags, int eflags,
110− int *match_end_ofs)
111−{
112− /* State variables required by GET_NEXT_WCHAR. */
113− tre_char_t prev_c = 0, next_c = 0;
114− const char *str_byte = string;
115− int pos = -1;
116− unsigned int pos_add_next = 1;
117−#ifdef TRE_WCHAR
118− const wchar_t *str_wide = string;
119−#ifdef TRE_MBSTATE
120− mbstate_t mbstate;
121−#endif /* TRE_MBSTATE */
122−#endif /* TRE_WCHAR */
123− int reg_notbol = eflags & REG_NOTBOL;
124− int reg_noteol = eflags & REG_NOTEOL;
125− int reg_newline = tnfa->cflags & REG_NEWLINE;
126− int str_user_end = 0;
127−
128− char *buf;
129− tre_tnfa_transition_t *trans_i;
130− tre_tnfa_reach_t *reach, *reach_next, *reach_i, *reach_next_i;
131− tre_reach_pos_t *reach_pos;
132− int *tag_i;
133− int num_tags, i;
134−
135− int match_eo = -1; /* end offset of match (-1 if no match found yet) */
136− int new_match = 0;
137− int *tmp_tags = NULL;
138− int *tmp_iptr;
139−
140−#ifdef TRE_MBSTATE
141− memset(&mbstate, '\0', sizeof(mbstate));
142−#endif /* TRE_MBSTATE */
143−
144− DPRINT(("tre_tnfa_run_parallel, input type %d\n", type));
145−
146− if (!match_tags)
147− num_tags = 0;
148− else
149− num_tags = tnfa->num_tags;
150−
151− /* Allocate memory for temporary data required for matching. This needs to
152− be done for every matching operation to be thread safe. This allocates
153− everything in a single large block from the stack frame using alloca()
154− or with malloc() if alloca is unavailable. */
155− {
156− int tbytes, rbytes, pbytes, xbytes, total_bytes;
157− char *tmp_buf;
158− /* Compute the length of the block we need. */
159− tbytes = sizeof(*tmp_tags) * num_tags;
160− rbytes = sizeof(*reach_next) * (tnfa->num_states + 1);
161− pbytes = sizeof(*reach_pos) * tnfa->num_states;
162− xbytes = sizeof(int) * num_tags;
163− total_bytes =
164− (sizeof(long) - 1) * 4 /* for alignment paddings */
165− + (rbytes + xbytes * tnfa->num_states) * 2 + tbytes + pbytes;
166−
167− /* Allocate the memory. */
168−#ifdef TRE_USE_ALLOCA
169− buf = alloca(total_bytes);
170−#else /* !TRE_USE_ALLOCA */
171− buf = xmalloc((unsigned)total_bytes);
172−#endif /* !TRE_USE_ALLOCA */
173− if (buf == NULL)
174− return REG_ESPACE;
175− memset(buf, 0, (size_t)total_bytes);
176−
177− /* Get the various pointers within tmp_buf (properly aligned). */
178− tmp_tags = (void *)buf;
179− tmp_buf = buf + tbytes;
180− tmp_buf += ALIGN(tmp_buf, long);
181− reach_next = (void *)tmp_buf;
182− tmp_buf += rbytes;
183− tmp_buf += ALIGN(tmp_buf, long);
184− reach = (void *)tmp_buf;
185− tmp_buf += rbytes;
186− tmp_buf += ALIGN(tmp_buf, long);
187− reach_pos = (void *)tmp_buf;
188− tmp_buf += pbytes;
189− tmp_buf += ALIGN(tmp_buf, long);
190− for (i = 0; i < tnfa->num_states; i++)
191− {
192− reach[i].tags = (void *)tmp_buf;
193− tmp_buf += xbytes;
194− reach_next[i].tags = (void *)tmp_buf;
195− tmp_buf += xbytes;
196− }
197− }
198−
199− for (i = 0; i < tnfa->num_states; i++)
200− reach_pos[i].pos = -1;
201−
202− /* If only one character can start a match, find it first. */
203− if (tnfa->first_char >= 0 && type == STR_BYTE && str_byte)
204− {
205− const char *orig_str = str_byte;
206− int first = tnfa->first_char;
207−
208− if (len >= 0)
209− str_byte = memchr(orig_str, first, (size_t)len);
210− else
211− str_byte = strchr(orig_str, first);
212− if (str_byte == NULL)
213− {
214−#ifndef TRE_USE_ALLOCA
215− if (buf)
216− xfree(buf);
217−#endif /* !TRE_USE_ALLOCA */
218− return REG_NOMATCH;
219− }
220− DPRINT(("skipped %lu chars\n", (unsigned long)(str_byte - orig_str)));
221− if (str_byte >= orig_str + 1)
222− prev_c = (unsigned char)*(str_byte - 1);
223− next_c = (unsigned char)*str_byte;
224− pos = str_byte - orig_str;
225− if (len < 0 || pos < len)
226− str_byte++;
227− }
228− else
229− {
230− GET_NEXT_WCHAR();
231− pos = 0;
232− }
233−
234−#if 0
235− /* Skip over characters that cannot possibly be the first character
236− of a match. */
237− if (tnfa->firstpos_chars != NULL)
238− {
239− char *chars = tnfa->firstpos_chars;
240−
241− if (len < 0)
242− {
243− const char *orig_str = str_byte;
244− /* XXX - use strpbrk() and wcspbrk() because they might be
245− optimized for the target architecture. Try also strcspn()
246− and wcscspn() and compare the speeds. */
247− while (next_c != L'\0' && !chars[next_c])
248− {
249− next_c = *str_byte++;
250− }
251− prev_c = *(str_byte - 2);
252− pos += str_byte - orig_str;
253− DPRINT(("skipped %d chars\n", str_byte - orig_str));
254− }
255− else
256− {
257− while (pos <= len && !chars[next_c])
258− {
259− prev_c = next_c;
260− next_c = (unsigned char)(*str_byte++);
261− pos++;
262− }
263− }
264− }
265−#endif
266−
267− DPRINT(("length: %d\n", len));
268− DPRINT(("pos:chr/code | states and tags\n"));
269− DPRINT(("-------------+------------------------------------------------\n"));
270−
271− reach_next_i = reach_next;
272− while (/*CONSTCOND*/1)
273− {
274− /* If no match found yet, add the initial states to `reach_next'. */
275− if (match_eo < 0)
276− {
277− DPRINT((" init >"));
278− trans_i = tnfa->initial;
279− while (trans_i->state != NULL)
280− {
281− if (reach_pos[trans_i->state_id].pos < pos)
282− {
283− if (trans_i->assertions
284− && CHECK_ASSERTIONS(trans_i->assertions))
285− {
286− DPRINT(("assertion failed\n"));
287− trans_i++;
288− continue;
289− }
290−
291− DPRINT((" %p", (void *)trans_i->state));
292− reach_next_i->state = trans_i->state;
293− for (i = 0; i < num_tags; i++)
294− reach_next_i->tags[i] = -1;
295− tag_i = trans_i->tags;
296− if (tag_i)
297− while (*tag_i >= 0)
298− {
299− if (*tag_i < num_tags)
300− reach_next_i->tags[*tag_i] = pos;
301− tag_i++;
302− }
303− if (reach_next_i->state == tnfa->final)
304− {
305− DPRINT((" found empty match\n"));
306− match_eo = pos;
307− new_match = 1;
308− for (i = 0; i < num_tags; i++)
309− match_tags[i] = reach_next_i->tags[i];
310− }
311− reach_pos[trans_i->state_id].pos = pos;
312− reach_pos[trans_i->state_id].tags = &reach_next_i->tags;
313− reach_next_i++;
314− }
315− trans_i++;
316− }
317− DPRINT(("\n"));
318− reach_next_i->state = NULL;
319− }
320− else
321− {
322− if (num_tags == 0 || reach_next_i == reach_next)
323− /*�We have found a match. */
324− break;
325− }
326−
327− /* Check for end of string. */
328− if (len < 0)
329− {
330− if (type == STR_USER)
331− {
332− if (str_user_end)
333− break;
334− }
335− else if (next_c == L'\0')
336− break;
337− }
338− else
339− {
340− if (pos >= len)
341− break;
342− }
343−
344− GET_NEXT_WCHAR();
345−
346−#ifdef TRE_DEBUG
347− DPRINT(("%3d:%2lc/%05d |", pos - 1, (tre_cint_t)prev_c, (int)prev_c));
348− tre_print_reach(tnfa, reach_next, num_tags);
349− DPRINT(("%3d:%2lc/%05d |", pos, (tre_cint_t)next_c, (int)next_c));
350− tre_print_reach(tnfa, reach_next, num_tags);
351−#endif /* TRE_DEBUG */
352−
353− /* Swap `reach' and `reach_next'. */
354− reach_i = reach;
355− reach = reach_next;
356− reach_next = reach_i;
357−
358− /* For each state in `reach', weed out states that don't fulfill the
359− minimal matching conditions. */
360− if (tnfa->num_minimals && new_match)
361− {
362− new_match = 0;
363− reach_next_i = reach_next;
364− for (reach_i = reach; reach_i->state; reach_i++)
365− {
366− int skip = 0;
367− for (i = 0; tnfa->minimal_tags[i] >= 0; i += 2)
368− {
369− int end = tnfa->minimal_tags[i];
370− int start = tnfa->minimal_tags[i + 1];
371− DPRINT((" Minimal start %d, end %d\n", start, end));
372− if (end >= num_tags)
373− {
374− DPRINT((" Throwing %p out.\n", reach_i->state));
375− skip = 1;
376− break;
377− }
378− else if (reach_i->tags[start] == match_tags[start]
379− && reach_i->tags[end] < match_tags[end])
380− {
381− DPRINT((" Throwing %p out because t%d < %d\n",
382− reach_i->state, end, match_tags[end]));
383− skip = 1;
384− break;
385− }
386− }
387− if (!skip)
388− {
389− reach_next_i->state = reach_i->state;
390− tmp_iptr = reach_next_i->tags;
391− reach_next_i->tags = reach_i->tags;
392− reach_i->tags = tmp_iptr;
393− reach_next_i++;
394− }
395− }
396− reach_next_i->state = NULL;
397−
398− /* Swap `reach' and `reach_next'. */
399− reach_i = reach;
400− reach = reach_next;
401− reach_next = reach_i;
402− }
403−
404− /* For each state in `reach' see if there is a transition leaving with
405− the current input symbol to a state not yet in `reach_next', and
406− add the destination states to `reach_next'. */
407− reach_next_i = reach_next;
408− for (reach_i = reach; reach_i->state; reach_i++)
409− {
410− for (trans_i = reach_i->state; trans_i->state; trans_i++)
411− {
412− /* Does this transition match the input symbol? */
413− if (trans_i->code_min <= (tre_cint_t)prev_c &&
414− trans_i->code_max >= (tre_cint_t)prev_c)
415− {
416− if (trans_i->assertions
417− && (CHECK_ASSERTIONS(trans_i->assertions)
418− || CHECK_CHAR_CLASSES(trans_i, tnfa, eflags)))
419− {
420− DPRINT(("assertion failed\n"));
421− continue;
422− }
423−
424− /* Compute the tags after this transition. */
425− for (i = 0; i < num_tags; i++)
426− tmp_tags[i] = reach_i->tags[i];
427− tag_i = trans_i->tags;
428− if (tag_i != NULL)
429− while (*tag_i >= 0)
430− {
431− if (*tag_i < num_tags)
432− tmp_tags[*tag_i] = pos;
433− tag_i++;
434− }
435−
436− if (reach_pos[trans_i->state_id].pos < pos)
437− {
438− /* Found an unvisited node. */
439− reach_next_i->state = trans_i->state;
440− tmp_iptr = reach_next_i->tags;
441− reach_next_i->tags = tmp_tags;
442− tmp_tags = tmp_iptr;
443− reach_pos[trans_i->state_id].pos = pos;
444− reach_pos[trans_i->state_id].tags = &reach_next_i->tags;
445−
446− if (reach_next_i->state == tnfa->final
447− && (match_eo == -1
448− || (num_tags > 0
449− && reach_next_i->tags[0] <= match_tags[0])))
450− {
451− DPRINT((" found match %p\n", trans_i->state));
452− match_eo = pos;
453− new_match = 1;
454− for (i = 0; i < num_tags; i++)
455− match_tags[i] = reach_next_i->tags[i];
456− }
457− reach_next_i++;
458−
459− }
460− else
461− {
462− assert(reach_pos[trans_i->state_id].pos == pos);
463− /* Another path has also reached this state. We choose
464− the winner by examining the tag values for both
465− paths. */
466− if (tre_tag_order(num_tags, tnfa->tag_directions,
467− tmp_tags,
468− *reach_pos[trans_i->state_id].tags))
469− {
470− /* The new path wins. */
471− tmp_iptr = *reach_pos[trans_i->state_id].tags;
472− *reach_pos[trans_i->state_id].tags = tmp_tags;
473− if (trans_i->state == tnfa->final)
474− {
475− DPRINT((" found better match\n"));
476− match_eo = pos;
477− new_match = 1;
478− for (i = 0; i < num_tags; i++)
479− match_tags[i] = tmp_tags[i];
480− }
481− tmp_tags = tmp_iptr;
482− }
483− }
484− }
485− }
486− }
487− reach_next_i->state = NULL;
488− }
489−
490− DPRINT(("match end offset = %d\n", match_eo));
491−
492−#ifndef TRE_USE_ALLOCA
493− if (buf)
494− xfree(buf);
495−#endif /* !TRE_USE_ALLOCA */
496−
497− *match_end_ofs = match_eo;
498− return match_eo >= 0 ? REG_OK : REG_NOMATCH;
499−}
500−
501−/* EOF */
src/core/regex/tre-match-utils.h+0−215
@@ -1,215 +0,0 @@
1−/*
2− tre-match-utils.h - TRE matcher helper definitions
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−#define str_source ((const tre_str_source*)string)
10−
11−#ifdef TRE_WCHAR
12−
13−#ifdef TRE_MULTIBYTE
14−
15−/* Wide character and multibyte support. */
16−
17−#define GET_NEXT_WCHAR() \
18− do { \
19− prev_c = next_c; \
20− if (type == STR_BYTE) \
21− { \
22− pos++; \
23− if (len >= 0 && pos >= len) \
24− next_c = '\0'; \
25− else \
26− next_c = (unsigned char)(*str_byte++); \
27− } \
28− else if (type == STR_WIDE) \
29− { \
30− pos++; \
31− if (len >= 0 && pos >= len) \
32− next_c = L'\0'; \
33− else \
34− next_c = *str_wide++; \
35− } \
36− else if (type == STR_MBS) \
37− { \
38− pos += pos_add_next; \
39− if (str_byte == NULL) \
40− next_c = L'\0'; \
41− else \
42− { \
43− size_t w; \
44− int max; \
45− if (len >= 0) \
46− max = len - pos; \
47− else \
48− max = 32; \
49− if (max <= 0) \
50− { \
51− next_c = L'\0'; \
52− pos_add_next = 1; \
53− } \
54− else \
55− { \
56− w = tre_mbrtowc(&next_c, str_byte, (size_t)max, &mbstate); \
57− if (w == (size_t)-1 || w == (size_t)-2) \
58− return REG_NOMATCH; \
59− if (w == 0 && len >= 0) \
60− { \
61− pos_add_next = 1; \
62− next_c = 0; \
63− str_byte++; \
64− } \
65− else \
66− { \
67− pos_add_next = w; \
68− str_byte += w; \
69− } \
70− } \
71− } \
72− } \
73− else if (type == STR_USER) \
74− { \
75− pos += pos_add_next; \
76− str_user_end = str_source->get_next_char(&next_c, &pos_add_next, \
77− str_source->context); \
78− } \
79− } while(/*CONSTCOND*/0)
80−
81−#else /* !TRE_MULTIBYTE */
82−
83−/* Wide character support, no multibyte support. */
84−
85−#define GET_NEXT_WCHAR() \
86− do { \
87− prev_c = next_c; \
88− if (type == STR_BYTE) \
89− { \
90− pos++; \
91− if (len >= 0 && pos >= len) \
92− next_c = '\0'; \
93− else \
94− next_c = (unsigned char)(*str_byte++); \
95− } \
96− else if (type == STR_WIDE) \
97− { \
98− pos++; \
99− if (len >= 0 && pos >= len) \
100− next_c = L'\0'; \
101− else \
102− next_c = *str_wide++; \
103− } \
104− else if (type == STR_USER) \
105− { \
106− pos += pos_add_next; \
107− str_user_end = str_source->get_next_char(&next_c, &pos_add_next, \
108− str_source->context); \
109− } \
110− } while(/*CONSTCOND*/0)
111−
112−#endif /* !TRE_MULTIBYTE */
113−
114−#else /* !TRE_WCHAR */
115−
116−/* No wide character or multibyte support. */
117−
118−#define GET_NEXT_WCHAR() \
119− do { \
120− prev_c = next_c; \
121− if (type == STR_BYTE) \
122− { \
123− pos++; \
124− if (len >= 0 && pos >= len) \
125− next_c = '\0'; \
126− else \
127− next_c = (unsigned char)(*str_byte++); \
128− } \
129− else if (type == STR_USER) \
130− { \
131− pos += pos_add_next; \
132− str_user_end = str_source->get_next_char(&next_c, &pos_add_next, \
133− str_source->context); \
134− } \
135− } while(/*CONSTCOND*/0)
136−
137−#endif /* !TRE_WCHAR */
138−
139−
140−
141−#define IS_WORD_CHAR(c) ((c) == L'_' || tre_isalnum(c))
142−
143−#define CHECK_ASSERTIONS(assertions) \
144− (((assertions & ASSERT_AT_BOL) \
145− && (pos > 0 || reg_notbol) \
146− && (prev_c != L'\n' || !reg_newline)) \
147− || ((assertions & ASSERT_AT_EOL) \
148− && (next_c != L'\0' || reg_noteol) \
149− && (next_c != L'\n' || !reg_newline)) \
150− || ((assertions & ASSERT_AT_BOW) \
151− && (IS_WORD_CHAR(prev_c) || !IS_WORD_CHAR(next_c))) \
152− || ((assertions & ASSERT_AT_EOW) \
153− && (!IS_WORD_CHAR(prev_c) || IS_WORD_CHAR(next_c))) \
154− || ((assertions & ASSERT_AT_WB) \
155− && (pos != 0 && next_c != L'\0' \
156− && IS_WORD_CHAR(prev_c) == IS_WORD_CHAR(next_c))) \
157− || ((assertions & ASSERT_AT_WB_NEG) \
158− && (pos == 0 || next_c == L'\0' \
159− || IS_WORD_CHAR(prev_c) != IS_WORD_CHAR(next_c))))
160−
161−#define CHECK_CHAR_CLASSES(trans_i, tnfa, eflags) \
162− (((trans_i->assertions & ASSERT_CHAR_CLASS) \
163− && !(tnfa->cflags & REG_ICASE) \
164− && !tre_isctype((tre_cint_t)prev_c, trans_i->u.class)) \
165− || ((trans_i->assertions & ASSERT_CHAR_CLASS) \
166− && (tnfa->cflags & REG_ICASE) \
167− && !tre_isctype(tre_tolower((tre_cint_t)prev_c),trans_i->u.class) \
168− && !tre_isctype(tre_toupper((tre_cint_t)prev_c),trans_i->u.class)) \
169− || ((trans_i->assertions & ASSERT_CHAR_CLASS_NEG) \
170− && tre_neg_char_classes_match(trans_i->neg_classes,(tre_cint_t)prev_c, \
171− tnfa->cflags & REG_ICASE)))
172−
173−
174−
175−
176−/* Returns 1 if `t1' wins `t2', 0 otherwise. */
177−inline static int
178−tre_tag_order(int num_tags, tre_tag_direction_t *tag_directions,
179− int *t1, int *t2)
180−{
181− int i;
182− for (i = 0; i < num_tags; i++)
183− {
184− if (tag_directions[i] == TRE_TAG_MINIMIZE)
185− {
186− if (t1[i] < t2[i])
187− return 1;
188− if (t1[i] > t2[i])
189− return 0;
190− }
191− else
192− {
193− if (t1[i] > t2[i])
194− return 1;
195− if (t1[i] < t2[i])
196− return 0;
197− }
198− }
199− /* assert(0);*/
200− return 0;
201−}
202−
203−inline static int
204−tre_neg_char_classes_match(tre_ctype_t *classes, tre_cint_t wc, int icase)
205−{
206− DPRINT(("neg_char_classes_test: %p, %d, %d\n", classes, wc, icase));
207− while (*classes != (tre_ctype_t)0)
208− if ((!icase && tre_isctype(wc, *classes))
209− || (icase && (tre_isctype(tre_toupper(wc), *classes)
210− || tre_isctype(tre_tolower(wc), *classes))))
211− return 1; /* Match. */
212− else
213− classes++;
214− return 0; /* No match. */
215−}
src/core/regex/tre-mem.c+0−155
@@ -1,155 +0,0 @@
1−/*
2− tre-mem.c - TRE memory allocator
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−/*
10− This memory allocator is for allocating small memory blocks efficiently
11− in terms of memory overhead and execution speed. The allocated blocks
12− cannot be freed individually, only all at once. There can be multiple
13− allocators, though.
14−*/
15−
16−#ifdef HAVE_CONFIG_H
17−#include <config.h>
18−#endif /* HAVE_CONFIG_H */
19−#include <stdlib.h>
20−#include <string.h>
21−
22−#include "tre-internal.h"
23−#include "tre-mem.h"
24−#include "xmalloc.h"
25−
26−
27−/* Returns a new memory allocator or NULL if out of memory. */
28−tre_mem_t
29−tre_mem_new_impl(int provided, void *provided_block)
30−{
31− tre_mem_t mem;
32− if (provided)
33− {
34− mem = provided_block;
35− memset(mem, 0, sizeof(*mem));
36− }
37− else
38− mem = xcalloc(1, sizeof(*mem));
39− if (mem == NULL)
40− return NULL;
41− return mem;
42−}
43−
44−
45−/* Frees the memory allocator and all memory allocated with it. */
46−void
47−tre_mem_destroy(tre_mem_t mem)
48−{
49− tre_list_t *tmp, *l = mem->blocks;
50−
51− while (l != NULL)
52− {
53− xfree(l->data);
54− tmp = l->next;
55− xfree(l);
56− l = tmp;
57− }
58− xfree(mem);
59−}
60−
61−
62−/* Allocates a block of `size' bytes from `mem'. Returns a pointer to the
63− allocated block or NULL if an underlying malloc() failed. */
64−void *
65−tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block,
66− int zero, size_t size)
67−{
68− void *ptr;
69−
70− if (mem->failed)
71− {
72− DPRINT(("tre_mem_alloc: oops, called after failure?!\n"));
73− return NULL;
74− }
75−
76−#ifdef MALLOC_DEBUGGING
77− if (!provided)
78− {
79− ptr = xmalloc(1);
80− if (ptr == NULL)
81− {
82− DPRINT(("tre_mem_alloc: xmalloc forced failure\n"));
83− mem->failed = 1;
84− return NULL;
85− }
86− xfree(ptr);
87− }
88−#endif /* MALLOC_DEBUGGING */
89−
90− if (mem->n < size)
91− {
92− /* We need more memory than is available in the current block.
93− Allocate a new block. */
94− tre_list_t *l;
95− if (provided)
96− {
97− DPRINT(("tre_mem_alloc: using provided block\n"));
98− if (provided_block == NULL)
99− {
100− DPRINT(("tre_mem_alloc: provided block was NULL\n"));
101− mem->failed = 1;
102− return NULL;
103− }
104− mem->ptr = provided_block;
105− mem->n = TRE_MEM_BLOCK_SIZE;
106− }
107− else
108− {
109− int block_size;
110− if (size * 8 > TRE_MEM_BLOCK_SIZE)
111− block_size = size * 8;
112− else
113− block_size = TRE_MEM_BLOCK_SIZE;
114− DPRINT(("tre_mem_alloc: allocating new %d byte block\n",
115− block_size));
116− l = xmalloc(sizeof(*l));
117− if (l == NULL)
118− {
119− mem->failed = 1;
120− return NULL;
121− }
122− l->data = xmalloc(block_size);
123− if (l->data == NULL)
124− {
125− xfree(l);
126− mem->failed = 1;
127− return NULL;
128− }
129− l->next = NULL;
130− if (mem->current != NULL)
131− mem->current->next = l;
132− if (mem->blocks == NULL)
133− mem->blocks = l;
134− mem->current = l;
135− mem->ptr = l->data;
136− mem->n = block_size;
137− }
138− }
139−
140− /* Make sure the next pointer will be aligned. */
141− size += ALIGN(mem->ptr + size, long);
142−
143− /* Allocate from current block. */
144− ptr = mem->ptr;
145− mem->ptr += size;
146− mem->n -= size;
147−
148− /* Set to zero if needed. */
149− if (zero)
150− memset(ptr, 0, size);
151−
152− return ptr;
153−}
154−
155−/* EOF */
src/core/regex/tre-mem.h+0−66
@@ -1,66 +0,0 @@
1−/*
2− tre-mem.h - TRE memory allocator interface
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−#ifndef TRE_MEM_H
10−#define TRE_MEM_H 1
11−
12−#include <stdlib.h>
13−
14−#define TRE_MEM_BLOCK_SIZE 1024
15−
16−typedef struct tre_list {
17− void *data;
18− struct tre_list *next;
19−} tre_list_t;
20−
21−typedef struct tre_mem_struct {
22− tre_list_t *blocks;
23− tre_list_t *current;
24− char *ptr;
25− size_t n;
26− int failed;
27− void **provided;
28−} *tre_mem_t;
29−
30−
31−tre_mem_t tre_mem_new_impl(int provided, void *provided_block);
32−void *tre_mem_alloc_impl(tre_mem_t mem, int provided, void *provided_block,
33− int zero, size_t size);
34−
35−/* Returns a new memory allocator or NULL if out of memory. */
36−#define tre_mem_new() tre_mem_new_impl(0, NULL)
37−
38−/* Allocates a block of `size' bytes from `mem'. Returns a pointer to the
39− allocated block or NULL if an underlying malloc() failed. */
40−#define tre_mem_alloc(mem, size) tre_mem_alloc_impl(mem, 0, NULL, 0, size)
41−
42−/* Allocates a block of `size' bytes from `mem'. Returns a pointer to the
43− allocated block or NULL if an underlying malloc() failed. The memory
44− is set to zero. */
45−#define tre_mem_calloc(mem, size) tre_mem_alloc_impl(mem, 0, NULL, 1, size)
46−
47−#ifdef TRE_USE_ALLOCA
48−/* alloca() versions. Like above, but memory is allocated with alloca()
49− instead of malloc(). */
50−
51−#define tre_mem_newa() \
52− tre_mem_new_impl(1, alloca(sizeof(struct tre_mem_struct)))
53−
54−#define tre_mem_alloca(mem, size) \
55− ((mem)->n >= (size) \
56− ? tre_mem_alloc_impl((mem), 1, NULL, 0, (size)) \
57− : tre_mem_alloc_impl((mem), 1, alloca(TRE_MEM_BLOCK_SIZE), 0, (size)))
58−#endif /* TRE_USE_ALLOCA */
59−
60−
61−/* Frees the memory allocator and all memory allocated with it. */
62−void tre_mem_destroy(tre_mem_t mem);
63−
64−#endif /* TRE_MEM_H */
65−
66−/* EOF */
src/core/regex/tre-parse.c+0−1739
@@ -1,1739 +0,0 @@
1−/*
2− tre-parse.c - Regexp parser
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−/*
10− This parser is just a simple recursive descent parser for POSIX.2
11− regexps. The parser supports both the obsolete default syntax and
12− the "extended" syntax, and some nonstandard extensions.
13−*/
14−
15−
16−#ifdef HAVE_CONFIG_H
17−#include <config.h>
18−#endif /* HAVE_CONFIG_H */
19−#include <string.h>
20−#include <assert.h>
21−#include <limits.h>
22−
23−#include "xmalloc.h"
24−#include "tre-mem.h"
25−#include "tre-ast.h"
26−#include "tre-stack.h"
27−#include "tre-parse.h"
28−
29−
30−/* Characters with special meanings in regexp syntax. */
31−#define CHAR_PIPE L'|'
32−#define CHAR_LPAREN L'('
33−#define CHAR_RPAREN L')'
34−#define CHAR_LBRACE L'{'
35−#define CHAR_RBRACE L'}'
36−#define CHAR_LBRACKET L'['
37−#define CHAR_RBRACKET L']'
38−#define CHAR_MINUS L'-'
39−#define CHAR_STAR L'*'
40−#define CHAR_QUESTIONMARK L'?'
41−#define CHAR_PLUS L'+'
42−#define CHAR_PERIOD L'.'
43−#define CHAR_COLON L':'
44−#define CHAR_EQUAL L'='
45−#define CHAR_COMMA L','
46−#define CHAR_CARET L'^'
47−#define CHAR_DOLLAR L'$'
48−#define CHAR_BACKSLASH L'\\'
49−#define CHAR_HASH L'#'
50−#define CHAR_TILDE L'~'
51−
52−
53−/* Some macros for expanding \w, \s, etc. */
54−static const struct tre_macro_struct {
55− const char c;
56− const char *expansion;
57−} tre_macros[] =
58− { {'t', "\t"}, {'n', "\n"}, {'r', "\r"},
59− {'f', "\f"}, {'a', "\a"}, {'e', "\033"},
60− {'w', "[[:alnum:]_]"}, {'W', "[^[:alnum:]_]"}, {'s', "[[:space:]]"},
61− {'S', "[^[:space:]]"}, {'d', "[[:digit:]]"}, {'D', "[^[:digit:]]"},
62− { 0, NULL }
63− };
64−
65−
66−/* Expands a macro delimited by `regex' and `regex_end' to `buf', which
67− must have at least `len' items. Sets buf[0] to zero if the there
68− is no match in `tre_macros'. */
69−static void
70−tre_expand_macro(const tre_char_t *regex, const tre_char_t *regex_end,
71− tre_char_t *buf, size_t buf_len)
72−{
73− int i;
74−
75− buf[0] = 0;
76− if (regex >= regex_end)
77− return;
78−
79− for (i = 0; tre_macros[i].expansion; i++)
80− {
81− if (tre_macros[i].c == *regex)
82− {
83− unsigned int j;
84− DPRINT(("Expanding macro '%c' => '%s'\n",
85− tre_macros[i].c, tre_macros[i].expansion));
86− for (j = 0; tre_macros[i].expansion[j] && j < buf_len; j++)
87− buf[j] = tre_macros[i].expansion[j];
88− buf[j] = 0;
89− break;
90− }
91− }
92−}
93−
94−static reg_errcode_t
95−tre_new_item(tre_mem_t mem, int min, int max, int *i, int *max_i,
96− tre_ast_node_t ***items)
97−{
98− reg_errcode_t status;
99− tre_ast_node_t **array = *items;
100− /* Allocate more space if necessary. */
101− if (*i >= *max_i)
102− {
103− tre_ast_node_t **new_items;
104− DPRINT(("out of array space, i = %d\n", *i));
105− /* If the array is already 1024 items large, give up -- there's
106− probably an error in the regexp (e.g. not a '\0' terminated
107− string and missing ']') */
108− if (*max_i > 1024)
109− return REG_ESPACE;
110− *max_i *= 2;
111− new_items = xrealloc(array, sizeof(*items) * *max_i);
112− if (new_items == NULL)
113− return REG_ESPACE;
114− *items = array = new_items;
115− }
116− array[*i] = tre_ast_new_literal(mem, min, max, -1);
117− status = array[*i] == NULL ? REG_ESPACE : REG_OK;
118− (*i)++;
119− return status;
120−}
121−
122−
123−/* Expands a character class to character ranges. */
124−static reg_errcode_t
125−tre_expand_ctype(tre_mem_t mem, tre_ctype_t class, tre_ast_node_t ***items,
126− int *i, int *max_i, int cflags)
127−{
128− reg_errcode_t status = REG_OK;
129− tre_cint_t c;
130− int j, min = -1, max = 0;
131− assert(TRE_MB_CUR_MAX == 1);
132−
133− DPRINT((" expanding class to character ranges\n"));
134− for (j = 0; (j < 256) && (status == REG_OK); j++)
135− {
136− c = j;
137− if (tre_isctype(c, class)
138− || ((cflags & REG_ICASE)
139− && (tre_isctype(tre_tolower(c), class)
140− || tre_isctype(tre_toupper(c), class))))
141−{
142− if (min < 0)
143− min = c;
144− max = c;
145− }
146− else if (min >= 0)
147− {
148− DPRINT((" range %c (%d) to %c (%d)\n", min, min, max, max));
149− status = tre_new_item(mem, min, max, i, max_i, items);
150− min = -1;
151− }
152− }
153− if (min >= 0 && status == REG_OK)
154− status = tre_new_item(mem, min, max, i, max_i, items);
155− return status;
156−}
157−
158−
159−static int
160−tre_compare_items(const void *a, const void *b)
161−{
162− const tre_ast_node_t *node_a = *(tre_ast_node_t * const *)a;
163− const tre_ast_node_t *node_b = *(tre_ast_node_t * const *)b;
164− tre_literal_t *l_a = node_a->obj, *l_b = node_b->obj;
165− int a_min = l_a->code_min, b_min = l_b->code_min;
166−
167− if (a_min < b_min)
168− return -1;
169− else if (a_min > b_min)
170− return 1;
171− else
172− return 0;
173−}
174−
175−#ifndef TRE_USE_SYSTEM_WCTYPE
176−
177−/* isalnum() and the rest may be macros, so wrap them to functions. */
178−int tre_isalnum_func(tre_cint_t c) { return tre_isalnum(c); }
179−int tre_isalpha_func(tre_cint_t c) { return tre_isalpha(c); }
180−
181−#ifdef tre_isascii
182−int tre_isascii_func(tre_cint_t c) { return tre_isascii(c); }
183−#else /* !tre_isascii */
184−int tre_isascii_func(tre_cint_t c) { return !(c >> 7); }
185−#endif /* !tre_isascii */
186−
187−#ifdef tre_isblank
188−int tre_isblank_func(tre_cint_t c) { return tre_isblank(c); }
189−#else /* !tre_isblank */
190−int tre_isblank_func(tre_cint_t c) { return ((c == ' ') || (c == '\t')); }
191−#endif /* !tre_isblank */
192−
193−int tre_iscntrl_func(tre_cint_t c) { return tre_iscntrl(c); }
194−int tre_isdigit_func(tre_cint_t c) { return tre_isdigit(c); }
195−int tre_isgraph_func(tre_cint_t c) { return tre_isgraph(c); }
196−int tre_islower_func(tre_cint_t c) { return tre_islower(c); }
197−int tre_isprint_func(tre_cint_t c) { return tre_isprint(c); }
198−int tre_ispunct_func(tre_cint_t c) { return tre_ispunct(c); }
199−int tre_isspace_func(tre_cint_t c) { return tre_isspace(c); }
200−int tre_isupper_func(tre_cint_t c) { return tre_isupper(c); }
201−int tre_isxdigit_func(tre_cint_t c) { return tre_isxdigit(c); }
202−
203−struct {
204− char *name;
205− int (*func)(tre_cint_t);
206−} tre_ctype_map[] = {
207− { "alnum", &tre_isalnum_func },
208− { "alpha", &tre_isalpha_func },
209−#ifdef tre_isascii
210− { "ascii", &tre_isascii_func },
211−#endif /* tre_isascii */
212−#ifdef tre_isblank
213− { "blank", &tre_isblank_func },
214−#endif /* tre_isblank */
215− { "cntrl", &tre_iscntrl_func },
216− { "digit", &tre_isdigit_func },
217− { "graph", &tre_isgraph_func },
218− { "lower", &tre_islower_func },
219− { "print", &tre_isprint_func },
220− { "punct", &tre_ispunct_func },
221− { "space", &tre_isspace_func },
222− { "upper", &tre_isupper_func },
223− { "xdigit", &tre_isxdigit_func },
224− { NULL, NULL}
225−};
226−
227−tre_ctype_t tre_ctype(const char *name)
228−{
229− int i;
230− for (i = 0; tre_ctype_map[i].name != NULL; i++)
231− {
232− if (strcmp(name, tre_ctype_map[i].name) == 0)
233− return tre_ctype_map[i].func;
234− }
235− return (tre_ctype_t)0;
236−}
237−#endif /* !TRE_USE_SYSTEM_WCTYPE */
238−
239−/* Maximum number of character classes that can occur in a negated bracket
240− expression. */
241−#define MAX_NEG_CLASSES 64
242−
243−/* Maximum length of character class names. */
244−#define MAX_CLASS_NAME
245−
246−#define REST(re) (int)(ctx->re_end - (re)), (re)
247−
248−static reg_errcode_t
249−tre_parse_bracket_items(tre_parse_ctx_t *ctx, int negate,
250− tre_ctype_t neg_classes[], int *num_neg_classes,
251− tre_ast_node_t ***items, int *num_items,
252− int *items_size)
253−{
254− const tre_char_t *re = ctx->re;
255− reg_errcode_t status = REG_OK;
256− tre_ctype_t class = (tre_ctype_t)0;
257− int i = *num_items;
258− int max_i = *items_size;
259− int skip;
260−
261− /* Build an array of the items in the bracket expression. */
262− while (status == REG_OK)
263− {
264− skip = 0;
265− if (re == ctx->re_end)
266− {
267− status = REG_EBRACK;
268− }
269− else if (*re == CHAR_RBRACKET && re > ctx->re)
270− {
271− DPRINT(("tre_parse_bracket: done: '%.*" STRF "'\n", REST(re)));
272− re++;
273− break;
274− }
275− else
276− {
277− tre_cint_t min = 0, max = 0;
278−
279− class = (tre_ctype_t)0;
280− if (re + 2 < ctx->re_end
281− && *(re + 1) == CHAR_MINUS && *(re + 2) != CHAR_RBRACKET)
282− {
283− DPRINT(("tre_parse_bracket: range: '%.*" STRF "'\n", REST(re)));
284− min = *re;
285− max = *(re + 2);
286− re += 3;
287− /* XXX - Should use collation order instead of encoding values
288− in character ranges. */
289− if (min > max)
290− status = REG_ERANGE;
291− }
292− else if (re + 1 < ctx->re_end
293− && *re == CHAR_LBRACKET && *(re + 1) == CHAR_PERIOD)
294− status = REG_ECOLLATE;
295− else if (re + 1 < ctx->re_end
296− && *re == CHAR_LBRACKET && *(re + 1) == CHAR_EQUAL)
297− status = REG_ECOLLATE;
298− else if (re + 1 < ctx->re_end
299− && *re == CHAR_LBRACKET && *(re + 1) == CHAR_COLON)
300− {
301− char tmp_str[64];
302− const tre_char_t *endptr = re + 2;
303− int len;
304− DPRINT(("tre_parse_bracket: class: '%.*" STRF "'\n", REST(re)));
305− while (endptr < ctx->re_end && *endptr != CHAR_COLON)
306− endptr++;
307− if (endptr != ctx->re_end)
308− {
309− len = MIN(endptr - re - 2, 63);
310−#ifdef TRE_WCHAR
311− {
312− tre_char_t tmp_wcs[64];
313− wcsncpy(tmp_wcs, re + 2, (size_t)len);
314− tmp_wcs[len] = L'\0';
315−#if defined HAVE_WCSRTOMBS
316− {
317− mbstate_t state;
318− const tre_char_t *src = tmp_wcs;
319− memset(&state, '\0', sizeof(state));
320− len = wcsrtombs(tmp_str, &src, sizeof(tmp_str), &state);
321− }
322−#elif defined HAVE_WCSTOMBS
323− len = wcstombs(tmp_str, tmp_wcs, 63);
324−#endif /* defined HAVE_WCSTOMBS */
325− }
326−#else /* !TRE_WCHAR */
327− strncpy(tmp_str, (const char*)re + 2, len);
328−#endif /* !TRE_WCHAR */
329− tmp_str[len] = '\0';
330− DPRINT((" class name: %s\n", tmp_str));
331− class = tre_ctype(tmp_str);
332− if (!class)
333− status = REG_ECTYPE;
334− /* Optimize character classes for 8 bit character sets. */
335− if (status == REG_OK && TRE_MB_CUR_MAX == 1)
336− {
337− status = tre_expand_ctype(ctx->mem, class, items,
338− &i, &max_i, ctx->cflags);
339− class = (tre_ctype_t)0;
340− skip = 1;
341− }
342− re = endptr + 2;
343− }
344− else
345− status = REG_ECTYPE;
346− min = 0;
347− max = TRE_CHAR_MAX;
348− }
349− else
350− {
351− DPRINT(("tre_parse_bracket: char: '%.*" STRF "'\n", REST(re)));
352− if (*re == CHAR_MINUS && *(re + 1) != CHAR_RBRACKET
353− && ctx->re != re)
354− /* Two ranges are not allowed to share and endpoint. */
355− status = REG_ERANGE;
356− min = max = *re++;
357− }
358−
359− if (status != REG_OK)
360− break;
361−
362− if (class && negate)
363− if (*num_neg_classes >= MAX_NEG_CLASSES)
364− status = REG_ESPACE;
365− else
366− neg_classes[(*num_neg_classes)++] = class;
367− else if (!skip)
368− {
369− status = tre_new_item(ctx->mem, min, max, &i, &max_i, items);
370− if (status != REG_OK)
371− break;
372− ((tre_literal_t*)((*items)[i-1])->obj)->u.class = class;
373− }
374−
375− /* Add opposite-case counterpoints if REG_ICASE is present.
376− This is broken if there are more than two "same" characters. */
377− if (ctx->cflags & REG_ICASE && !class && status == REG_OK && !skip)
378− {
379− tre_cint_t cmin, ccurr;
380−
381− DPRINT(("adding opposite-case counterpoints\n"));
382− while (min <= max)
383− {
384− if (tre_islower(min))
385− {
386− cmin = ccurr = tre_toupper(min++);
387− while (tre_islower(min) && tre_toupper(min) == ccurr + 1
388− && min <= max)
389− ccurr = tre_toupper(min++);
390− status = tre_new_item(ctx->mem, cmin, ccurr,
391− &i, &max_i, items);
392− }
393− else if (tre_isupper(min))
394− {
395− cmin = ccurr = tre_tolower(min++);
396− while (tre_isupper(min) && tre_tolower(min) == ccurr + 1
397− && min <= max)
398− ccurr = tre_tolower(min++);
399− status = tre_new_item(ctx->mem, cmin, ccurr,
400− &i, &max_i, items);
401− }
402− else min++;
403− if (status != REG_OK)
404− break;
405− }
406− if (status != REG_OK)
407− break;
408− }
409− }
410− }
411− *num_items = i;
412− *items_size = max_i;
413− ctx->re = re;
414− return status;
415−}
416−
417−static reg_errcode_t
418−tre_parse_bracket(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
419−{
420− tre_ast_node_t *node = NULL;
421− int negate = 0;
422− reg_errcode_t status = REG_OK;
423− tre_ast_node_t **items, *u, *n;
424− int i = 0, j, max_i = 32, curr_max, curr_min;
425− tre_ctype_t neg_classes[MAX_NEG_CLASSES];
426− int num_neg_classes = 0;
427−
428− /* Start off with an array of `max_i' elements. */
429− items = xmalloc(sizeof(*items) * max_i);
430− if (items == NULL)
431− return REG_ESPACE;
432−
433− if (*ctx->re == CHAR_CARET)
434− {
435− DPRINT(("tre_parse_bracket: negate: '%.*" STRF "'\n", REST(ctx->re)));
436− negate = 1;
437− ctx->re++;
438− }
439−
440− status = tre_parse_bracket_items(ctx, negate, neg_classes, &num_neg_classes,
441− &items, &i, &max_i);
442−
443− if (status != REG_OK)
444− goto parse_bracket_done;
445−
446− /* Sort the array if we need to negate it. */
447− if (negate)
448− qsort(items, (unsigned)i, sizeof(*items), tre_compare_items);
449−
450− curr_max = curr_min = 0;
451− /* Build a union of the items in the array, negated if necessary. */
452− for (j = 0; j < i && status == REG_OK; j++)
453− {
454− int min, max;
455− tre_literal_t *l = items[j]->obj;
456− min = l->code_min;
457− max = l->code_max;
458−
459− DPRINT(("item: %d - %d, class %ld, curr_max = %d\n",
460− (int)l->code_min, (int)l->code_max, (long)l->u.class, curr_max));
461−
462− if (negate)
463− {
464− if (min < curr_max)
465− {
466− /* Overlap. */
467− curr_max = MAX(max + 1, curr_max);
468− DPRINT(("overlap, curr_max = %d\n", curr_max));
469− l = NULL;
470− }
471− else
472− {
473− /* No overlap. */
474− curr_max = min - 1;
475− if (curr_max >= curr_min)
476− {
477− DPRINT(("no overlap\n"));
478− l->code_min = curr_min;
479− l->code_max = curr_max;
480− }
481− else
482− {
483− DPRINT(("no overlap, zero room\n"));
484− l = NULL;
485− }
486− curr_min = curr_max = max + 1;
487− }
488− }
489−
490− if (l != NULL)
491− {
492− int k;
493− DPRINT(("creating %d - %d\n", (int)l->code_min, (int)l->code_max));
494− l->position = ctx->position;
495− if (num_neg_classes > 0)
496− {
497− l->neg_classes = tre_mem_alloc(ctx->mem,
498− (sizeof(l->neg_classes)
499− * (num_neg_classes + 1)));
500− if (l->neg_classes == NULL)
501− {
502− status = REG_ESPACE;
503− break;
504− }
505− for (k = 0; k < num_neg_classes; k++)
506− l->neg_classes[k] = neg_classes[k];
507− l->neg_classes[k] = (tre_ctype_t)0;
508− }
509− else
510− l->neg_classes = NULL;
511− if (node == NULL)
512− node = items[j];
513− else
514− {
515− u = tre_ast_new_union(ctx->mem, node, items[j]);
516− if (u == NULL)
517− status = REG_ESPACE;
518− node = u;
519− }
520− }
521− }
522−
523− if (status != REG_OK)
524− goto parse_bracket_done;
525−
526− if (negate)
527− {
528− int k;
529− DPRINT(("final: creating %d - %d\n", curr_min, (int)TRE_CHAR_MAX));
530− n = tre_ast_new_literal(ctx->mem, curr_min, TRE_CHAR_MAX, ctx->position);
531− if (n == NULL)
532− status = REG_ESPACE;
533− else
534− {
535− tre_literal_t *l = n->obj;
536− if (num_neg_classes > 0)
537− {
538− l->neg_classes = tre_mem_alloc(ctx->mem,
539− (sizeof(l->neg_classes)
540− * (num_neg_classes + 1)));
541− if (l->neg_classes == NULL)
542− {
543− status = REG_ESPACE;
544− goto parse_bracket_done;
545− }
546− for (k = 0; k < num_neg_classes; k++)
547− l->neg_classes[k] = neg_classes[k];
548− l->neg_classes[k] = (tre_ctype_t)0;
549− }
550− else
551− l->neg_classes = NULL;
552− if (node == NULL)
553− node = n;
554− else
555− {
556− u = tre_ast_new_union(ctx->mem, node, n);
557− if (u == NULL)
558− status = REG_ESPACE;
559− node = u;
560− }
561− }
562− }
563−
564− if (status != REG_OK)
565− goto parse_bracket_done;
566−
567−#ifdef TRE_DEBUG
568− tre_ast_print(node);
569−#endif /* TRE_DEBUG */
570−
571− parse_bracket_done:
572− xfree(items);
573− ctx->position++;
574− *result = node;
575− return status;
576−}
577−
578−
579−/* Parses a positive decimal integer. Returns -1 if the string does not
580− contain a valid number. */
581−static int
582−tre_parse_int(const tre_char_t **regex, const tre_char_t *regex_end)
583−{
584− int num = -1;
585− const tre_char_t *r = *regex;
586− while (r < regex_end && *r >= L'0' && *r <= L'9')
587− {
588− if (num < 0)
589− num = 0;
590− num = num * 10 + *r - L'0';
591− r++;
592− }
593− *regex = r;
594− return num;
595−}
596−
597−
598−static reg_errcode_t
599−tre_parse_bound(tre_parse_ctx_t *ctx, tre_ast_node_t **result)
600−{
601− int min, max, i;
602− int cost_ins, cost_del, cost_subst, cost_max;
603− int limit_ins, limit_del, limit_subst, limit_err;
604− const tre_char_t *r = ctx->re;
605− const tre_char_t *start;
606− int minimal = (ctx->cflags & REG_UNGREEDY) ? 1 : 0;
607− int approx = 0;
608− int costs_set = 0;
609− int counts_set = 0;
610−
611− cost_ins = cost_del = cost_subst = cost_max = TRE_PARAM_UNSET;
612− limit_ins = limit_del = limit_subst = limit_err = TRE_PARAM_UNSET;
613−
614− /* Parse number (minimum repetition count). */
615− min = -1;
616− if (r < ctx->re_end && *r >= L'0' && *r <= L'9') {
617− DPRINT(("tre_parse: min count: '%.*" STRF "'\n", REST(r)));
618− min = tre_parse_int(&r, ctx->re_end);
619− }
620−
621− /* Parse comma and second number (maximum repetition count). */
622− max = min;
623− if (r < ctx->re_end && *r == CHAR_COMMA)
624− {
625− r++;
626− DPRINT(("tre_parse: max count: '%.*" STRF "'\n", REST(r)));
627− max = tre_parse_int(&r, ctx->re_end);
628− }
629−
630− /* Check that the repeat counts are sane. */
631− if ((max >= 0 && min > max) || max > RE_DUP_MAX)
632− return REG_BADBR;
633−
634−
635− /*
636− '{'
637− optionally followed immediately by a number == minimum repcount
638− optionally followed by , then a number == maximum repcount
639− + then a number == maximum insertion count
640− - then a number == maximum deletion count
641− # then a number == maximum substitution count
642− ~ then a number == maximum number of errors
643− Any of +, -, # or ~ without followed by a number means that
644− the maximum count/number of errors is infinite.
645−
646− An equation of the form
647− Xi + Yd + Zs < C
648− can be specified to set costs and the cost limit to a value
649− different from the default value:
650− - X is the cost of an insertion
651− - Y is the cost of a deletion
652− - Z is the cost of a substitution
653− - C is the maximum cost
654−
655− If no count limit or cost is set for an operation, the operation
656− is not allowed at all.
657− */
658−
659−
660− do {
661− int done;
662− start = r;
663−
664− /* Parse count limit settings */
665− done = 0;
666− if (!counts_set)
667− while (r + 1 < ctx->re_end && !done)
668− {
669− switch (*r)
670− {
671− case CHAR_PLUS: /* Insert limit */
672− DPRINT(("tre_parse: ins limit: '%.*" STRF "'\n", REST(r)));
673− r++;
674− limit_ins = tre_parse_int(&r, ctx->re_end);
675− if (limit_ins < 0)
676− limit_ins = INT_MAX;
677− counts_set = 1;
678− break;
679− case CHAR_MINUS: /* Delete limit */
680− DPRINT(("tre_parse: del limit: '%.*" STRF "'\n", REST(r)));
681− r++;
682− limit_del = tre_parse_int(&r, ctx->re_end);
683− if (limit_del < 0)
684− limit_del = INT_MAX;
685− counts_set = 1;
686− break;
687− case CHAR_HASH: /* Substitute limit */
688− DPRINT(("tre_parse: subst limit: '%.*" STRF "'\n", REST(r)));
689− r++;
690− limit_subst = tre_parse_int(&r, ctx->re_end);
691− if (limit_subst < 0)
692− limit_subst = INT_MAX;
693− counts_set = 1;
694− break;
695− case CHAR_TILDE: /* Maximum number of changes */
696− DPRINT(("tre_parse: count limit: '%.*" STRF "'\n", REST(r)));
697− r++;
698− limit_err = tre_parse_int(&r, ctx->re_end);
699− if (limit_err < 0)
700− limit_err = INT_MAX;
701− approx = 1;
702− break;
703− case CHAR_COMMA:
704− r++;
705− break;
706− case L' ':
707− r++;
708− break;
709− case L'}':
710− done = 1;
711− break;
712− default:
713− done = 1;
714− break;
715− }
716− }
717−
718− /* Parse cost restriction equation. */
719− done = 0;
720− if (!costs_set)
721− while (r + 1 < ctx->re_end && !done)
722− {
723− switch (*r)
724− {
725− case CHAR_PLUS:
726− case L' ':
727− r++;
728− break;
729− case L'<':
730− DPRINT(("tre_parse: max cost: '%.*" STRF "'\n", REST(r)));
731− r++;
732− while (*r == L' ')
733− r++;
734− cost_max = tre_parse_int(&r, ctx->re_end);
735− if (cost_max < 0)
736− cost_max = INT_MAX;
737− else
738− cost_max--;
739− approx = 1;
740− break;
741− case CHAR_COMMA:
742− r++;
743− done = 1;
744− break;
745− default:
746− if (*r >= L'0' && *r <= L'9')
747− {
748−#ifdef TRE_DEBUG
749− const tre_char_t *sr = r;
750−#endif /* TRE_DEBUG */
751− int cost = tre_parse_int(&r, ctx->re_end);
752− /* XXX - make sure r is not past end. */
753− switch (*r)
754− {
755− case L'i': /* Insert cost */
756− DPRINT(("tre_parse: ins cost: '%.*" STRF "'\n",
757− REST(sr)));
758− r++;
759− cost_ins = cost;
760− costs_set = 1;
761− break;
762− case L'd': /* Delete cost */
763− DPRINT(("tre_parse: del cost: '%.*" STRF "'\n",
764− REST(sr)));
765− r++;
766− cost_del = cost;
767− costs_set = 1;
768− break;
769− case L's': /* Substitute cost */
770− DPRINT(("tre_parse: subst cost: '%.*" STRF "'\n",
771− REST(sr)));
772− r++;
773− cost_subst = cost;
774− costs_set = 1;
775− break;
776− default:
777− return REG_BADBR;
778− }
779− }
780− else
781− {
782− done = 1;
783− break;
784− }
785− }
786− }
787− } while (start != r);
788−
789− /* Missing }. */
790− if (r >= ctx->re_end)
791− return REG_EBRACE;
792−
793− /* Empty contents of {}. */
794− if (r == ctx->re)
795− return REG_BADBR;
796−
797− /* Parse the ending '}' or '\}'.*/
798− if (ctx->cflags & REG_EXTENDED)
799− {
800− if (r >= ctx->re_end || *r != CHAR_RBRACE)
801− return REG_BADBR;
802− r++;
803− }
804− else
805− {
806− if (r + 1 >= ctx->re_end
807− || *r != CHAR_BACKSLASH
808− || *(r + 1) != CHAR_RBRACE)
809− return REG_BADBR;
810− r += 2;
811− }
812−
813−
814− /* Parse trailing '?' marking minimal repetition. */
815− if (r < ctx->re_end)
816− {
817− if (*r == CHAR_QUESTIONMARK)
818− {
819− minimal = !(ctx->cflags & REG_UNGREEDY);
820− r++;
821− }
822− else if (*r == CHAR_STAR || *r == CHAR_PLUS)
823− {
824− /* These are reserved for future extensions. */
825− return REG_BADRPT;
826− }
827− }
828−
829− /* Create the AST node(s). */
830− if (min == 0 && max == 0)
831− {
832− *result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
833− if (*result == NULL)
834− return REG_ESPACE;
835− }
836− else
837− {
838− if (min < 0 && max < 0)
839− /* Only approximate parameters set, no repetitions. */
840− min = max = 1;
841−
842− *result = tre_ast_new_iter(ctx->mem, *result, min, max, minimal);
843− if (!*result)
844− return REG_ESPACE;
845−
846− /* If approximate matching parameters are set, add them to the
847− iteration node. */
848− if (approx || costs_set || counts_set)
849− {
850− int *params;
851− tre_iteration_t *iter = (*result)->obj;
852−
853− if (costs_set || counts_set)
854− {
855− if (limit_ins == TRE_PARAM_UNSET)
856− {
857− if (cost_ins == TRE_PARAM_UNSET)
858− limit_ins = 0;
859− else
860− limit_ins = INT_MAX;
861− }
862−
863− if (limit_del == TRE_PARAM_UNSET)
864− {
865− if (cost_del == TRE_PARAM_UNSET)
866− limit_del = 0;
867− else
868− limit_del = INT_MAX;
869− }
870−
871− if (limit_subst == TRE_PARAM_UNSET)
872− {
873− if (cost_subst == TRE_PARAM_UNSET)
874− limit_subst = 0;
875− else
876− limit_subst = INT_MAX;
877− }
878− }
879−
880− if (cost_max == TRE_PARAM_UNSET)
881− cost_max = INT_MAX;
882− if (limit_err == TRE_PARAM_UNSET)
883− limit_err = INT_MAX;
884−
885− ctx->have_approx = 1;
886− params = tre_mem_alloc(ctx->mem, sizeof(*params) * TRE_PARAM_LAST);
887− if (!params)
888− return REG_ESPACE;
889− for (i = 0; i < TRE_PARAM_LAST; i++)
890− params[i] = TRE_PARAM_UNSET;
891− params[TRE_PARAM_COST_INS] = cost_ins;
892− params[TRE_PARAM_COST_DEL] = cost_del;
893− params[TRE_PARAM_COST_SUBST] = cost_subst;
894− params[TRE_PARAM_COST_MAX] = cost_max;
895− params[TRE_PARAM_MAX_INS] = limit_ins;
896− params[TRE_PARAM_MAX_DEL] = limit_del;
897− params[TRE_PARAM_MAX_SUBST] = limit_subst;
898− params[TRE_PARAM_MAX_ERR] = limit_err;
899− iter->params = params;
900− }
901− }
902−
903− DPRINT(("tre_parse_bound: min %d, max %d, costs [%d,%d,%d, total %d], "
904− "limits [%d,%d,%d, total %d]\n",
905− min, max, cost_ins, cost_del, cost_subst, cost_max,
906− limit_ins, limit_del, limit_subst, limit_err));
907−
908−
909− ctx->re = r;
910− return REG_OK;
911−}
912−
913−typedef enum {
914− PARSE_RE = 0,
915− PARSE_ATOM,
916− PARSE_MARK_FOR_SUBMATCH,
917− PARSE_BRANCH,
918− PARSE_PIECE,
919− PARSE_CATENATION,
920− PARSE_POST_CATENATION,
921− PARSE_UNION,
922− PARSE_POST_UNION,
923− PARSE_POSTFIX,
924− PARSE_RESTORE_CFLAGS
925−} tre_parse_re_stack_symbol_t;
926−
927−
928−reg_errcode_t
929−tre_parse(tre_parse_ctx_t *ctx)
930−{
931− tre_ast_node_t *result = NULL;
932− tre_parse_re_stack_symbol_t symbol;
933− reg_errcode_t status = REG_OK;
934− tre_stack_t *stack = ctx->stack;
935− int bottom = tre_stack_num_objects(stack);
936− int depth = 0;
937− int temporary_cflags = 0;
938−
939− DPRINT(("tre_parse: parsing '%.*" STRF "', len = %d\n",
940− ctx->len, ctx->re, ctx->len));
941−
942− if (!ctx->nofirstsub)
943− {
944− STACK_PUSH(stack, int, ctx->submatch_id);
945− STACK_PUSH(stack, int, PARSE_MARK_FOR_SUBMATCH);
946− ctx->submatch_id++;
947− }
948− STACK_PUSH(stack, int, PARSE_RE);
949− ctx->re_start = ctx->re;
950− ctx->re_end = ctx->re + ctx->len;
951−
952−
953− /* The following is basically just a recursive descent parser. I use
954− an explicit stack instead of recursive functions mostly because of
955− two reasons: compatibility with systems which have an overflowable
956− call stack, and efficiency (both in lines of code and speed). */
957− while (tre_stack_num_objects(stack) > bottom && status == REG_OK)
958− {
959− if (status != REG_OK)
960− break;
961− symbol = tre_stack_pop_int(stack);
962− switch (symbol)
963− {
964− case PARSE_RE:
965− /* Parse a full regexp. A regexp is one or more branches,
966− separated by the union operator `|'. */
967−#ifdef REG_LITERAL
968− if (!(ctx->cflags & REG_LITERAL)
969− && ctx->cflags & REG_EXTENDED)
970−#endif /* REG_LITERAL */
971− STACK_PUSHX(stack, int, PARSE_UNION);
972− STACK_PUSHX(stack, int, PARSE_BRANCH);
973− break;
974−
975− case PARSE_BRANCH:
976− /* Parse a branch. A branch is one or more pieces, concatenated.
977− A piece is an atom possibly followed by a postfix operator. */
978− STACK_PUSHX(stack, int, PARSE_CATENATION);
979− STACK_PUSHX(stack, int, PARSE_PIECE);
980− break;
981−
982− case PARSE_PIECE:
983− /* Parse a piece. A piece is an atom possibly followed by one
984− or more postfix operators. */
985−#ifdef REG_LITERAL
986− if (!(ctx->cflags & REG_LITERAL))
987−#endif /* REG_LITERAL */
988− STACK_PUSHX(stack, int, PARSE_POSTFIX);
989− STACK_PUSHX(stack, int, PARSE_ATOM);
990− break;
991−
992− case PARSE_CATENATION:
993− /* If the expression has not ended, parse another piece. */
994− {
995− tre_char_t c;
996− if (ctx->re >= ctx->re_end)
997− break;
998− c = *ctx->re;
999−#ifdef REG_LITERAL
1000− if (!(ctx->cflags & REG_LITERAL))
1001− {
1002−#endif /* REG_LITERAL */
1003− if (ctx->cflags & REG_EXTENDED && c == CHAR_PIPE)
1004− break;
1005− if ((ctx->cflags & REG_EXTENDED
1006− && c == CHAR_RPAREN && depth > 0)
1007− || (!(ctx->cflags & REG_EXTENDED)
1008− && (c == CHAR_BACKSLASH
1009− && *(ctx->re + 1) == CHAR_RPAREN)))
1010− {
1011− if (!(ctx->cflags & REG_EXTENDED) && depth == 0)
1012− status = REG_EPAREN;
1013− DPRINT(("tre_parse: group end: '%.*" STRF "'\n",
1014− REST(ctx->re)));
1015− depth--;
1016− if (!(ctx->cflags & REG_EXTENDED))
1017− ctx->re += 2;
1018− break;
1019− }
1020−#ifdef REG_LITERAL
1021− }
1022−#endif /* REG_LITERAL */
1023−
1024−#ifdef REG_RIGHT_ASSOC
1025− if (ctx->cflags & REG_RIGHT_ASSOC)
1026− {
1027− /* Right associative concatenation. */
1028− STACK_PUSHX(stack, voidptr, result);
1029− STACK_PUSHX(stack, int, PARSE_POST_CATENATION);
1030− STACK_PUSHX(stack, int, PARSE_CATENATION);
1031− STACK_PUSHX(stack, int, PARSE_PIECE);
1032− }
1033− else
1034−#endif /* REG_RIGHT_ASSOC */
1035− {
1036− /* Default case, left associative concatenation. */
1037− STACK_PUSHX(stack, int, PARSE_CATENATION);
1038− STACK_PUSHX(stack, voidptr, result);
1039− STACK_PUSHX(stack, int, PARSE_POST_CATENATION);
1040− STACK_PUSHX(stack, int, PARSE_PIECE);
1041− }
1042− break;
1043− }
1044−
1045− case PARSE_POST_CATENATION:
1046− {
1047− tre_ast_node_t *tree = tre_stack_pop_voidptr(stack);
1048− tre_ast_node_t *tmp_node;
1049− tmp_node = tre_ast_new_catenation(ctx->mem, tree, result);
1050− if (!tmp_node)
1051− return REG_ESPACE;
1052− result = tmp_node;
1053− break;
1054− }
1055−
1056− case PARSE_UNION:
1057− if (ctx->re >= ctx->re_end)
1058− break;
1059−#ifdef REG_LITERAL
1060− if (ctx->cflags & REG_LITERAL)
1061− break;
1062−#endif /* REG_LITERAL */
1063− switch (*ctx->re)
1064− {
1065− case CHAR_PIPE:
1066− DPRINT(("tre_parse: union: '%.*" STRF "'\n",
1067− REST(ctx->re)));
1068− STACK_PUSHX(stack, int, PARSE_UNION);
1069− STACK_PUSHX(stack, voidptr, result);
1070− STACK_PUSHX(stack, int, PARSE_POST_UNION);
1071− STACK_PUSHX(stack, int, PARSE_BRANCH);
1072− ctx->re++;
1073− break;
1074−
1075− case CHAR_RPAREN:
1076− ctx->re++;
1077− break;
1078−
1079− default:
1080− break;
1081− }
1082− break;
1083−
1084− case PARSE_POST_UNION:
1085− {
1086− tre_ast_node_t *tmp_node;
1087− tre_ast_node_t *tree = tre_stack_pop_voidptr(stack);
1088− tmp_node = tre_ast_new_union(ctx->mem, tree, result);
1089− if (!tmp_node)
1090− return REG_ESPACE;
1091− result = tmp_node;
1092− break;
1093− }
1094−
1095− case PARSE_POSTFIX:
1096− /* Parse postfix operators. */
1097− if (ctx->re >= ctx->re_end)
1098− break;
1099−#ifdef REG_LITERAL
1100− if (ctx->cflags & REG_LITERAL)
1101− break;
1102−#endif /* REG_LITERAL */
1103− switch (*ctx->re)
1104− {
1105− case CHAR_PLUS:
1106− case CHAR_QUESTIONMARK:
1107− if (!(ctx->cflags & REG_EXTENDED))
1108− break;
1109− /*FALLTHROUGH*/
1110− case CHAR_STAR:
1111− {
1112− tre_ast_node_t *tmp_node;
1113− int minimal = (ctx->cflags & REG_UNGREEDY) ? 1 : 0;
1114− int rep_min = 0;
1115− int rep_max = -1;
1116−#ifdef TRE_DEBUG
1117− const tre_char_t *tmp_re;
1118−#endif
1119−
1120− if (*ctx->re == CHAR_PLUS)
1121− rep_min = 1;
1122− if (*ctx->re == CHAR_QUESTIONMARK)
1123− rep_max = 1;
1124−#ifdef TRE_DEBUG
1125− tmp_re = ctx->re;
1126−#endif
1127−
1128− if (ctx->re + 1 < ctx->re_end)
1129− {
1130− if (*(ctx->re + 1) == CHAR_QUESTIONMARK)
1131− {
1132− minimal = !(ctx->cflags & REG_UNGREEDY);
1133− ctx->re++;
1134− }
1135− else if (*(ctx->re + 1) == CHAR_STAR
1136− || *(ctx->re + 1) == CHAR_PLUS)
1137− {
1138− /* These are reserved for future extensions. */
1139− return REG_BADRPT;
1140− }
1141− }
1142−
1143− DPRINT(("tre_parse: %s star: '%.*" STRF "'\n",
1144− minimal ? " minimal" : "greedy", REST(tmp_re)));
1145− ctx->re++;
1146− tmp_node = tre_ast_new_iter(ctx->mem, result, rep_min, rep_max,
1147− minimal);
1148− if (tmp_node == NULL)
1149− return REG_ESPACE;
1150− result = tmp_node;
1151− STACK_PUSHX(stack, int, PARSE_POSTFIX);
1152− }
1153− break;
1154−
1155− case CHAR_BACKSLASH:
1156− /* "\{" is special without REG_EXTENDED */
1157− if (!(ctx->cflags & REG_EXTENDED)
1158− && ctx->re + 1 < ctx->re_end
1159− && *(ctx->re + 1) == CHAR_LBRACE)
1160− {
1161− ctx->re++;
1162− goto parse_brace;
1163− }
1164− else
1165− break;
1166−
1167− case CHAR_LBRACE:
1168− /* "{" is literal without REG_EXTENDED */
1169− if (!(ctx->cflags & REG_EXTENDED))
1170− break;
1171−
1172− parse_brace:
1173− DPRINT(("tre_parse: bound: '%.*" STRF "'\n",
1174− REST(ctx->re)));
1175− ctx->re++;
1176−
1177− status = tre_parse_bound(ctx, &result);
1178− if (status != REG_OK)
1179− return status;
1180− STACK_PUSHX(stack, int, PARSE_POSTFIX);
1181− break;
1182− }
1183− break;
1184−
1185− case PARSE_ATOM:
1186− /* Parse an atom. An atom is a regular expression enclosed in `()',
1187− an empty set of `()', a bracket expression, `.', `^', `$',
1188− a `\' followed by a character, or a single character. */
1189−
1190− /* End of regexp? (empty string). */
1191− if (ctx->re >= ctx->re_end)
1192− goto parse_literal;
1193−
1194−#ifdef REG_LITERAL
1195− if (ctx->cflags & REG_LITERAL)
1196− goto parse_literal;
1197−#endif /* REG_LITERAL */
1198−
1199− switch (*ctx->re)
1200− {
1201− case CHAR_LPAREN: /* parenthesized subexpression */
1202−
1203− /* Handle "(?...)" extensions. They work in a way similar
1204− to Perls corresponding extensions. */
1205− if (ctx->cflags & REG_EXTENDED
1206− && *(ctx->re + 1) == CHAR_QUESTIONMARK)
1207− {
1208− int new_cflags = ctx->cflags;
1209− int bit = 1;
1210− DPRINT(("tre_parse: extension: '%.*" STRF "\n",
1211− REST(ctx->re)));
1212− ctx->re += 2;
1213− while (/*CONSTCOND*/1)
1214− {
1215− if (*ctx->re == L'i')
1216− {
1217− DPRINT(("tre_parse: icase: '%.*" STRF "\n",
1218− REST(ctx->re)));
1219− if (bit)
1220− new_cflags |= REG_ICASE;
1221− else
1222− new_cflags &= ~REG_ICASE;
1223− ctx->re++;
1224− }
1225− else if (*ctx->re == L'n')
1226− {
1227− DPRINT(("tre_parse: newline: '%.*" STRF "\n",
1228− REST(ctx->re)));
1229− if (bit)
1230− new_cflags |= REG_NEWLINE;
1231− else
1232− new_cflags &= ~REG_NEWLINE;
1233− ctx->re++;
1234− }
1235−#ifdef REG_RIGHT_ASSOC
1236− else if (*ctx->re == L'r')
1237− {
1238− DPRINT(("tre_parse: right assoc: '%.*" STRF "\n",
1239− REST(ctx->re)));
1240− if (bit)
1241− new_cflags |= REG_RIGHT_ASSOC;
1242− else
1243− new_cflags &= ~REG_RIGHT_ASSOC;
1244− ctx->re++;
1245− }
1246−#endif /* REG_RIGHT_ASSOC */
1247−#ifdef REG_UNGREEDY
1248− else if (*ctx->re == L'U')
1249− {
1250− DPRINT(("tre_parse: ungreedy: '%.*" STRF "\n",
1251− REST(ctx->re)));
1252− if (bit)
1253− new_cflags |= REG_UNGREEDY;
1254− else
1255− new_cflags &= ~REG_UNGREEDY;
1256− ctx->re++;
1257− }
1258−#endif /* REG_UNGREEDY */
1259− else if (*ctx->re == CHAR_MINUS)
1260− {
1261− DPRINT(("tre_parse: turn off: '%.*" STRF "\n",
1262− REST(ctx->re)));
1263− ctx->re++;
1264− bit = 0;
1265− }
1266− else if (*ctx->re == CHAR_COLON)
1267− {
1268− DPRINT(("tre_parse: no group: '%.*" STRF "\n",
1269− REST(ctx->re)));
1270− ctx->re++;
1271− depth++;
1272− break;
1273− }
1274− else if (*ctx->re == CHAR_HASH)
1275− {
1276− DPRINT(("tre_parse: comment: '%.*" STRF "\n",
1277− REST(ctx->re)));
1278− /* A comment can contain any character except a
1279− right parenthesis */
1280− while (*ctx->re != CHAR_RPAREN
1281− && ctx->re < ctx->re_end)
1282− ctx->re++;
1283− if (*ctx->re == CHAR_RPAREN && ctx->re < ctx->re_end)
1284− {
1285− ctx->re++;
1286− break;
1287− }
1288− else
1289− return REG_BADPAT;
1290− }
1291− else if (*ctx->re == CHAR_RPAREN)
1292− {
1293− ctx->re++;
1294− break;
1295− }
1296− else
1297− return REG_BADPAT;
1298− }
1299−
1300− /* Turn on the cflags changes for the rest of the
1301− enclosing group. */
1302− STACK_PUSHX(stack, int, ctx->cflags);
1303− STACK_PUSHX(stack, int, PARSE_RESTORE_CFLAGS);
1304− STACK_PUSHX(stack, int, PARSE_RE);
1305− ctx->cflags = new_cflags;
1306− break;
1307− }
1308−
1309− if (ctx->cflags & REG_EXTENDED
1310− || (ctx->re > ctx->re_start
1311− && *(ctx->re - 1) == CHAR_BACKSLASH))
1312− {
1313− depth++;
1314− if (ctx->re + 2 < ctx->re_end
1315− && *(ctx->re + 1) == CHAR_QUESTIONMARK
1316− && *(ctx->re + 2) == CHAR_COLON)
1317− {
1318− DPRINT(("tre_parse: group begin: '%.*" STRF
1319− "', no submatch\n", REST(ctx->re)));
1320− /* Don't mark for submatching. */
1321− ctx->re += 3;
1322− STACK_PUSHX(stack, int, PARSE_RE);
1323− }
1324− else
1325− {
1326− DPRINT(("tre_parse: group begin: '%.*" STRF
1327− "', submatch %d\n", REST(ctx->re),
1328− ctx->submatch_id));
1329− ctx->re++;
1330− /* First parse a whole RE, then mark the resulting tree
1331− for submatching. */
1332− STACK_PUSHX(stack, int, ctx->submatch_id);
1333− STACK_PUSHX(stack, int, PARSE_MARK_FOR_SUBMATCH);
1334− STACK_PUSHX(stack, int, PARSE_RE);
1335− ctx->submatch_id++;
1336− }
1337− }
1338− else
1339− goto parse_literal;
1340− break;
1341−
1342− case CHAR_RPAREN: /* end of current subexpression */
1343− if ((ctx->cflags & REG_EXTENDED && depth > 0)
1344− || (ctx->re > ctx->re_start
1345− && *(ctx->re - 1) == CHAR_BACKSLASH))
1346− {
1347− DPRINT(("tre_parse: empty: '%.*" STRF "'\n",
1348− REST(ctx->re)));
1349− /* We were expecting an atom, but instead the current
1350− subexpression was closed. POSIX leaves the meaning of
1351− this to be implementation-defined. We interpret this as
1352− an empty expression (which matches an empty string). */
1353− result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
1354− if (result == NULL)
1355− return REG_ESPACE;
1356− if (!(ctx->cflags & REG_EXTENDED))
1357− ctx->re--;
1358− }
1359− else
1360− goto parse_literal;
1361− break;
1362−
1363− case CHAR_LBRACKET: /* bracket expression */
1364− DPRINT(("tre_parse: bracket: '%.*" STRF "'\n",
1365− REST(ctx->re)));
1366− ctx->re++;
1367− status = tre_parse_bracket(ctx, &result);
1368− if (status != REG_OK)
1369− return status;
1370− break;
1371−
1372− case CHAR_BACKSLASH:
1373− /* If this is "\(" or "\)" chew off the backslash and
1374− try again. */
1375− if (!(ctx->cflags & REG_EXTENDED)
1376− && ctx->re + 1 < ctx->re_end
1377− && (*(ctx->re + 1) == CHAR_LPAREN
1378− || *(ctx->re + 1) == CHAR_RPAREN))
1379− {
1380− ctx->re++;
1381− STACK_PUSHX(stack, int, PARSE_ATOM);
1382− break;
1383− }
1384−
1385− /* If a macro is used, parse the expanded macro recursively. */
1386− {
1387− tre_char_t buf[64];
1388− tre_expand_macro(ctx->re + 1, ctx->re_end,
1389− buf, elementsof(buf));
1390− if (buf[0] != 0)
1391− {
1392− tre_parse_ctx_t subctx;
1393− memcpy(&subctx, ctx, sizeof(subctx));
1394− subctx.re = buf;
1395− subctx.len = tre_strlen(buf);
1396− subctx.nofirstsub = 1;
1397− status = tre_parse(&subctx);
1398− if (status != REG_OK)
1399− return status;
1400− ctx->re += 2;
1401− ctx->position = subctx.position;
1402− result = subctx.result;
1403− break;
1404− }
1405− }
1406−
1407− if (ctx->re + 1 >= ctx->re_end)
1408− /* Trailing backslash. */
1409− return REG_EESCAPE;
1410−
1411−#ifdef REG_LITERAL
1412− if (*(ctx->re + 1) == L'Q')
1413− {
1414− DPRINT(("tre_parse: tmp literal: '%.*" STRF "'\n",
1415− REST(ctx->re)));
1416− ctx->cflags |= REG_LITERAL;
1417− temporary_cflags |= REG_LITERAL;
1418− ctx->re += 2;
1419− STACK_PUSHX(stack, int, PARSE_ATOM);
1420− break;
1421− }
1422−#endif /* REG_LITERAL */
1423−
1424− DPRINT(("tre_parse: bleep: '%.*" STRF "'\n", REST(ctx->re)));
1425− ctx->re++;
1426− switch (*ctx->re)
1427− {
1428− case L'b':
1429− result = tre_ast_new_literal(ctx->mem, ASSERTION,
1430− ASSERT_AT_WB, -1);
1431− ctx->re++;
1432− break;
1433− case L'B':
1434− result = tre_ast_new_literal(ctx->mem, ASSERTION,
1435− ASSERT_AT_WB_NEG, -1);
1436− ctx->re++;
1437− break;
1438− case L'<':
1439− result = tre_ast_new_literal(ctx->mem, ASSERTION,
1440− ASSERT_AT_BOW, -1);
1441− ctx->re++;
1442− break;
1443− case L'>':
1444− result = tre_ast_new_literal(ctx->mem, ASSERTION,
1445− ASSERT_AT_EOW, -1);
1446− ctx->re++;
1447− break;
1448− case L'x':
1449− ctx->re++;
1450− if (ctx->re[0] != CHAR_LBRACE && ctx->re < ctx->re_end)
1451− {
1452− /* 8 bit hex char. */
1453− char tmp[3] = {0, 0, 0};
1454− long val;
1455− DPRINT(("tre_parse: 8 bit hex: '%.*" STRF "'\n",
1456− REST(ctx->re - 2)));
1457−
1458− if (tre_isxdigit(ctx->re[0]) && ctx->re < ctx->re_end)
1459− {
1460− tmp[0] = (char)ctx->re[0];
1461− ctx->re++;
1462− }
1463− if (tre_isxdigit(ctx->re[0]) && ctx->re < ctx->re_end)
1464− {
1465− tmp[1] = (char)ctx->re[0];
1466− ctx->re++;
1467− }
1468− val = strtol(tmp, NULL, 16);
1469− result = tre_ast_new_literal(ctx->mem, (int)val,
1470− (int)val, ctx->position);
1471− ctx->position++;
1472− break;
1473− }
1474− else if (ctx->re < ctx->re_end)
1475− {
1476− /* Wide char. */
1477− char tmp[32];
1478− long val;
1479− int i = 0;
1480− ctx->re++;
1481− while (ctx->re_end - ctx->re >= 0)
1482− {
1483− if (ctx->re[0] == CHAR_RBRACE)
1484− break;
1485− if (tre_isxdigit(ctx->re[0]))
1486− {
1487− tmp[i] = (char)ctx->re[0];
1488− i++;
1489− ctx->re++;
1490− continue;
1491− }
1492− return REG_EBRACE;
1493− }
1494− ctx->re++;
1495− tmp[i] = 0;
1496− val = strtol(tmp, NULL, 16);
1497− result = tre_ast_new_literal(ctx->mem, (int)val, (int)val,
1498− ctx->position);
1499− ctx->position++;
1500− break;
1501− }
1502− /*FALLTHROUGH*/
1503−
1504− default:
1505− if (tre_isdigit(*ctx->re))
1506− {
1507− /* Back reference. */
1508− int val = *ctx->re - L'0';
1509− DPRINT(("tre_parse: backref: '%.*" STRF "'\n",
1510− REST(ctx->re - 1)));
1511− result = tre_ast_new_literal(ctx->mem, BACKREF, val,
1512− ctx->position);
1513− if (result == NULL)
1514− return REG_ESPACE;
1515− ctx->position++;
1516− ctx->max_backref = MAX(val, ctx->max_backref);
1517− ctx->re++;
1518− }
1519− else
1520− {
1521− /* Escaped character. */
1522− DPRINT(("tre_parse: escaped: '%.*" STRF "'\n",
1523− REST(ctx->re - 1)));
1524− result = tre_ast_new_literal(ctx->mem, *ctx->re, *ctx->re,
1525− ctx->position);
1526− ctx->position++;
1527− ctx->re++;
1528− }
1529− break;
1530− }
1531− if (result == NULL)
1532− return REG_ESPACE;
1533− break;
1534−
1535− case CHAR_PERIOD: /* the any-symbol */
1536− DPRINT(("tre_parse: any: '%.*" STRF "'\n",
1537− REST(ctx->re)));
1538− if (ctx->cflags & REG_NEWLINE)
1539− {
1540− tre_ast_node_t *tmp1;
1541− tre_ast_node_t *tmp2;
1542− tmp1 = tre_ast_new_literal(ctx->mem, 0, L'\n' - 1,
1543− ctx->position);
1544− if (!tmp1)
1545− return REG_ESPACE;
1546− tmp2 = tre_ast_new_literal(ctx->mem, L'\n' + 1, TRE_CHAR_MAX,
1547− ctx->position + 1);
1548− if (!tmp2)
1549− return REG_ESPACE;
1550− result = tre_ast_new_union(ctx->mem, tmp1, tmp2);
1551− if (!result)
1552− return REG_ESPACE;
1553− ctx->position += 2;
1554− }
1555− else
1556− {
1557− result = tre_ast_new_literal(ctx->mem, 0, TRE_CHAR_MAX,
1558− ctx->position);
1559− if (!result)
1560− return REG_ESPACE;
1561− ctx->position++;
1562− }
1563− ctx->re++;
1564− break;
1565−
1566− case CHAR_CARET: /* beginning of line assertion */
1567− /* '^' has a special meaning everywhere in EREs, and in the
1568− beginning of the RE and after \( is BREs. */
1569− if (ctx->cflags & REG_EXTENDED
1570− || (ctx->re - 2 >= ctx->re_start
1571− && *(ctx->re - 2) == CHAR_BACKSLASH
1572− && *(ctx->re - 1) == CHAR_LPAREN)
1573− || ctx->re == ctx->re_start)
1574− {
1575− DPRINT(("tre_parse: BOL: '%.*" STRF "'\n",
1576− REST(ctx->re)));
1577− result = tre_ast_new_literal(ctx->mem, ASSERTION,
1578− ASSERT_AT_BOL, -1);
1579− if (result == NULL)
1580− return REG_ESPACE;
1581− ctx->re++;
1582− }
1583− else
1584− goto parse_literal;
1585− break;
1586−
1587− case CHAR_DOLLAR: /* end of line assertion. */
1588− /* '$' is special everywhere in EREs, and in the end of the
1589− string and before \) is BREs. */
1590− if (ctx->cflags & REG_EXTENDED
1591− || (ctx->re + 2 < ctx->re_end
1592− && *(ctx->re + 1) == CHAR_BACKSLASH
1593− && *(ctx->re + 2) == CHAR_RPAREN)
1594− || ctx->re + 1 == ctx->re_end)
1595− {
1596− DPRINT(("tre_parse: EOL: '%.*" STRF "'\n",
1597− REST(ctx->re)));
1598− result = tre_ast_new_literal(ctx->mem, ASSERTION,
1599− ASSERT_AT_EOL, -1);
1600− if (result == NULL)
1601− return REG_ESPACE;
1602− ctx->re++;
1603− }
1604− else
1605− goto parse_literal;
1606− break;
1607−
1608− default:
1609− parse_literal:
1610−
1611− if (temporary_cflags && ctx->re + 1 < ctx->re_end
1612− && *ctx->re == CHAR_BACKSLASH && *(ctx->re + 1) == L'E')
1613− {
1614− DPRINT(("tre_parse: end tmps: '%.*" STRF "'\n",
1615− REST(ctx->re)));
1616− ctx->cflags &= ~temporary_cflags;
1617− temporary_cflags = 0;
1618− ctx->re += 2;
1619− STACK_PUSHX(stack, int, PARSE_PIECE);
1620− break;
1621− }
1622−
1623−
1624− /* We are expecting an atom. If the subexpression (or the whole
1625− regexp ends here, we interpret it as an empty expression
1626− (which matches an empty string). */
1627− if (
1628−#ifdef REG_LITERAL
1629− !(ctx->cflags & REG_LITERAL) &&
1630−#endif /* REG_LITERAL */
1631− (ctx->re >= ctx->re_end
1632− || *ctx->re == CHAR_STAR
1633− || (ctx->cflags & REG_EXTENDED
1634− && (*ctx->re == CHAR_PIPE
1635− || *ctx->re == CHAR_LBRACE
1636− || *ctx->re == CHAR_PLUS
1637− || *ctx->re == CHAR_QUESTIONMARK))
1638− /* Test for "\)" in BRE mode. */
1639− || (!(ctx->cflags & REG_EXTENDED)
1640− && ctx->re + 1 < ctx->re_end
1641− && *ctx->re == CHAR_BACKSLASH
1642− && *(ctx->re + 1) == CHAR_LBRACE)))
1643− {
1644− DPRINT(("tre_parse: empty: '%.*" STRF "'\n",
1645− REST(ctx->re)));
1646− result = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
1647− if (!result)
1648− return REG_ESPACE;
1649− break;
1650− }
1651−
1652− DPRINT(("tre_parse: literal: '%.*" STRF "'\n",
1653− REST(ctx->re)));
1654− /* Note that we can't use an tre_isalpha() test here, since there
1655− may be characters which are alphabetic but neither upper or
1656− lower case. */
1657− if (ctx->cflags & REG_ICASE
1658− && (tre_isupper(*ctx->re) || tre_islower(*ctx->re)))
1659− {
1660− tre_ast_node_t *tmp1;
1661− tre_ast_node_t *tmp2;
1662−
1663− /* XXX - Can there be more than one opposite-case
1664− counterpoints for some character in some locale? Or
1665− more than two characters which all should be regarded
1666− the same character if case is ignored? If yes, there
1667− does not seem to be a portable way to detect it. I guess
1668− that at least for multi-character collating elements there
1669− could be several opposite-case counterpoints, but they
1670− cannot be supported portably anyway. */
1671− tmp1 = tre_ast_new_literal(ctx->mem, tre_toupper(*ctx->re),
1672− tre_toupper(*ctx->re),
1673− ctx->position);
1674− if (!tmp1)
1675− return REG_ESPACE;
1676− tmp2 = tre_ast_new_literal(ctx->mem, tre_tolower(*ctx->re),
1677− tre_tolower(*ctx->re),
1678− ctx->position);
1679− if (!tmp2)
1680− return REG_ESPACE;
1681− result = tre_ast_new_union(ctx->mem, tmp1, tmp2);
1682− if (!result)
1683− return REG_ESPACE;
1684− }
1685− else
1686− {
1687− result = tre_ast_new_literal(ctx->mem, *ctx->re, *ctx->re,
1688− ctx->position);
1689− if (!result)
1690− return REG_ESPACE;
1691− }
1692− ctx->position++;
1693− ctx->re++;
1694− break;
1695− }
1696− break;
1697−
1698− case PARSE_MARK_FOR_SUBMATCH:
1699− {
1700− int submatch_id = tre_stack_pop_int(stack);
1701−
1702− if (result->submatch_id >= 0)
1703− {
1704− tre_ast_node_t *n, *tmp_node;
1705− n = tre_ast_new_literal(ctx->mem, EMPTY, -1, -1);
1706− if (n == NULL)
1707− return REG_ESPACE;
1708− tmp_node = tre_ast_new_catenation(ctx->mem, n, result);
1709− if (tmp_node == NULL)
1710− return REG_ESPACE;
1711− tmp_node->num_submatches = result->num_submatches;
1712− result = tmp_node;
1713− }
1714− result->submatch_id = submatch_id;
1715− result->num_submatches++;
1716− break;
1717− }
1718−
1719− case PARSE_RESTORE_CFLAGS:
1720− ctx->cflags = tre_stack_pop_int(stack);
1721− break;
1722−
1723− default:
1724− assert(0);
1725− break;
1726− }
1727− }
1728−
1729− /* Check for missing closing parentheses. */
1730− if (depth > 0)
1731− return REG_EPAREN;
1732−
1733− if (status == REG_OK)
1734− ctx->result = result;
1735−
1736− return status;
1737−}
1738−
1739−/* EOF */
src/core/regex/tre-parse.h+0−50
@@ -1,50 +0,0 @@
1−/*
2− tre-parse.c - Regexp parser definitions
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−#ifndef TRE_PARSE_H
10−#define TRE_PARSE_H 1
11−
12−/* Parse context. */
13−typedef struct {
14− /* Memory allocator. The AST is allocated using this. */
15− tre_mem_t mem;
16− /* Stack used for keeping track of regexp syntax. */
17− tre_stack_t *stack;
18− /* The parse result. */
19− tre_ast_node_t *result;
20− /* The regexp to parse and its length. */
21− const tre_char_t *re;
22− /* The first character of the entire regexp. */
23− const tre_char_t *re_start;
24− /* The first character after the end of the regexp. */
25− const tre_char_t *re_end;
26− int len;
27− /* Current submatch ID. */
28− int submatch_id;
29− /* Current position (number of literal). */
30− int position;
31− /* The highest back reference or -1 if none seen so far. */
32− int max_backref;
33− /* This flag is set if the regexp uses approximate matching. */
34− int have_approx;
35− /* Compilation flags. */
36− int cflags;
37− /* If this flag is set the top-level submatch is not captured. */
38− int nofirstsub;
39− /* The currently set approximate matching parameters. */
40− int params[TRE_PARAM_LAST];
41−} tre_parse_ctx_t;
42−
43−/* Parses a wide character regexp pattern into a syntax tree. This parser
44− handles both syntaxes (BRE and ERE), including the TRE extensions. */
45−reg_errcode_t
46−tre_parse(tre_parse_ctx_t *ctx);
47−
48−#endif /* TRE_PARSE_H */
49−
50−/* EOF */
src/core/regex/tre-stack.c+0−125
@@ -1,125 +0,0 @@
1−/*
2− tre-stack.c - Simple stack implementation
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−#ifdef HAVE_CONFIG_H
10−#include <config.h>
11−#endif /* HAVE_CONFIG_H */
12−#include <stdlib.h>
13−#include <assert.h>
14−
15−#include "tre-internal.h"
16−#include "tre-stack.h"
17−#include "xmalloc.h"
18−
19−union tre_stack_item {
20− void *voidptr_value;
21− int int_value;
22−};
23−
24−struct tre_stack_rec {
25− int size;
26− int max_size;
27− int increment;
28− int ptr;
29− union tre_stack_item *stack;
30−};
31−
32−
33−tre_stack_t *
34−tre_stack_new(int size, int max_size, int increment)
35−{
36− tre_stack_t *s;
37−
38− s = xmalloc(sizeof(*s));
39− if (s != NULL)
40− {
41− s->stack = xmalloc(sizeof(*s->stack) * size);
42− if (s->stack == NULL)
43− {
44− xfree(s);
45− return NULL;
46− }
47− s->size = size;
48− s->max_size = max_size;
49− s->increment = increment;
50− s->ptr = 0;
51− }
52− return s;
53−}
54−
55−void
56−tre_stack_destroy(tre_stack_t *s)
57−{
58− xfree(s->stack);
59− xfree(s);
60−}
61−
62−int
63−tre_stack_num_objects(tre_stack_t *s)
64−{
65− return s->ptr;
66−}
67−
68−static reg_errcode_t
69−tre_stack_push(tre_stack_t *s, union tre_stack_item value)
70−{
71− if (s->ptr < s->size)
72− {
73− s->stack[s->ptr] = value;
74− s->ptr++;
75− }
76− else
77− {
78− if (s->size >= s->max_size)
79− {
80− DPRINT(("tre_stack_push: stack full\n"));
81− return REG_ESPACE;
82− }
83− else
84− {
85− union tre_stack_item *new_buffer;
86− int new_size;
87− DPRINT(("tre_stack_push: trying to realloc more space\n"));
88− new_size = s->size + s->increment;
89− if (new_size > s->max_size)
90− new_size = s->max_size;
91− new_buffer = xrealloc(s->stack, sizeof(*new_buffer) * new_size);
92− if (new_buffer == NULL)
93− {
94− DPRINT(("tre_stack_push: realloc failed.\n"));
95− return REG_ESPACE;
96− }
97− DPRINT(("tre_stack_push: realloc succeeded.\n"));
98− assert(new_size > s->size);
99− s->size = new_size;
100− s->stack = new_buffer;
101− tre_stack_push(s, value);
102− }
103− }
104− return REG_OK;
105−}
106−
107−#define define_pushf(typetag, type) \
108− declare_pushf(typetag, type) { \
109− union tre_stack_item item; \
110− item.typetag ## _value = value; \
111− return tre_stack_push(s, item); \
112−}
113−
114−define_pushf(int, int)
115−define_pushf(voidptr, void *)
116−
117−#define define_popf(typetag, type) \
118− declare_popf(typetag, type) { \
119− return s->stack[--s->ptr].typetag ## _value; \
120− }
121−
122−define_popf(int, int)
123−define_popf(voidptr, void *)
124−
125−/* EOF */
src/core/regex/tre-stack.h+0−76
@@ -1,76 +0,0 @@
1−/*
2− tre-stack.h: Stack definitions
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−
10−#ifndef TRE_STACK_H
11−#define TRE_STACK_H 1
12−
13−#include "tre.h"
14−
15−typedef struct tre_stack_rec tre_stack_t;
16−
17−/* Creates a new stack object. `size' is initial size in bytes, `max_size'
18− is maximum size, and `increment' specifies how much more space will be
19− allocated with realloc() if all space gets used up. Returns the stack
20− object or NULL if out of memory. */
21−tre_stack_t *
22−tre_stack_new(int size, int max_size, int increment);
23−
24−/* Frees the stack object. */
25−void
26−tre_stack_destroy(tre_stack_t *s);
27−
28−/* Returns the current number of objects in the stack. */
29−int
30−tre_stack_num_objects(tre_stack_t *s);
31−
32−/* Each tre_stack_push_*(tre_stack_t *s, <type> value) function pushes
33− `value' on top of stack `s'. Returns REG_ESPACE if out of memory.
34− This tries to realloc() more space before failing if maximum size
35− has not yet been reached. Returns REG_OK if successful. */
36−#define declare_pushf(typetag, type) \
37− reg_errcode_t tre_stack_push_ ## typetag(tre_stack_t *s, type value)
38−
39−declare_pushf(voidptr, void *);
40−declare_pushf(int, int);
41−
42−/* Each tre_stack_pop_*(tre_stack_t *s) function pops the topmost
43− element off of stack `s' and returns it. The stack must not be
44− empty. */
45−#define declare_popf(typetag, type) \
46− type tre_stack_pop_ ## typetag(tre_stack_t *s)
47−
48−declare_popf(voidptr, void *);
49−declare_popf(int, int);
50−
51−/* Just to save some typing. */
52−#define STACK_PUSH(s, typetag, value) \
53− do \
54− { \
55− status = tre_stack_push_ ## typetag(s, value); \
56− } \
57− while (/*CONSTCOND*/0)
58−
59−#define STACK_PUSHX(s, typetag, value) \
60− { \
61− status = tre_stack_push_ ## typetag(s, value); \
62− if (status != REG_OK) \
63− break; \
64− }
65−
66−#define STACK_PUSHR(s, typetag, value) \
67− { \
68− reg_errcode_t _status; \
69− _status = tre_stack_push_ ## typetag(s, value); \
70− if (_status != REG_OK) \
71− return _status; \
72− }
73−
74−#endif /* TRE_STACK_H */
75−
76−/* EOF */
src/core/regex/tre.h+0−276
@@ -1,276 +0,0 @@
1−/*
2− tre.h - TRE public API definitions
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−#ifndef TRE_H
10−#define TRE_H 1
11−
12−#include "tre-config.h"
13−
14−#ifdef HAVE_SYS_TYPES_H
15−#include <sys/types.h>
16−#endif /* HAVE_SYS_TYPES_H */
17−
18−#ifdef HAVE_LIBUTF8_H
19−#include <libutf8.h>
20−#endif /* HAVE_LIBUTF8_H */
21−
22−#ifdef TRE_USE_SYSTEM_REGEX_H
23−/* Include the system regex.h to make TRE ABI compatible with the
24− system regex. */
25−#include TRE_SYSTEM_REGEX_H_PATH
26−#define tre_regcomp regcomp
27−#define tre_regexec regexec
28−#define tre_regerror regerror
29−#define tre_regfree regfree
30−#endif /* TRE_USE_SYSTEM_REGEX_H */
31−
32−#ifdef __cplusplus
33−extern "C" {
34−#endif
35−
36−#ifdef TRE_USE_SYSTEM_REGEX_H
37−
38−#ifndef REG_OK
39−#define REG_OK 0
40−#endif /* !REG_OK */
41−
42−#ifndef HAVE_REG_ERRCODE_T
43−typedef int reg_errcode_t;
44−#endif /* !HAVE_REG_ERRCODE_T */
45−
46−#if !defined(REG_NOSPEC) && !defined(REG_LITERAL)
47−#define REG_LITERAL 0x1000
48−#endif
49−
50−/* Extra tre_regcomp() flags. */
51−#ifndef REG_BASIC
52−#define REG_BASIC 0
53−#endif /* !REG_BASIC */
54−#define REG_RIGHT_ASSOC (REG_LITERAL << 1)
55−#define REG_UNGREEDY (REG_RIGHT_ASSOC << 1)
56−
57−/* Extra tre_regexec() flags. */
58−#define REG_APPROX_MATCHER 0x1000
59−#define REG_BACKTRACKING_MATCHER (REG_APPROX_MATCHER << 1)
60−
61−#else /* !TRE_USE_SYSTEM_REGEX_H */
62−
63−/* If the we're not using system regex.h, we need to define the
64− structs and enums ourselves. */
65−
66−typedef int regoff_t;
67−typedef struct {
68− size_t re_nsub; /* Number of parenthesized subexpressions. */
69− void *value; /* For internal use only. */
70−} regex_t;
71−
72−typedef struct {
73− regoff_t rm_so;
74− regoff_t rm_eo;
75−} regmatch_t;
76−
77−
78−typedef enum {
79− REG_OK = 0, /* No error. */
80− /* POSIX tre_regcomp() return error codes. (In the order listed in the
81− standard.) */
82− REG_NOMATCH, /* No match. */
83− REG_BADPAT, /* Invalid regexp. */
84− REG_ECOLLATE, /* Unknown collating element. */
85− REG_ECTYPE, /* Unknown character class name. */
86− REG_EESCAPE, /* Trailing backslash. */
87− REG_ESUBREG, /* Invalid back reference. */
88− REG_EBRACK, /* "[]" imbalance */
89− REG_EPAREN, /* "\(\)" or "()" imbalance */
90− REG_EBRACE, /* "\{\}" or "{}" imbalance */
91− REG_BADBR, /* Invalid content of {} */
92− REG_ERANGE, /* Invalid use of range operator */
93− REG_ESPACE, /* Out of memory. */
94− REG_BADRPT /* Invalid use of repetition operators. */
95−} reg_errcode_t;
96−
97−/* POSIX tre_regcomp() flags. */
98−#define REG_EXTENDED 1
99−#define REG_ICASE (REG_EXTENDED << 1)
100−#define REG_NEWLINE (REG_ICASE << 1)
101−#define REG_NOSUB (REG_NEWLINE << 1)
102−
103−/* Extra tre_regcomp() flags. */
104−#define REG_BASIC 0
105−#define REG_LITERAL (REG_NOSUB << 1)
106−#define REG_RIGHT_ASSOC (REG_LITERAL << 1)
107−#define REG_UNGREEDY (REG_RIGHT_ASSOC << 1)
108−
109−/* POSIX tre_regexec() flags. */
110−#define REG_NOTBOL 1
111−#define REG_NOTEOL (REG_NOTBOL << 1)
112−
113−/* Extra tre_regexec() flags. */
114−#define REG_APPROX_MATCHER (REG_NOTEOL << 1)
115−#define REG_BACKTRACKING_MATCHER (REG_APPROX_MATCHER << 1)
116−
117−#endif /* !TRE_USE_SYSTEM_REGEX_H */
118−
119−/* REG_NOSPEC and REG_LITERAL mean the same thing. */
120−#if defined(REG_LITERAL) && !defined(REG_NOSPEC)
121−#define REG_NOSPEC REG_LITERAL
122−#elif defined(REG_NOSPEC) && !defined(REG_LITERAL)
123−#define REG_LITERAL REG_NOSPEC
124−#endif /* defined(REG_NOSPEC) */
125−
126−/* The maximum number of iterations in a bound expression. */
127−#undef RE_DUP_MAX
128−#define RE_DUP_MAX 255
129−
130−/* The POSIX.2 regexp functions */
131−extern int
132−tre_regcomp(regex_t *preg, const char *regex, int cflags);
133−
134−extern int
135−tre_regexec(const regex_t *preg, const char *string, size_t nmatch,
136− regmatch_t pmatch[], int eflags);
137−
138−extern size_t
139−tre_regerror(int errcode, const regex_t *preg, char *errbuf,
140− size_t errbuf_size);
141−
142−extern void
143−tre_regfree(regex_t *preg);
144−
145−#ifdef TRE_WCHAR
146−#ifdef HAVE_WCHAR_H
147−#include <wchar.h>
148−#endif /* HAVE_WCHAR_H */
149−
150−/* Wide character versions (not in POSIX.2). */
151−extern int
152−tre_regwcomp(regex_t *preg, const wchar_t *regex, int cflags);
153−
154−extern int
155−tre_regwexec(const regex_t *preg, const wchar_t *string,
156− size_t nmatch, regmatch_t pmatch[], int eflags);
157−#endif /* TRE_WCHAR */
158−
159−/* Versions with a maximum length argument and therefore the capability to
160− handle null characters in the middle of the strings (not in POSIX.2). */
161−extern int
162−tre_regncomp(regex_t *preg, const char *regex, size_t len, int cflags);
163−
164−extern int
165−tre_regnexec(const regex_t *preg, const char *string, size_t len,
166− size_t nmatch, regmatch_t pmatch[], int eflags);
167−
168−#ifdef TRE_WCHAR
169−extern int
170−tre_regwncomp(regex_t *preg, const wchar_t *regex, size_t len, int cflags);
171−
172−extern int
173−tre_regwnexec(const regex_t *preg, const wchar_t *string, size_t len,
174− size_t nmatch, regmatch_t pmatch[], int eflags);
175−#endif /* TRE_WCHAR */
176−
177−#ifdef TRE_APPROX
178−
179−/* Approximate matching parameter struct. */
180−typedef struct {
181− int cost_ins; /* Default cost of an inserted character. */
182− int cost_del; /* Default cost of a deleted character. */
183− int cost_subst; /* Default cost of a substituted character. */
184− int max_cost; /* Maximum allowed cost of a match. */
185−
186− int max_ins; /* Maximum allowed number of inserts. */
187− int max_del; /* Maximum allowed number of deletes. */
188− int max_subst; /* Maximum allowed number of substitutes. */
189− int max_err; /* Maximum allowed number of errors total. */
190−} regaparams_t;
191−
192−/* Approximate matching result struct. */
193−typedef struct {
194− size_t nmatch; /* Length of pmatch[] array. */
195− regmatch_t *pmatch; /* Submatch data. */
196− int cost; /* Cost of the match. */
197− int num_ins; /* Number of inserts in the match. */
198− int num_del; /* Number of deletes in the match. */
199− int num_subst; /* Number of substitutes in the match. */
200−} regamatch_t;
201−
202−
203−/* Approximate matching functions. */
204−extern int
205−tre_regaexec(const regex_t *preg, const char *string,
206− regamatch_t *match, regaparams_t params, int eflags);
207−
208−extern int
209−tre_reganexec(const regex_t *preg, const char *string, size_t len,
210− regamatch_t *match, regaparams_t params, int eflags);
211−#ifdef TRE_WCHAR
212−/* Wide character approximate matching. */
213−extern int
214−tre_regawexec(const regex_t *preg, const wchar_t *string,
215− regamatch_t *match, regaparams_t params, int eflags);
216−
217−extern int
218−tre_regawnexec(const regex_t *preg, const wchar_t *string, size_t len,
219− regamatch_t *match, regaparams_t params, int eflags);
220−#endif /* TRE_WCHAR */
221−
222−/* Sets the parameters to default values. */
223−extern void
224−tre_regaparams_default(regaparams_t *params);
225−#endif /* TRE_APPROX */
226−
227−#ifdef TRE_WCHAR
228−typedef wchar_t tre_char_t;
229−#else /* !TRE_WCHAR */
230−typedef unsigned char tre_char_t;
231−#endif /* !TRE_WCHAR */
232−
233−typedef struct {
234− int (*get_next_char)(tre_char_t *c, unsigned int *pos_add, void *context);
235− void (*rewind)(size_t pos, void *context);
236− int (*compare)(size_t pos1, size_t pos2, size_t len, void *context);
237− void *context;
238−} tre_str_source;
239−
240−extern int
241−tre_reguexec(const regex_t *preg, const tre_str_source *string,
242− size_t nmatch, regmatch_t pmatch[], int eflags);
243−
244−/* Returns the version string. The returned string is static. */
245−extern char *
246−tre_version(void);
247−
248−/* Returns the value for a config parameter. The type to which `result'
249− must point to depends of the value of `query', see documentation for
250− more details. */
251−extern int
252−tre_config(int query, void *result);
253−
254−enum {
255− TRE_CONFIG_APPROX,
256− TRE_CONFIG_WCHAR,
257− TRE_CONFIG_MULTIBYTE,
258− TRE_CONFIG_SYSTEM_ABI,
259− TRE_CONFIG_VERSION
260−};
261−
262−/* Returns 1 if the compiled pattern has back references, 0 if not. */
263−extern int
264−tre_have_backrefs(const regex_t *preg);
265−
266−/* Returns 1 if the compiled pattern uses approximate matching features,
267− 0 if not. */
268−extern int
269−tre_have_approx(const regex_t *preg);
270−
271−#ifdef __cplusplus
272−}
273−#endif
274−#endif /* TRE_H */
275−
276−/* EOF */
src/core/regex/xmalloc.c+0−351
@@ -1,351 +0,0 @@
1−/*
2− xmalloc.c - Simple malloc debugging library implementation
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−/*
10− TODO:
11− - red zones
12− - group dumps by source location
13−*/
14−
15−#ifdef HAVE_CONFIG_H
16−#include <config.h>
17−#endif /* HAVE_CONFIG_H */
18−
19−#include <stdlib.h>
20−#include <assert.h>
21−#include <stdio.h>
22−#define XMALLOC_INTERNAL 1
23−#include "xmalloc.h"
24−
25−
26−/*
27− Internal stuff.
28−*/
29−
30−typedef struct hashTableItemRec {
31− void *ptr;
32− int bytes;
33− const char *file;
34− int line;
35− const char *func;
36− struct hashTableItemRec *next;
37−} hashTableItem;
38−
39−typedef struct {
40− hashTableItem **table;
41−} hashTable;
42−
43−static int xmalloc_peak;
44−int xmalloc_current;
45−static int xmalloc_peak_blocks;
46−int xmalloc_current_blocks;
47−static int xmalloc_fail_after;
48−
49−#define TABLE_BITS 8
50−#define TABLE_MASK ((1 << TABLE_BITS) - 1)
51−#define TABLE_SIZE (1 << TABLE_BITS)
52−
53−static hashTable *
54−hash_table_new(void)
55−{
56− hashTable *tbl;
57−
58− tbl = malloc(sizeof(*tbl));
59−
60− if (tbl != NULL)
61− {
62− tbl->table = calloc(TABLE_SIZE, sizeof(*tbl->table));
63−
64− if (tbl->table == NULL)
65− {
66− free(tbl);
67− return NULL;
68− }
69− }
70−
71− return tbl;
72−}
73−
74−static int
75−hash_void_ptr(void *ptr)
76−{
77− int hash;
78− int i;
79−
80− /* I took this hash function just off the top of my head, I have
81− no idea whether it is bad or very bad. */
82− hash = 0;
83− for (i = 0; i < (int)sizeof(ptr)*8 / TABLE_BITS; i++)
84− {
85− hash ^= (unsigned long)ptr >> i*8;
86− hash += i * 17;
87− hash &= TABLE_MASK;
88− }
89− return hash;
90−}
91−
92−static void
93−hash_table_add(hashTable *tbl, void *ptr, int bytes,
94− const char *file, int line, const char *func)
95−{
96− int i;
97− hashTableItem *item, *new;
98−
99− i = hash_void_ptr(ptr);
100−
101− item = tbl->table[i];
102− if (item != NULL)
103− while (item->next != NULL)
104− item = item->next;
105−
106− new = malloc(sizeof(*new));
107− assert(new != NULL);
108− new->ptr = ptr;
109− new->bytes = bytes;
110− new->file = file;
111− new->line = line;
112− new->func = func;
113− new->next = NULL;
114− if (item != NULL)
115− item->next = new;
116− else
117− tbl->table[i] = new;
118−
119− xmalloc_current += bytes;
120− if (xmalloc_current > xmalloc_peak)
121− xmalloc_peak = xmalloc_current;
122− xmalloc_current_blocks++;
123− if (xmalloc_current_blocks > xmalloc_peak_blocks)
124− xmalloc_peak_blocks = xmalloc_current_blocks;
125−}
126−
127−static void
128−hash_table_del(hashTable *tbl, void *ptr)
129−{
130− int i;
131− hashTableItem *item, *prev;
132−
133− i = hash_void_ptr(ptr);
134−
135− item = tbl->table[i];
136− if (item == NULL)
137− {
138− printf("xfree: invalid ptr %p\n", ptr);
139− abort();
140− }
141− prev = NULL;
142− while (item->ptr != ptr)
143− {
144− prev = item;
145− item = item->next;
146− }
147− if (item->ptr != ptr)
148− {
149− printf("xfree: invalid ptr %p\n", ptr);
150− abort();
151− }
152−
153− xmalloc_current -= item->bytes;
154− xmalloc_current_blocks--;
155−
156− if (prev != NULL)
157− {
158− prev->next = item->next;
159− free(item);
160− }
161− else
162− {
163− tbl->table[i] = item->next;
164− free(item);
165− }
166−}
167−
168−static hashTable *xmalloc_table = NULL;
169−
170−static void
171−xmalloc_init(void)
172−{
173− if (xmalloc_table == NULL)
174− {
175− xmalloc_table = hash_table_new();
176− xmalloc_peak = 0;
177− xmalloc_peak_blocks = 0;
178− xmalloc_current = 0;
179− xmalloc_current_blocks = 0;
180− xmalloc_fail_after = -1;
181− }
182− assert(xmalloc_table != NULL);
183− assert(xmalloc_table->table != NULL);
184−}
185−
186−
187−
188−/*
189− Public API.
190−*/
191−
192−void
193−xmalloc_configure(int fail_after)
194−{
195− xmalloc_init();
196− xmalloc_fail_after = fail_after;
197−}
198−
199−int
200−xmalloc_dump_leaks(void)
201−{
202− int i;
203− int num_leaks = 0;
204− int leaked_bytes = 0;
205− hashTableItem *item;
206−
207− xmalloc_init();
208−
209− for (i = 0; i < TABLE_SIZE; i++)
210− {
211− item = xmalloc_table->table[i];
212− while (item != NULL)
213− {
214− printf("%s:%d: %s: %d bytes at %p not freed\n",
215− item->file, item->line, item->func, item->bytes, item->ptr);
216− num_leaks++;
217− leaked_bytes += item->bytes;
218− item = item->next;
219− }
220− }
221− if (num_leaks == 0)
222− printf("No memory leaks.\n");
223− else
224− printf("%d unfreed memory chuncks, total %d unfreed bytes.\n",
225− num_leaks, leaked_bytes);
226− printf("Peak memory consumption %d bytes (%.1f kB, %.1f MB) in %d blocks ",
227− xmalloc_peak, (double)xmalloc_peak / 1024,
228− (double)xmalloc_peak / (1024*1024), xmalloc_peak_blocks);
229− printf("(average ");
230− if (xmalloc_peak_blocks)
231− printf("%d", ((xmalloc_peak + xmalloc_peak_blocks / 2)
232− / xmalloc_peak_blocks));
233− else
234− printf("N/A");
235− printf(" bytes per block).\n");
236−
237− return num_leaks;
238−}
239−
240−void *
241−xmalloc_impl(size_t size, const char *file, int line, const char *func)
242−{
243− void *ptr;
244−
245− xmalloc_init();
246− assert(size > 0);
247−
248− if (xmalloc_fail_after == 0)
249− {
250− xmalloc_fail_after = -2;
251−#if 0
252− printf("xmalloc: forced failure %s:%d: %s\n", file, line, func);
253−#endif
254− return NULL;
255− }
256− else if (xmalloc_fail_after == -2)
257− {
258− printf("xmalloc: called after failure from %s:%d: %s\n",
259− file, line, func);
260− assert(0);
261− }
262− else if (xmalloc_fail_after > 0)
263− xmalloc_fail_after--;
264−
265− ptr = malloc(size);
266− if (ptr != NULL)
267− hash_table_add(xmalloc_table, ptr, (int)size, file, line, func);
268− return ptr;
269−}
270−
271−void *
272−xcalloc_impl(size_t nmemb, size_t size, const char *file, int line,
273− const char *func)
274−{
275− void *ptr;
276−
277− xmalloc_init();
278− assert(size > 0);
279−
280− if (xmalloc_fail_after == 0)
281− {
282− xmalloc_fail_after = -2;
283−#if 0
284− printf("xcalloc: forced failure %s:%d: %s\n", file, line, func);
285−#endif
286− return NULL;
287− }
288− else if (xmalloc_fail_after == -2)
289− {
290− printf("xcalloc: called after failure from %s:%d: %s\n",
291− file, line, func);
292− assert(0);
293− }
294− else if (xmalloc_fail_after > 0)
295− xmalloc_fail_after--;
296−
297− ptr = calloc(nmemb, size);
298− if (ptr != NULL)
299− hash_table_add(xmalloc_table, ptr, (int)(nmemb * size), file, line, func);
300− return ptr;
301−}
302−
303−void
304−xfree_impl(void *ptr, const char *file, int line, const char *func)
305−{
306− /*LINTED*/(void)&file;
307− /*LINTED*/(void)&line;
308− /*LINTED*/(void)&func;
309− xmalloc_init();
310−
311− if (ptr != NULL)
312− hash_table_del(xmalloc_table, ptr);
313− free(ptr);
314−}
315−
316−void *
317−xrealloc_impl(void *ptr, size_t new_size, const char *file, int line,
318− const char *func)
319−{
320− void *new_ptr;
321−
322− xmalloc_init();
323− assert(ptr != NULL);
324− assert(new_size > 0);
325−
326− if (xmalloc_fail_after == 0)
327− {
328− xmalloc_fail_after = -2;
329− return NULL;
330− }
331− else if (xmalloc_fail_after == -2)
332− {
333− printf("xrealloc: called after failure from %s:%d: %s\n",
334− file, line, func);
335− assert(0);
336− }
337− else if (xmalloc_fail_after > 0)
338− xmalloc_fail_after--;
339−
340− new_ptr = realloc(ptr, new_size);
341− if (new_ptr != NULL)
342− {
343− hash_table_del(xmalloc_table, ptr);
344− hash_table_add(xmalloc_table, new_ptr, (int)new_size, file, line, func);
345− }
346− return new_ptr;
347−}
348−
349−
350−
351−/* EOF */
src/core/regex/xmalloc.h+0−77
@@ -1,77 +0,0 @@
1−/*
2− xmalloc.h - Simple malloc debugging library API
3−
4− This software is released under a BSD-style license.
5− See the file LICENSE for details and copyright.
6−
7−*/
8−
9−#ifndef _XMALLOC_H
10−#define _XMALLOC_H 1
11−
12−void *xmalloc_impl(size_t size, const char *file, int line, const char *func);
13−void *xcalloc_impl(size_t nmemb, size_t size, const char *file, int line,
14− const char *func);
15−void xfree_impl(void *ptr, const char *file, int line, const char *func);
16−void *xrealloc_impl(void *ptr, size_t new_size, const char *file, int line,
17− const char *func);
18−int xmalloc_dump_leaks(void);
19−void xmalloc_configure(int fail_after);
20−
21−
22−#ifndef XMALLOC_INTERNAL
23−#ifdef MALLOC_DEBUGGING
24−
25−/* Version 2.4 and later of GCC define a magical variable `__PRETTY_FUNCTION__'
26− which contains the name of the function currently being defined.
27−# define __XMALLOC_FUNCTION __PRETTY_FUNCTION__
28− This is broken in G++ before version 2.6.
29− C9x has a similar variable called __func__, but prefer the GCC one since
30− it demangles C++ function names. */
31−# ifdef __GNUC__
32−# if __GNUC__ > 2 || (__GNUC__ == 2 \
33− && __GNUC_MINOR__ >= (defined __cplusplus ? 6 : 4))
34−# define __XMALLOC_FUNCTION __PRETTY_FUNCTION__
35−# else
36−# define __XMALLOC_FUNCTION ((const char *) 0)
37−# endif
38−# else
39−# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
40−# define __XMALLOC_FUNCTION __func__
41−# else
42−# define __XMALLOC_FUNCTION ((const char *) 0)
43−# endif
44−# endif
45−
46−#define xmalloc(size) xmalloc_impl(size, __FILE__, __LINE__, \
47− __XMALLOC_FUNCTION)
48−#define xcalloc(nmemb, size) xcalloc_impl(nmemb, size, __FILE__, __LINE__, \
49− __XMALLOC_FUNCTION)
50−#define xfree(ptr) xfree_impl(ptr, __FILE__, __LINE__, __XMALLOC_FUNCTION)
51−#define xrealloc(ptr, new_size) xrealloc_impl(ptr, new_size, __FILE__, \
52− __LINE__, __XMALLOC_FUNCTION)
53−#undef malloc
54−#undef calloc
55−#undef free
56−#undef realloc
57−
58−#define malloc USE_XMALLOC_INSTEAD_OF_MALLOC
59−#define calloc USE_XCALLOC_INSTEAD_OF_CALLOC
60−#define free USE_XFREE_INSTEAD_OF_FREE
61−#define realloc USE_XREALLOC_INSTEAD_OF_REALLOC
62−
63−#else /* !MALLOC_DEBUGGING */
64−
65−#include <stdlib.h>
66−
67−#define xmalloc(size) malloc(size)
68−#define xcalloc(nmemb, size) calloc(nmemb, size)
69−#define xfree(ptr) free(ptr)
70−#define xrealloc(ptr, new_size) realloc(ptr, new_size)
71−
72−#endif /* !MALLOC_DEBUGGING */
73−#endif /* !XMALLOC_INTERNAL */
74−
75−#endif /* _XMALLOC_H */
76−
77−/* EOF */
src/core/ulib_regex.cpp+0−407
@@ -1,407 +0,0 @@
1−/*----------------------------------------------------------------------------
2− ChucK Concurrent, On-the-fly Audio Programming Language
3− Compiler and Virtual Machine
4−
5− Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6− http://chuck.stanford.edu/
7− http://chuck.cs.princeton.edu/
8−
9− This program is free software; you can redistribute it and/or modify
10− it under the terms of the GNU General Public License as published by
11− the Free Software Foundation; either version 2 of the License, or
12− (at your option) any later version.
13−
14− This program is distributed in the hope that it will be useful,
15− but WITHOUT ANY WARRANTY; without even the implied warranty of
16− MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17− GNU General Public License for more details.
18−
19− You should have received a copy of the GNU General Public License
20− along with this program; if not, write to the Free Software
21− Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22− U.S.A.
23− -----------------------------------------------------------------------------*/
24−
25−//-----------------------------------------------------------------------------
26−// file: ulib_regex.cpp
27−// desc: regex library
28−//
29−// author: Spencer Salazar (spencer@ccrma.stanford.edu)
30−// date: Summer 2013
31−//-----------------------------------------------------------------------------
32−#include "ulib_regex.h"
33−#include "chuck_errmsg.h"
34−#include "chuck_instr.h"
35−#include "chuck_type.h"
36−#include "chuck_vm.h"
37−
38−#ifdef WIN32
39−#include "regex/regex.h"
40−#else
41−#include <regex.h>
42−#endif
43−
44−#define CK_REGEX_MAX_MATCHES (10)
45−
46−CK_DLL_SFUN( regex_match );
47−CK_DLL_SFUN( regex_match2 );
48−CK_DLL_SFUN( regex_replace );
49−CK_DLL_SFUN( regex_replaceAll );
50−
51−DLL_QUERY regex_query( Chuck_DL_Query * QUERY )
52−{
53− // set name
54− QUERY->setname( QUERY, "RegEx" );
55−
56− // begin class
57− QUERY->begin_class( QUERY, "RegEx", "Object" );
58− QUERY->doc_class( QUERY, "Class for regular expression matching and replacing in strings. Regex style is POSIX-extended." );
59−
60− // add match
61− QUERY->add_sfun( QUERY, regex_match, "int", "match" );
62− QUERY->add_arg( QUERY, "string", "pattern");
63− QUERY->add_arg( QUERY, "string", "str");
64− QUERY->doc_func( QUERY, "Return true if match for pattern is found in str, false otherwise." );
65−
66− // add match2
67− QUERY->add_sfun( QUERY, regex_match2, "int", "match" );
68− QUERY->add_arg( QUERY, "string", "pattern");
69− QUERY->add_arg( QUERY, "string", "str");
70− QUERY->add_arg( QUERY, "string[]", "matches");
71− QUERY->doc_func( QUERY, "Return the match and sub-patterns in matches. matches[0] in the entire matched pattern, matches[1] is the first sub-pattern (if any), and so on." );
72−
73− // add replace
74− QUERY->add_sfun( QUERY, regex_replace, "string", "replace" );
75− QUERY->add_arg( QUERY, "string", "pattern");
76− QUERY->add_arg( QUERY, "string", "replacement");
77− QUERY->add_arg( QUERY, "string", "str");
78− QUERY->doc_func( QUERY, "Replace the first instance of pattern in str with replacement, returning the result." );
79−
80− // add replaceAll
81− QUERY->add_sfun( QUERY, regex_replaceAll, "string", "replaceAll" );
82− QUERY->add_arg( QUERY, "string", "pattern");
83− QUERY->add_arg( QUERY, "string", "replacement");
84− QUERY->add_arg( QUERY, "string", "str");
85− QUERY->doc_func( QUERY, "Replace all instances of pattern in str with replacement, returning the result.");
86−
87− QUERY->end_class( QUERY );
88−
89− return TRUE;
90−
91−//error:
92−// return FALSE;
93−}
94−
95−
96−CK_DLL_SFUN( regex_match )
97−{
98− Chuck_String * pattern = GET_NEXT_STRING(ARGS);
99− Chuck_String * str = GET_NEXT_STRING(ARGS);
100−
101− regex_t regex;
102− t_CKBOOL r_free = FALSE;
103− int result = 0;
104−
105− if(pattern == NULL)
106− {
107− throw_exception(SHRED, "NullPointerException", "RegEx.match: argument 'pattern' is null");
108− goto error;
109− }
110− if(str == NULL)
111− {
112− throw_exception(SHRED, "NullPointerException", "RegEx.match: argument 'str' is null");
113− goto error;
114− }
115−
116− result = regcomp(&regex, pattern->str().c_str(), REG_EXTENDED | REG_NOSUB);
117− if(result != 0)
118− goto error;
119−
120− r_free = TRUE;
121−
122− result = regexec(&regex, str->str().c_str(), 0, NULL, 0);
123−
124− RETURN->v_int = (result == 0 ? 1 : 0);
125−
126− regfree(&regex);
127− r_free = FALSE;
128−
129− return;
130−
131−error:
132− if(result != 0)
133− {
134− char buf[256];
135−
136− regerror(result, &regex, buf, 256);
137− EM_error2( 0, "(RegEx.match): regex reported error: %s", buf);
138− }
139−
140− if(r_free)
141− {
142− regfree(&regex);
143− r_free = FALSE;
144− }
145−
146− RETURN->v_int = 0;
147−}
148−
149−
150−CK_DLL_SFUN( regex_match2 )
151−{
152− Chuck_String * pattern = GET_NEXT_STRING(ARGS);
153− Chuck_String * str = GET_NEXT_STRING(ARGS);
154− Chuck_Array4 * matches = (Chuck_Array4 *) GET_NEXT_OBJECT(ARGS);
155−
156− regex_t regex;
157− t_CKBOOL r_free = FALSE;
158− size_t i;
159− regmatch_t *matcharray = NULL;
160− int result = 0;
161−
162− if(pattern == NULL)
163− {
164− throw_exception(SHRED, "NullPointerException", "RegEx.match: argument 'pattern' is null");
165− goto error;
166− }
167− if(str == NULL)
168− {
169− throw_exception(SHRED, "NullPointerException", "RegEx.match: argument 'str' is null");
170− goto error;
171− }
172− if(matches == NULL)
173− {
174− throw_exception(SHRED, "NullPointerException", "RegEx.match: argument 'matches' is null");
175− goto error;
176− }
177−
178−
179− //matches->clear();
180− // bugfix: array.clear() doesnt seem to work?
181− matches->set_size(0);
182−
183− result = regcomp(&regex, pattern->str().c_str(), REG_EXTENDED);
184− if(result != 0)
185− goto error;
186−
187− r_free = TRUE;
188−
189− matcharray = new regmatch_t[regex.re_nsub+1];
190−
191− result = regexec(&regex, str->str().c_str(), regex.re_nsub+1, matcharray, 0);
192−
193− RETURN->v_int = (result == 0 ? 1 : 0);
194−
195− regfree(&regex);
196− r_free = FALSE;
197−
198− if(result == 0)
199− {
200− for(i = 0; i < regex.re_nsub+1; i++)
201− {
202− Chuck_String * match = (Chuck_String *) instantiate_and_initialize_object(SHRED->vm_ref->env()->t_string, SHRED);
203−
204− if(matcharray[i].rm_so >= 0 && matcharray[i].rm_eo > 0)
205− match->set( std::string(str->str(), matcharray[i].rm_so,
206− matcharray[i].rm_eo-matcharray[i].rm_so) );
207−
208− matches->push_back((t_CKUINT) match);
209− }
210− }
211−
212− SAFE_DELETE(matcharray);
213−
214− return;
215−
216−error:
217− if(result != 0)
218− {
219− char errbuf[256];
220−
221− regerror(result, &regex, errbuf, 256);
222− EM_error2( 0, "(RegEx.match): regex reported error: %s", errbuf);
223− }
224−
225− if(r_free)
226− {
227− regfree(&regex);
228− r_free = FALSE;
229− }
230−
231− SAFE_DELETE(matcharray);
232−
233− RETURN->v_int = 0;
234−}
235−
236−
237−CK_DLL_SFUN( regex_replace )
238−{
239− Chuck_String * pattern = GET_NEXT_STRING(ARGS);
240− Chuck_String * replace = GET_NEXT_STRING(ARGS);
241− Chuck_String * str = GET_NEXT_STRING(ARGS);
242−
243− Chuck_String * ret = (Chuck_String *) instantiate_and_initialize_object(SHRED->vm_ref->env()->t_string, SHRED);
244− ret->set( str->str() );
245−
246− regex_t regex;
247− t_CKBOOL r_free = FALSE;
248− regmatch_t *matcharray = NULL;
249− int result = 0;
250−
251− if(pattern == NULL)
252− {
253− throw_exception(SHRED, "NullPointerException",
254− "RegEx.match: argument 'pattern' is null");
255− goto error;
256− }
257− if(str == NULL)
258− {
259− throw_exception(SHRED, "NullPointerException",
260− "RegEx.match: argument 'str' is null");
261− goto error;
262− }
263− if(replace == NULL)
264− {
265− throw_exception(SHRED, "NullPointerException",
266− "RegEx.match: argument 'replace' is null");
267− goto error;
268− }
269−
270− // compile regex
271− result = regcomp(&regex, pattern->str().c_str(), REG_EXTENDED);
272− if(result != 0)
273− goto error;
274−
275− r_free = TRUE;
276−
277− // perform match
278− matcharray = new regmatch_t[regex.re_nsub+1];
279− result = regexec(&regex, str->str().c_str(), regex.re_nsub+1, matcharray, 0);
280−
281− regfree(&regex);
282− r_free = FALSE;
283−
284− // perform substitution
285− if(result == 0 && matcharray[0].rm_so >= 0 && matcharray[0].rm_eo >= 0)
286− {
287− std::string s = ret->str();
288− s.replace(matcharray[0].rm_so,
289− matcharray[0].rm_eo-matcharray[0].rm_so, replace->str());
290− ret->set( s );
291− }
292−
293− SAFE_DELETE(matcharray);
294−
295− RETURN->v_string = ret;
296−
297− return;
298−
299−error:
300− if(result != 0)
301− {
302− char errbuf[256];
303−
304− regerror(result, &regex, errbuf, 256);
305− EM_error2( 0, "(RegEx.match): regex reported error: %s", errbuf);
306− }
307−
308− if(r_free)
309− {
310− regfree(&regex);
311− r_free = FALSE;
312− }
313−
314− RETURN->v_int = 0;
315−}
316−
317−
318−CK_DLL_SFUN( regex_replaceAll )
319−{
320− Chuck_String * pattern = GET_NEXT_STRING(ARGS);
321− Chuck_String * replace = GET_NEXT_STRING(ARGS);
322− Chuck_String * str = GET_NEXT_STRING(ARGS);
323−
324− Chuck_String * ret = (Chuck_String *) instantiate_and_initialize_object(SHRED->vm_ref->env()->t_string, SHRED);
325− ret->set( str->str() );
326−
327− regex_t regex;
328− t_CKBOOL r_free = FALSE;
329− regmatch_t *matcharray = NULL;
330− int result = 0;
331− size_t pos = 0;
332−
333− if(pattern == NULL)
334− {
335− throw_exception(SHRED, "NullPointerException",
336− "RegEx.match: argument 'pattern' is null");
337− goto error;
338− }
339− if(str == NULL)
340− {
341− throw_exception(SHRED, "NullPointerException",
342− "RegEx.match: argument 'str' is null");
343− goto error;
344− }
345− if(replace == NULL)
346− {
347− throw_exception(SHRED, "NullPointerException",
348− "RegEx.match: argument 'replace' is null");
349− goto error;
350− }
351−
352− // compile regex
353− result = regcomp(&regex, pattern->str().c_str(), REG_EXTENDED);
354− if(result != 0)
355− goto error;
356−
357− r_free = TRUE;
358−
359− // perform match
360− matcharray = new regmatch_t[regex.re_nsub+1];
361−
362− while(pos < str->str().size())
363− {
364− result = regexec(&regex, ret->str().c_str()+pos, regex.re_nsub+1, matcharray, 0);
365−
366− // perform substitution
367− if(result != 0)
368− break;
369− else if(matcharray[0].rm_so >= 0 && matcharray[0].rm_eo >= 0)
370− {
371− std::string s = ret->str();
372− s.replace(pos+matcharray[0].rm_so,
373− matcharray[0].rm_eo-matcharray[0].rm_so,
374− replace->str());
375− ret->set( s );
376−
377− pos = pos + matcharray[0].rm_so + replace->str().size();
378− }
379− }
380−
381− SAFE_DELETE(matcharray);
382−
383− regfree(&regex);
384− r_free = FALSE;
385−
386− RETURN->v_string = ret;
387−
388− return;
389−
390−error:
391− if(result != 0)
392− {
393− char errbuf[256];
394−
395− regerror(result, &regex, errbuf, 256);
396− EM_error2( 0, "(RegEx.match): regex reported error: %s", errbuf);
397− }
398−
399− if(r_free)
400− {
401− regfree(&regex);
402− r_free = FALSE;
403− }
404−
405− RETURN->v_int = 0;
406−}
407−
src/core/ulib_regex.h+0−40
@@ -1,40 +0,0 @@
1−/*----------------------------------------------------------------------------
2− ChucK Concurrent, On-the-fly Audio Programming Language
3− Compiler and Virtual Machine
4−
5− Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6− http://chuck.stanford.edu/
7− http://chuck.cs.princeton.edu/
8−
9− This program is free software; you can redistribute it and/or modify
10− it under the terms of the GNU General Public License as published by
11− the Free Software Foundation; either version 2 of the License, or
12− (at your option) any later version.
13−
14− This program is distributed in the hope that it will be useful,
15− but WITHOUT ANY WARRANTY; without even the implied warranty of
16− MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17− GNU General Public License for more details.
18−
19− You should have received a copy of the GNU General Public License
20− along with this program; if not, write to the Free Software
21− Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22− U.S.A.
23− -----------------------------------------------------------------------------*/
24−
25−//-----------------------------------------------------------------------------
26−// file: ulib_regex.h
27−// desc: regex library
28−//
29−// author: Spencer Salazar (spencer@ccrma.stanford.edu)
30−// date: Summer 2013
31−//-----------------------------------------------------------------------------
32−#ifndef __ULIB_REGEX_H__
33−#define __ULIB_REGEX_H__
34−
35−#include "chuck_dl.h"
36−
37−DLL_QUERY regex_query( Chuck_DL_Query * QUERY );
38−
39−
40−#endif // __ULIB_REGEX_H__
src/makefile+2−2
@@ -40,7 +40,7 @@ EMSCRIPTENSRCS=host_web/chuck_emscripten.cpp \ · 39 unmodified lines
4040 core/uana_extract.cpp core/uana_xform.cpp core/ugen_filter.cpp \
4141 core/ugen_osc.cpp core/ugen_stk.cpp core/ugen_xxx.cpp \
4242 core/ulib_ai.cpp core/ulib_doc.cpp core/ulib_machine.cpp \
43− core/ulib_math.cpp core/ulib_regex.cpp core/ulib_std.cpp \
43+ core/ulib_math.cpp core/ulib_std.cpp \
4444 core/util_buffers.cpp core/util_math.c core/util_raw.c \
4545 core/util_string.cpp core/util_xforms.c core/chuck_win32.c \
4646 core/util_sndfile.c
@@ -157,7 +157,7 @@ CXXOBJS_CORE+= chuck.o chuck_absyn.o chuck_parse.o chuck_errmsg.o \ · 110 unmodified lines
157157 chuck_carrier.o chuck_globals.o \
158158 hidio_sdl.o midiio_rtmidi.o rtmidi.o ugen_osc.o ugen_filter.o \
159159 ugen_stk.o ugen_xxx.o ulib_ai.o ulib_doc.o ulib_machine.o \
160− ulib_math.o ulib_std.o ulib_opsc.o ulib_regex.o util_buffers.o \
160+ ulib_math.o ulib_std.o ulib_opsc.o util_buffers.o \
161161 util_console.o util_string.o util_thread.o util_opsc.o \
162162 util_serial.o util_hid.o uana_xform.o uana_extract.o
163163 LO_COBJS_CORE+= lo/address.o lo/blob.o lo/bundle.o lo/message.o lo/method.o \
src/xcode/chuck.xcodeproj/project.pbxproj+0−6
@@ -68,7 +68,6 @@ · 67 unmodified lines
6868 091677411F7CAD1100248F78 /* uana_extract.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 09812B980C6E394A00D1D68C /* uana_extract.cpp */; };
6969 091677431F7CAD1100248F78 /* util_serial.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0966E6C815CFBB0F0099CBD8 /* util_serial.cpp */; };
7070 091677441F7CAD1100248F78 /* chuck_io.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0962DA2715D3A626002DEFF3 /* chuck_io.cpp */; };
71− 091677451F7CAD1100248F78 /* ulib_regex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 091F327C17A03A4D00686C8D /* ulib_regex.cpp */; };
7271 091677481F7CAD1100248F78 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09A40BD40A9A57C6007604EA /* Carbon.framework */; };
7372 091677491F7CAD1100248F78 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09A40BD50A9A57C6007604EA /* CoreAudio.framework */; };
7473 0916774A1F7CAD1100248F78 /* CoreMIDI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09A40BD60A9A57C6007604EA /* CoreMIDI.framework */; };
@@ -139,8 +138,6 @@ · 64 unmodified lines
139138 090B4B1A0C4F038E00DF5577 /* uana_xform.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = uana_xform.cpp; path = ../core/uana_xform.cpp; sourceTree = SOURCE_ROOT; };
140139 090B4B1B0C4F038E00DF5577 /* uana_xform.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = uana_xform.h; path = ../core/uana_xform.h; sourceTree = SOURCE_ROOT; };
141140 091677521F7CAD1100248F78 /* libchuck.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libchuck.a; sourceTree = BUILT_PRODUCTS_DIR; };
142− 091F327C17A03A4D00686C8D /* ulib_regex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ulib_regex.cpp; path = ../core/ulib_regex.cpp; sourceTree = SOURCE_ROOT; };
143− 091F327D17A03A4D00686C8D /* ulib_regex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ulib_regex.h; path = ../core/ulib_regex.h; sourceTree = SOURCE_ROOT; };
144141 095D14581341476200BBD9EB /* MultitouchSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MultitouchSupport.framework; path = System/Library/PrivateFrameworks/MultitouchSupport.framework; sourceTree = SDKROOT; };
145142 0962DA2715D3A626002DEFF3 /* chuck_io.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = chuck_io.cpp; path = ../core/chuck_io.cpp; sourceTree = SOURCE_ROOT; };
146143 0962DA2815D3A626002DEFF3 /* chuck_io.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = chuck_io.h; path = ../core/chuck_io.h; sourceTree = SOURCE_ROOT; };
@@ -932,8 +929,6 @@ · 785 unmodified lines
932929 09A40B4F0A9A54DA007604EA /* ulib_opsc.h */,
933930 09A40B500A9A54DA007604EA /* ulib_std.cpp */,
934931 09A40B510A9A54DA007604EA /* ulib_std.h */,
935− 091F327C17A03A4D00686C8D /* ulib_regex.cpp */,
936− 091F327D17A03A4D00686C8D /* ulib_regex.h */,
937932 09A40B520A9A54DA007604EA /* util_buffers.cpp */,
938933 09A40B530A9A54DA007604EA /* util_buffers.h */,
939934 09A40B540A9A54DA007604EA /* util_console.cpp */,
@@ -1169,7 +1164,6 @@ · 229 unmodified lines
11691164 8615DFFA264D9AE20084EF86 /* chuck_globals.cpp in Sources */,
11701165 091677431F7CAD1100248F78 /* util_serial.cpp in Sources */,
11711166 091677441F7CAD1100248F78 /* chuck_io.cpp in Sources */,
1172− 091677451F7CAD1100248F78 /* ulib_regex.cpp in Sources */,
11731167 );
11741168 runOnlyForDeploymentPostprocessing = 0;
11751169 };

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t