RPM Package Manager, CVS Repository
http://rpm5.org/cvs/
____________________________________________________________________________
Server: rpm5.org Name: Ralf S. Engelschall
Root: /v/rpm/cvs Email: rse@rpm5.org
Module: rpm lua Date: 12-Jan-2008 13:33:34
Branch: HEAD Handle: 2008011212333301
Added files:
lua/local lrexlib.txt lrexlib_algo.h lrexlib_common.c
lrexlib_common.h lrexlib_lpcre.c lrexlib_lpcre_f.c
lrexlib_lposix.c
Modified files:
lua Makefile.am
lua/local llocal.lua lrexlib.h
rpm/rpmio rpmlua.c
Removed files:
lua/local lrexlib.c
Log:
Upgrade the RPM Lua extension "lrexlib" from ancient version 1.1x
to latest version 2.2 in order to get a larger bunch of additional
PCRE-based functionalities (for instance string splitting, etc). The
source files had to be renamed to contain prefix "lrexlib_" in order to
resolve conflict between the Lua POSIX extension "lposix.c" and the Lua
POSIX-Regex extension "lposix.c".
Summary:
Revision Changes Path
1.17 +6 -1 lua/Makefile.am
1.12 +8 -8 lua/local/llocal.lua
1.9 +0 -661 lua/local/lrexlib.c
1.3 +3 -1 lua/local/lrexlib.h
1.1 +655 -0 lua/local/lrexlib.txt
1.1 +623 -0 lua/local/lrexlib_algo.h
1.1 +244 -0 lua/local/lrexlib_common.c
1.1 +86 -0 lua/local/lrexlib_common.h
1.1 +446 -0 lua/local/lrexlib_lpcre.c
1.1 +194 -0 lua/local/lrexlib_lpcre_f.c
1.1 +308 -0 lua/local/lrexlib_lposix.c
2.40 +2 -1 rpm/rpmio/rpmlua.c
____________________________________________________________________________
patch -p0 <<'@@ .'
Index: lua/Makefile.am
============================================================================
$ cvs diff -u -r1.16 -r1.17 Makefile.am
--- lua/Makefile.am 10 Jan 2008 20:49:36 -0000 1.16
+++ lua/Makefile.am 12 Jan 2008 12:33:33 -0000 1.17
@@ -29,7 +29,12 @@
local/lposix.h \
local/lposix.c \
local/lrexlib.h \
- local/lrexlib.c \
+ local/lrexlib_algo.h \
+ local/lrexlib_common.h \
+ local/lrexlib_common.c \
+ local/lrexlib_lpcre.c \
+ local/lrexlib_lpcre_f.c \
+ local/lrexlib_lposix.c \
local/luuid.h \
local/luuid.c \
linit.c \
@@ .
patch -p0 <<'@@ .'
Index: lua/local/llocal.lua
============================================================================
$ cvs diff -u -r1.11 -r1.12 llocal.lua
--- lua/local/llocal.lua 11 Jan 2008 18:58:16 -0000 1.11
+++ lua/local/llocal.lua 12 Jan 2008 12:33:33 -0000 1.12
@@ -5,9 +5,9 @@
-- provide a generic regular expression constructor
-- based on the most powerful regular expression engine
-rex.new = rex.newPCRE
-if rex.new == nil then
- rex.new = rex.newPOSIX
+rex = rex_posix
+if rex_pcre ~= nil then
+ rex = rex_pcre
end
-- provide additional "util" namespace
@@ -26,7 +26,7 @@
local pat = rex.new(expr)
local pos = 1
for line in io.lines(filename) do
- if pat:match(line) then
+ if pat:tfind(line) then
table.insert(lines, pos, line)
end
pos = pos + 1
@@ -49,7 +49,7 @@
end
local pat = rex.new(expr)
for line in io.lines(filename) do
- if pat:match(line) then
+ if pat:tfind(line) then
return true
end
end
@@ -62,7 +62,7 @@
-- regular expression based string matching
function util.rmatch(str, regex)
- return rex.new(regex):match(str)
+ return rex.new(regex):tfind(str)
end
-- regular expression based string substitution
@@ -72,7 +72,7 @@
local result_last = ""
while result ~= result_last do
result_last = result
- local s, e, m = re:match(result)
+ local s, e, m = re:tfind(result)
if s ~= nil then
local prolog = string.sub(result, 1, s - 1)
local epilog = string.sub(result, e + 1)
@@ -105,7 +105,7 @@
end
count = count - 1
end
- local s, e, m = re:match(str)
+ local s, e, m = re:tfind(str)
if s ~= nil then
table.insert(result, string.sub(str, 1, s -1))
str = string.sub(str, e + 1)
@@ .
rm -f lua/local/lrexlib.c <<'@@ .'
Index: lua/local/lrexlib.c
============================================================================
[NO CHANGE SUMMARY BECAUSE FILE AS A WHOLE IS JUST REMOVED]
@@ .
patch -p0 <<'@@ .'
Index: lua/local/lrexlib.h
============================================================================
$ cvs diff -u -r1.2 -r1.3 lrexlib.h
--- lua/local/lrexlib.h 23 Mar 2004 05:09:14 -0000 1.2
+++ lua/local/lrexlib.h 12 Jan 2008 12:33:33 -0000 1.3
@@ -1,7 +1,9 @@
#ifndef LREXLIB_H
#define LREXLIB_H
-int luaopen_rex(lua_State *L)
+int luaopen_rex_pcre(lua_State *L)
+ /*@modifies L @*/;
+int luaopen_rex_posix(lua_State *L)
/*@modifies L @*/;
#endif
@@ .
patch -p0 <<'@@ .'
Index: lua/local/lrexlib.txt
============================================================================
$ cvs diff -u -r0 -r1.1 lrexlib.txt
--- /dev/null 2008-01-12 13:33:00 +0100
+++ lrexlib.txt 2008-01-12 13:33:33 +0100
@@ -0,0 +1,655 @@
+Lrexlib 2.2 Reference Manual
+
+Table of Contents
+
+ * Introduction
+ * Notes
+ * Common (PCRE and POSIX) functions and methods
+ + match
+ + find
+ + gmatch
+ + gsub
+ + split
+ + flags
+ + new
+ + tfind
+ + exec
+ * PCRE-only functions and methods
+ + dfa_exec
+ + maketables
+ + config
+ + version
+ * Other functions
+ + plainfind
+ * Incompatibilities with the Previous Versions
+
+-------------------------------------------------------------------------------
+
+Introduction
+
+Lrexlib provides bindings of the two principal regular expression library
+interfaces (POSIX and PCRE) to Lua 5.1.
+
+Lrexlib builds into shared libraries called by default rex_posix.so and
+rex_pcre.so, which can be used with require.
+
+Lrexlib is copyright Reuben Thomas 2000-2007 and copyright Shmuel Zeigerman
+2004-2007, and is released under the MIT license.
+
+-------------------------------------------------------------------------------
+
+Notes
+
+ 1. Most functions and methods in Lrexlib have mandatory and optional
+ arguments. There are no dependencies between arguments in Lrexlib's
+ functions and methods. Any optional argument can be supplied as nil (or
+ omitted if it is trailing one), the library will then use the default value
+ for that argument.
+
+ 2. This document uses the following syntax for optional arguments: they are
+ bracketed separately, and commas are left outside brackets, e.g.:
+
+ MyFunc (arg1, arg2, [arg3], [arg4])
+
+ 3. Throughout this document, the identifier rex is used in place of either
+ rex_posix or rex_pcre, that are the default namespaces for the
+ corresponding libraries.
+
+ 4. All functions receiving a regular expression pattern as an argument will
+ generate an error if that pattern is found invalid by the used POSIX / PCRE
+ library.
+
+ 5. The default value for compilation flags (cf) that Lrexlib uses when the
+ parameter is not supplied or nil, is:
+
+ o 0 for PCRE
+ o REG_EXTENDED for POSIX regex library
+
+ For PCRE, cf may also be supplied as a string, whose characters stand for
+ PCRE compilation flags. Combinations of the following characters (case
+ sensitive) are supported:
+
+ +-------------------------+
+ |Character| PCRE flag |
+ |---------+---------------|
+ |i |PCRE_CASELESS |
+ |---------+---------------|
+ |m |PCRE_MULTILINE |
+ |---------+---------------|
+ |s |PCRE_DOTALL |
+ |---------+---------------|
+ |x |PCRE_EXTENDED |
+ |---------+---------------|
+ |U |PCRE_UNGREEDY |
+ |---------+---------------|
+ |X |PCRE_EXTRA |
+ +-------------------------+
+
+ 6. The default value for execution flags (ef) that Lrexlib uses when the
+ parameter is not supplied or nil, is:
+
+ o 0 for PCRE
+ o 0 for standard POSIX regex library
+ o REG_STARTEND for those POSIX regex libraries that support it, e.g.
+ Spencer's.
+
+ 7. Parameter locale (lo) can be either a string (e.g., "French_France.1252"),
+ or a userdata obtained from a call to maketables. The default value, used
+ when the parameter is not supplied or nil, is the built-in PCRE set of
+ character tables.
+
+-------------------------------------------------------------------------------
+
+Common (PCRE and POSIX) functions and methods
+
+match
+
+rex.match (subj, patt, [init], [cf], [ef], [lo])
+
+The function searches for the first match of the regexp patt in the string subj
+, starting from offset init, subject to flags cf and ef.
+
+PCRE: A locale lo may be specified.
+
+ +-------------------------------------------------------------------------+
+ |Parameter| Description | Type | Default |
+ | | | | Value |
+ |---------+------------------------------------+---------------+----------|
+ |subj |subject |string |n/a |
+ |---------+------------------------------------+---------------+----------|
+ |patt |regular expression pattern |string |n/a |
+ |---------+------------------------------------+---------------+----------|
+ |[init] |start offset in the subject (can be |number |1 |
+ | |negative) | | |
+ |---------+------------------------------------+---------------+----------|
+ |[cf] |compilation flags (bitwise OR) |number |cf |
+ |---------+------------------------------------+---------------+----------|
+ |[ef] |execution flags (bitwise OR) |number |ef |
+ |---------+------------------------------------+---------------+----------|
+ |[lo] |[PCRE] locale |string or |locale |
+ | | |userdata | |
+ +-------------------------------------------------------------------------+
+
+Returns on success:
+ 1. All substring matches ("captures"), in the order they appear in the
+ pattern. false is returned for sub-patterns that did not participate in
+ the match. If the pattern specified no captures then the whole matched
+ substring is returned.
+Returns on failure:
+ 1. nil
+
+-------------------------------------------------------------------------------
+
+find
+
+rex.find (subj, patt, [init], [cf], [ef], [lo])
+
+The function searches for the first match of the regexp patt in the string subj
+, starting from offset init, subject to flags cf and ef.
+
+PCRE: A locale lo may be specified.
+
+ +-------------------------------------------------------------------------+
+ |Parameter| Description | Type | Default |
+ | | | | Value |
+ |---------+------------------------------------+---------------+----------|
+ |subj |subject |string |n/a |
+ |---------+------------------------------------+---------------+----------|
+ |patt |regular expression pattern |string |n/a |
+ |---------+------------------------------------+---------------+----------|
+ |[init] |start offset in the subject (can be |number |1 |
+ | |negative) | | |
+ |---------+------------------------------------+---------------+----------|
+ |[cf] |compilation flags (bitwise OR) |number |cf |
+ |---------+------------------------------------+---------------+----------|
+ |[ef] |execution flags (bitwise OR) |number |ef |
+ |---------+------------------------------------+---------------+----------|
+ |[lo] |[PCRE] locale |string or |locale |
+ | | |userdata | |
+ +-------------------------------------------------------------------------+
+
+Returns on success:
+ 1. The start point of the match (a number).
+ 2. The end point of the match (a number).
+ 3. All substring matches ("captures"), in the order they appear in the
+ pattern. false is returned for sub-patterns that did not participate in
+ the match.
+Returns on failure:
+ 1. nil
+
+-------------------------------------------------------------------------------
+
+gmatch
+
+rex.gmatch (subj, patt, [cf], [ef], [lo])
+
+The function is intended for use in the generic for Lua construct. It returns
+an iterator for repeated matching of the pattern patt in the string subj,
+subject to flags cf and ef.
+
+PCRE: A locale lo may be specified.
+
+ +-------------------------------------------------------------------------+
+ |Parameter| Description | Type |Default Value|
+ |---------+------------------------------+------------------+-------------|
+ |subj |subject |string |n/a |
+ |---------+------------------------------+------------------+-------------|
+ |patt |regular expression pattern |string |n/a |
+ |---------+------------------------------+------------------+-------------|
+ |[cf] |compilation flags (bitwise OR)|number |cf |
+ |---------+------------------------------+------------------+-------------|
+ |[ef] |execution flags (bitwise OR) |number |ef |
+ |---------+------------------------------+------------------+-------------|
+ |[lo] |[PCRE] locale |string or userdata|locale |
+ +-------------------------------------------------------------------------+
+
+The iterator function is called by Lua. On every iteration (that is, on every
+match), it returns all captures in the order they appear in the pattern (or the
+entire match if the pattern specified no captures). The iteration will continue
+till the subject fails to match.
+
+-------------------------------------------------------------------------------
+
+gsub
+
+rex.gsub (subj, patt, repl, [n], [cf], [ef], [lo])
+
+This function searches for all matches of the pattern patt in the string subj
+and replaces them according to the parameters repl and n (see details below).
+
+PCRE: A locale lo may be specified.
+
+ +-------------------------------------------------------------------------+
+ |Parameter| Description | Type |Default |
+ | | | | Value |
+ |---------+---------------------------------------+--------------+--------|
+ |subj |subject |string |n/a |
+ |---------+---------------------------------------+--------------+--------|
+ |patt |regular expression pattern |string |n/a |
+ |---------+---------------------------------------+--------------+--------|
+ | | |string, | |
+ |repl |substitution source |function or |n/a |
+ | | |table | |
+ |---------+---------------------------------------+--------------+--------|
+ |[n] |maximum number of matches to search |number or |nil |
+ | |for, or control function, or nil |function | |
+ |---------+---------------------------------------+--------------+--------|
+ |[cf] |compilation flags (bitwise OR) |number |cf |
+ |---------+---------------------------------------+--------------+--------|
+ |[ef] |execution flags (bitwise OR) |number |ef |
+ |---------+---------------------------------------+--------------+--------|
+ |[lo] |[PCRE] locale |string or |locale |
+ | | |userdata | |
+ +-------------------------------------------------------------------------+
+
+Returns:
+ 1. The subject string with the substitutions made.
+ 2. Number of matches found.
+ 3. Number of substitutions made.
+Details:
+
+ The parameter repl can be either a string, a function or a table. On each
+ match made, it is converted into a value repl_out that may be used for the
+ replacement.
+
+ repl_out is generated differently depending on the type of repl:
+
+ 1. If repl is a string then it is treated as a template for substitution,
+ where the %X occurences in repl are handled in a special way, depending
+ on the value of the character X:
+
+ o if X represents a digit, then each %X occurence is substituted by
+ the value of the X-th submatch (capture), with the following cases
+ handled specially:
+ # each %0 is substituted by the entire match
+ # if the pattern contains no captures, then each %1 is
+ substituted by the entire match
+ # any other %X where X is greater than the number of captures in
+ the pattern will generate an error ("invalid capture index")
+ # if the pattern does contain a capture with number X but that
+ capture didn't participate in the match, then %X is substituted
+ by an empty string
+ o if X is any non-digit character then %X is substituted by X
+
+ All parts of repl other than %X are copied to repl_out verbatim.
+
+ 2. If repl is a function then it is called on each match with the
+ submatches passed as parameters (if there are no submatches then the
+ entire match is passed as the only parameter). repl_out is the return
+ value of the repl call, and is interpreted as follows:
+
+ o if it is a string or a number (coerced to a string), then the
+ replacement value is that string;
+ o if it is a nil or a false, then no replacement is to be done;
+
+ 3. If repl is a table then repl_out is repl [m1], where m1 is the first
+ submatch (or the entire match if there are no submatches), following
+ the same rules as for the return value of repl call, described in the
+ above paragraph.
+
+ Note: Under some circumstances, the value of repl_out may be ignored; see
+ below.
+
+ gsub behaves differently depending on the type of n:
+
+ 1. If n is a number then it is treated as the maximum number of matches to
+ search for (an omitted or nil value means an unlimited number of
+ matches). On each match, the replacement value is the repl_out string
+ (see above).
+
+ 2. If n is a function, then it is called on each match, after repl_out is
+ produced (so if repl is a function, it will be called prior to the n
+ call).
+
+ n receives 3 arguments and returns 2 values. Its arguments are:
+
+ 1. The start offset of the match (a number)
+ 2. The end offset of the match (a number)
+ 3. repl_out
+
+ The type of its first return controls the replacement produced by gsub
+ for the current match:
+
+ # true -- replace/don't replace, according to repl_out;
+ # nil/false -- don't replace;
+ # a string (or a number coerced to a string) -- replace by that
+ string;
+
+ The type of its second return controls gsub behavior after the current
+ match is handled:
+
+ # nil/false -- no changes: n will be called on the next match;
+ # true -- search for an unlimited number of matches; n will not
+ be called again;
+ # a number -- maximum number of matches to search for, beginning
+ from the next match; n will not be called again;
+
+-------------------------------------------------------------------------------
+
+split
+
+rex.split (subj, sep, [cf], [ef], [lo])
+
+The function is intended for use in the generic for Lua construct. It is used
+for splitting a subject string subj into parts (sections). The sep parameter is
+a regular expression pattern representing separators between the sections.
+
+The function returns an iterator for repeated matching of the pattern sep in
+the string subj, subject to flags cf and ef.
+
+PCRE: A locale lo may be specified.
+
+ +-------------------------------------------------------------------------+
+ |Parameter| Description | Type | Default |
+ | | | | Value |
+ |---------+----------------------------------+----------------+-----------|
+ |subj |subject |string |n/a |
+ |---------+----------------------------------+----------------+-----------|
+ |sep |separator (regular expression |string |n/a |
+ | |pattern) | | |
+ |---------+----------------------------------+----------------+-----------|
+ |[cf] |compilation flags (bitwise OR) |number |cf |
+ |---------+----------------------------------+----------------+-----------|
+ |[ef] |execution flags (bitwise OR) |number |ef |
+ |---------+----------------------------------+----------------+-----------|
+ |[lo] |[PCRE] locale |string or |locale |
+ | | |userdata | |
+ +-------------------------------------------------------------------------+
+
+On every iteration pass, the iterator returns:
+
+ 1. A subject section (can be an empty string), followed by
+ 2. All captures in the order they appear in the sep pattern (or the entire
+ match if the sep pattern specified no captures). If there is no match
+ (this can occur only in the last iteration), then nothing is returned
+ after the subject section.
+
+The iteration will continue till the end of the subject. Unlike gmatch, there
+will always be at least one iteration pass, even if there's no matches in the
+subject.
+
+-------------------------------------------------------------------------------
+
+flags
+
+rex.flags ([tb])
+
+This function returns a table containing numeric values of the constants
+defined by the used regex library (either PCRE or POSIX). Those constants are
+keyed by their names (strings). If the table argument tb is supplied then it is
+used as the output table, else a new table is created.
+
+The constants contained in the returned table can then be used in most
+functions and methods where compilation flags or execution flags can be
+specified. They can also be used for comparing with return codes of some
+functions and methods for determining the reason of failure. For details, see
+PCRE and POSIX documentation.
+
+ +--------------------------------------------------------------+
+ |Parameter| Description |Type |Default Value|
+ |---------+--------------------------------+-----+-------------|
+ |[tb] |a table for placing results into|table|nil |
+ +--------------------------------------------------------------+
+
+Returns:
+ 1. A table filled with the results.
+
+-------------------------------------------------------------------------------
+
+new
+
+rex.new (patt, [cf], [lo])
+
+The functions compiles regular expression patt into a regular expression object
+whose internal representation is correspondent to the library used (PCRE or
+POSIX regex). The returned result then can be used by the methods tfind, exec
+and dfa_exec. Regular expression objects are automatically garbage collected.
+
+PCRE: A locale lo may be specified.
+
+ +-------------------------------------------------------------------------+
+ |Parameter| Description | Type |Default Value|
+ |---------+------------------------------+------------------+-------------|
+ |patt |regular expression pattern |string |n/a |
+ |---------+------------------------------+------------------+-------------|
+ |[cf] |compilation flags (bitwise OR)|number |cf |
+ |---------+------------------------------+------------------+-------------|
+ |[lo] |[PCRE] locale |string or userdata|locale |
+ +-------------------------------------------------------------------------+
+
+Returns:
+ 1. Compiled regular expression (a userdata).
+
+-------------------------------------------------------------------------------
+
+tfind
+
+r:tfind (subj, [init], [ef])
+
+The method searches for the first match of the compiled regexp r in the string
+subj, starting from offset init, subject to execution flags ef.
+
+ +-------------------------------------------------------------------------+
+ |Parameter| Description | Type | Default |
+ | | | | Value |
+ |---------+-----------------------------------------+--------+------------|
+ |r |regex object produced by new |userdata|n/a |
+ |---------+-----------------------------------------+--------+------------|
+ |subj |subject |string |n/a |
+ |---------+-----------------------------------------+--------+------------|
+ |[init] |start offset in the subject (can be |number |1 |
+ | |negative) | | |
+ |---------+-----------------------------------------+--------+------------|
+ |[ef] |execution flags (bitwise OR) |number |ef |
+ +-------------------------------------------------------------------------+
+
+Returns on success:
+ 1. The start point of the match (a number).
+ 2. The end point of the match (a number).
+ 3. Substring matches ("captures" in Lua terminology) are returned as a
+ third result, in a table. This table contains false in the positions
+ where the corresponding sub-pattern did not participate in the match.
+ 1. PCRE: if named subpatterns are used then the table also contains
+ substring matches keyed by their correspondent subpattern names
+ (strings).
+Returns on failure:
+ 1. nil
+Notes:
+ 1. If named subpatterns (see PCRE docs) are used then the returned table
+ also contains substring matches keyed by their correspondent subpattern
+ names (strings).
+
+-------------------------------------------------------------------------------
+
+exec
+
+r:exec (subj, [init], [ef])
+
+The method searches for the first match of the compiled regexp r in the string
+subj, starting from offset init, subject to execution flags ef.
+
+ +-------------------------------------------------------------------------+
+ |Parameter| Description | Type | Default |
+ | | | | Value |
+ |---------+-----------------------------------------+--------+------------|
+ |r |regex object produced by new |userdata|n/a |
+ |---------+-----------------------------------------+--------+------------|
+ |subj |subject |string |n/a |
+ |---------+-----------------------------------------+--------+------------|
+ |[init] |start offset in the subject (can be |number |1 |
+ | |negative) | | |
+ |---------+-----------------------------------------+--------+------------|
+ |[ef] |execution flags (bitwise OR) |number |ef |
+ +-------------------------------------------------------------------------+
+
+Returns on success:
+ 1. The start point of the first match (a number).
+ 2. The end point of the first match (a number).
+ 3. The offsets of substring matches ("captures" in Lua terminology) are
+ returned as a third result, in a table. This table contains false in
+ the positions where the corresponding sub-pattern did not participate
+ in the match.
+ 1. PCRE: if named subpatterns are used then the table also contains
+ substring matches keyed by their correspondent subpattern names
+ (strings).
+Returns on failure:
+ 1. nil
+Example:
+ If the whole match is at offsets 10,20 and substring matches are at offsets
+ 12,14 and 16,19 then the function returns the following: 10, 20, {
+ 12,14,16,19 }.
+
+-------------------------------------------------------------------------------
+
+PCRE-only functions and methods
+
+dfa_exec
+
+[PCRE 6.0 and later. See pcre_dfa_exec in the PCRE docs.]
+
+r:dfa_exec (subj, [init], [ef], [ovecsize], [wscount])
+
+The method matches a compiled regular expression r against a given subject
+string subj, using a DFA matching algorithm.
+
+ +-------------------------------------------------------------------------+
+ |Parameter | Description | Type | Default |
+ | | | | Value |
+ |----------+----------------------------------------+--------+------------|
+ |r |regex object produced by new |userdata|n/a |
+ |----------+----------------------------------------+--------+------------|
+ |subj |subject |string |n/a |
+ |----------+----------------------------------------+--------+------------|
+ |[init] |start offset in the subject (can be |number |1 |
+ | |negative) | | |
+ |----------+----------------------------------------+--------+------------|
+ |[ef] |execution flags (bitwise OR) |number |ef |
+ |----------+----------------------------------------+--------+------------|
+ |[ovecsize]|size of the array for result offsets |number |100 |
+ |----------+----------------------------------------+--------+------------|
+ |[wscount] |number of elements in the working space |number |50 |
+ | |array | | |
+ +-------------------------------------------------------------------------+
+
+Returns on success (either full or partial match):
+ 1. The start point of the matches found (a number).
+ 2. A table containing the end points of the matches found, the longer
+ matches first.
+ 3. The return value of the underlying pcre_dfa_exec call (a number).
+Returns on failure (no match):
+ 1. nil
+Example:
+ If there are 3 matches found starting at offset 10 and ending at offsets
+ 15, 20 and 25 then the function returns the following: 10, { 25,20,15 }, 3.
+
+-------------------------------------------------------------------------------
+
+maketables
+
+[PCRE only. See pcre_maketables in the PCRE docs.]
+
+rex.maketables ()
+
+Creates a set of character tables corresponding to the current locale and
+returns it as a userdata. The returned value can be passed to any Lrexlib
+function accepting the locale parameter.
+
+-------------------------------------------------------------------------------
+
+config
+
+[PCRE 4.0 and later. See pcre_config in the PCRE docs.]
+
+rex.config ([tb])
+
+This function returns a table containing the values of the configuration
+parameters used at PCRE library build-time. Those parameters (numbers) are
+keyed by their names (strings). If the table argument tb is supplied then it is
+used as the output table, else a new table is created.
+
+ +--------------------------------------------------------------+
+ |Parameter| Description |Type |Default Value|
+ |---------+--------------------------------+-----+-------------|
+ |[tb] |a table for placing results into|table|nil |
+ +--------------------------------------------------------------+
+
+Returns:
+ 1. A table filled with the results.
+
+-------------------------------------------------------------------------------
+
+version
+
+[PCRE only. See pcre_version in the PCRE docs.]
+
+rex.version ()
+
+This function returns a string containing the version of the used PCRE library
+and its release date.
+
+-------------------------------------------------------------------------------
+
+Other functions
+
+plainfind
+
+rex.plainfind (subj, patt, [init], [ci])
+
+The function searches for the first match of the string patt in the subject
+subj, starting from offset init.
+
+ + The string patt is not regular expression, all its characters stand for
+ themselves.
+ + Both strings subj and patt can have embedded zeros.
+ + The flag ci specifies case-insensitive search (current locale is used).
+ + This function uses neither PCRE nor POSIX regex library.
+ +-------------------------------------------------------------------------+
+ |Parameter| Description | Type | Default |
+ | | | | Value |
+ |---------+------------------------------------------+-------+------------|
+ |subj |subject |string |n/a |
+ |---------+------------------------------------------+-------+------------|
+ |patt |text to find |string |n/a |
+ |---------+------------------------------------------+-------+------------|
+ |[init] |start offset in the subject (can be |number |1 |
+ | |negative) | | |
+ |---------+------------------------------------------+-------+------------|
+ |[ci] |case insensitive search |boolean|false |
+ +-------------------------------------------------------------------------+
+
+Returns on success:
+ 1. The start point of the match (a number).
+ 2. The end point of the match (a number).
+Returns on failure:
+ 1. nil
+
+-------------------------------------------------------------------------------
+
+Incompatibilities with the Previous Versions
+
+Incompatibilities between the versions 2.0 and 1.19:
+
+ 1. Lua 5.1 is required
+ 2. Functions newPCRE and newPOSIX renamed to new
+ 3. Functions flagsPCRE and flagsPOSIX renamed to flags
+ 4. Function versionPCRE renamed to version
+ 5. Method match renamed to tfind
+ 6. Method gmatch removed (similar functionality is provided by function
+ gmatch)
+ 7. Methods tfind and exec: 2 values are returned on failure
+ 8. (PCRE) exec: the returned table may additionally contain named
+ subpatterns
+
+Incompatibilities between the versions 2.1 and 2.0:
+
+ 1. match, find, tfind, exec, dfa_exec: only one value (a nil) is returned
+ when the subject does not match the pattern. Any other failure
+ generates an error.
+
+Incompatibilities between the versions 2.2 and 2.1:
+
+ 1. gsub: a special "break" return of repl function is deprecated.
+ 2. (PCRE) gsub, gmatch: after finding an empty match at the current
+ position, the functions try to find a non-empty match anchored to the
+ same position.
+
@@ .
patch -p0 <<'@@ .'
Index: lua/local/lrexlib_algo.h
============================================================================
$ cvs diff -u -r0 -r1.1 lrexlib_algo.h
--- /dev/null 2008-01-12 13:33:00 +0100
+++ lrexlib_algo.h 2008-01-12 13:33:33 +0100
@@ -0,0 +1,623 @@
+/* algo.h */
+/* See Copyright Notice in the file LICENSE */
+
+#include "lrexlib_common.h"
+
+#define REX_VERSION "Lrexlib 2.2.2"
+
+/* Forward declarations */
+static void gmatch_pushsubject (lua_State *L, TArgExec *argE);
+static int findmatch_exec (TUserdata *ud, TArgExec *argE);
+static int tfind_exec (TUserdata *ud, TArgExec *argE);
+static int split_exec (TUserdata *ud, TArgExec *argE, int offset);
+static int compile_regex (lua_State *L, const TArgComp *argC, TUserdata **pud);
+static int generate_error (lua_State *L, const TUserdata *ud, int errcode);
+
+#ifndef ALG_OPTLOCALE
+# define ALG_OPTLOCALE(a,b,c) ((void)a)
+#endif
+
+
+/* When doing an iterative search, there can occur a situation of a zero-length
+ * match at the current position, that prevents further advance on the subject
+ * string.
+ * There are two ways to handle that (AFAIK):
+ * a) Advance by one character (continue the search from the next position),
+ * or
+ * b) Search for a non-zero-length match that begins from the current
+ * position ("retry" the search). If the match is not found then advance
+ * by one character.
+ * The "b)" seems more correct, but most regex libraries expose no API for that.
+ * The known exception is PCRE that has flags PCRE_NOTEMPTY and PCRE_ANCHORED.
+ */
+#ifdef ALG_USERETRY
+ #define SET_RETRY(a,b) (a=b)
+ static int gsub_exec (TUserdata *ud, TArgExec *argE, int offset, int retry);
+ static int gmatch_exec (TUserdata *ud, TArgExec *argE, int retry);
+ #define GSUB_EXEC gsub_exec
+ #define GMATCH_EXEC gmatch_exec
+#else
+ #define SET_RETRY(a,b) ((void)a)
+ static int gsub_exec (TUserdata *ud, TArgExec *argE, int offset);
+ static int gmatch_exec (TUserdata *ud, TArgExec *argE);
+ #define GSUB_EXEC(a,b,c,d) gsub_exec(a,b,c)
+ #define GMATCH_EXEC(a,b,c) gmatch_exec(a,b)
+#endif
+
+
+static int OptLimit (lua_State *L, int pos) {
+ if (lua_isnoneornil (L, pos))
+ return GSUB_UNLIMITED;
+ if (lua_isfunction (L, pos))
+ return GSUB_CONDITIONAL;
+ if (lua_isnumber (L, pos)) {
+ int a = lua_tointeger (L, pos);
+ return a < 0 ? 0 : a;
+ }
+ return luaL_argerror (L, pos, "number or function expected");
+}
+
+
+static int get_startoffset(lua_State *L, int stackpos, size_t len) {
+ int startoffset = luaL_optint(L, stackpos, 1);
+ if(startoffset > 0)
+ startoffset--;
+ else if(startoffset < 0) {
+ startoffset += len;
+ if(startoffset < 0)
+ startoffset = 0;
+ }
+ return startoffset;
+}
+
+
+static TUserdata* check_ud (lua_State *L)
+{
+ TUserdata *ud;
+ if (lua_getmetatable(L, 1) &&
+ lua_rawequal(L, -1, LUA_ENVIRONINDEX) &&
+ (ud = (TUserdata *)lua_touserdata(L, 1)) != NULL) {
+ lua_pop(L, 1);
+ return ud;
+ }
+ luaL_argerror(L, 1, "incorrect type");
+ return NULL;
+}
+
+
+static void checkarg_new (lua_State *L, TArgComp *argC) {
+ argC->pattern = luaL_checklstring (L, 1, &argC->patlen);
+ argC->cflags = ALG_GETCFLAGS (L, 2);
+ ALG_OPTLOCALE (argC, L, 3);
+}
+
+
+/* function gsub (s, patt, f, [n], [cf], [ef], [lo]) */
+static void checkarg_gsub (lua_State *L, TArgComp *argC, TArgExec *argE) {
+ argE->text = luaL_checklstring (L, 1, &argE->textlen);
+ argC->pattern = luaL_checklstring (L, 2, &argC->patlen);
+ lua_tostring (L, 3); /* converts number (if any) to string */
+ argE->reptype = lua_type (L, 3);
+ if (argE->reptype != LUA_TSTRING && argE->reptype != LUA_TTABLE &&
+ argE->reptype != LUA_TFUNCTION) {
+ luaL_argerror (L, 3, "must be string, table or function");
+ }
+ argE->funcpos = 3;
+ argE->funcpos2 = 4;
+ argE->maxmatch = OptLimit (L, 4);
+ argC->cflags = ALG_GETCFLAGS (L, 5);
+ argE->eflags = luaL_optint (L, 6, ALG_EFLAGS_DFLT);
+ ALG_OPTLOCALE (argC, L, 7);
+}
+
+
+/* function find (s, patt, [st], [cf], [ef], [lo]) */
+/* function match (s, patt, [st], [cf], [ef], [lo]) */
+static void checkarg_find_f (lua_State *L, TArgComp *argC, TArgExec *argE) {
+ argE->text = luaL_checklstring (L, 1, &argE->textlen);
+ argC->pattern = luaL_checklstring (L, 2, &argC->patlen);
+ argE->startoffset = get_startoffset (L, 3, argE->textlen);
+ argC->cflags = ALG_GETCFLAGS (L, 4);
+ argE->eflags = luaL_optint (L, 5, ALG_EFLAGS_DFLT);
+ ALG_OPTLOCALE (argC, L, 6);
+}
+
+
+/* function gmatch (s, patt, [cf], [ef], [lo]) */
+/* function split (s, patt, [cf], [ef], [lo]) */
+static void checkarg_gmatch_split (lua_State *L, TArgComp *argC, TArgExec *argE) {
+ argE->text = luaL_checklstring (L, 1, &argE->textlen);
+ argC->pattern = luaL_checklstring (L, 2, &argC->patlen);
+ argC->cflags = ALG_GETCFLAGS (L, 3);
+ argE->eflags = luaL_optint (L, 4, ALG_EFLAGS_DFLT);
+ ALG_OPTLOCALE (argC, L, 5);
+}
+
+
+/* method r:tfind (s, [st], [ef]) */
+/* method r:exec (s, [st], [ef]) */
+static void checkarg_tfind (lua_State *L, TArgExec *argE, TUserdata **ud) {
+ *ud = check_ud (L);
+ argE->text = luaL_checklstring (L, 2, &argE->textlen);
+ argE->startoffset = get_startoffset (L, 3, argE->textlen);
+ argE->eflags = luaL_optint (L, 4, ALG_EFLAGS_DFLT);
+}
+
+
+static int ud_new (lua_State *L) {
+ TArgComp argC;
+ checkarg_new (L, &argC);
+ return compile_regex (L, &argC, NULL);
+}
+
+static void push_substrings (lua_State *L, TUserdata *ud, const char *text,
+ TFreeList *freelist) {
+ int i;
+ if (lua_checkstack (L, ALG_NSUB(ud)) == 0) {
+ if (freelist)
+ freelist_free (freelist);
+ luaL_error (L, "cannot add %d stack slots", ALG_NSUB(ud));
+ }
+ for (i = 1; i <= ALG_NSUB(ud); i++) {
+ ALG_PUSHSUB_OR_FALSE (L, ud, text, i);
+ }
+}
+
+static int gsub (lua_State *L) {
+ TUserdata *ud;
+ TArgComp argC;
+ TArgExec argE;
+ int n_match = 0, n_subst = 0, st = 0, retry;
+ TBuffer BufOut, BufRep, BufTemp, *pBuf = &BufOut;
+ TFreeList freelist;
+ /*------------------------------------------------------------------*/
+ checkarg_gsub (L, &argC, &argE);
+ compile_regex (L, &argC, &ud);
+ freelist_init (&freelist);
+ /*------------------------------------------------------------------*/
+ if (argE.reptype == LUA_TSTRING) {
+ buffer_init (&BufRep, 256, L, &freelist);
+ bufferZ_putrepstring (&BufRep, argE.funcpos, ALG_NSUB(ud));
+ }
+ /*------------------------------------------------------------------*/
+ if (argE.maxmatch == GSUB_CONDITIONAL) {
+ buffer_init (&BufTemp, 1024, L, &freelist);
+ pBuf = &BufTemp;
+ }
+ /*------------------------------------------------------------------*/
+ buffer_init (&BufOut, 1024, L, &freelist);
+ SET_RETRY (retry, 0);
+ while ((argE.maxmatch < 0 || n_match < argE.maxmatch) && st <= (int)argE.textlen) {
+ int from, to, res;
+ int curr_subst = 0;
+ res = GSUB_EXEC (ud, &argE, st, retry);
+ if (res == ALG_NOMATCH) {
+#ifdef ALG_USERETRY
+ if (retry) {
+ if (st < (int)argE.textlen) { /* advance by 1 char (not replaced) */
+ buffer_addlstring (&BufOut, argE.text + st, 1);
+ ++st;
+ retry = 0;
+ continue;
+ }
+ }
+#endif
+ break;
+ }
+ else if (!ALG_ISMATCH (res)) {
+ freelist_free (&freelist);
+ return generate_error (L, ud, res);
+ }
+ ++n_match;
+ from = ALG_BASE(st) + ALG_SUBBEG(ud,0);
+ to = ALG_BASE(st) + ALG_SUBEND(ud,0);
+ if (st < from) {
+ buffer_addlstring (&BufOut, argE.text + st, from - st);
+#ifdef ALG_PULL
+ st = from;
+#endif
+ }
+ /*----------------------------------------------------------------*/
+ if (argE.reptype == LUA_TSTRING) {
+ size_t iter = 0, num;
+ const char *str;
+ while (bufferZ_next (&BufRep, &iter, &num, &str)) {
+ if (str)
+ buffer_addlstring (pBuf, str, num);
+ else if (num == 0 || ALG_SUBVALID (ud,num))
+ buffer_addlstring (pBuf, argE.text + ALG_BASE(st) + ALG_SUBBEG(ud,num), ALG_SUBLEN(ud,num));
+ }
+ curr_subst = 1;
+ }
+ /*----------------------------------------------------------------*/
+ else if (argE.reptype == LUA_TTABLE) {
+ if (ALG_NSUB(ud) > 0)
+ ALG_PUSHSUB_OR_FALSE (L, ud, argE.text + ALG_BASE(st), 1);
+ else
+ lua_pushlstring (L, argE.text + from, to - from);
+ lua_gettable (L, argE.funcpos);
+ }
+ /*----------------------------------------------------------------*/
+ else if (argE.reptype == LUA_TFUNCTION) {
+ int narg;
+ lua_pushvalue (L, argE.funcpos);
+ if (ALG_NSUB(ud) > 0) {
+ push_substrings (L, ud, argE.text + ALG_BASE(st), &freelist);
+ narg = ALG_NSUB(ud);
+ }
+ else {
+ lua_pushlstring (L, argE.text + from, to - from);
+ narg = 1;
+ }
+ if (0 != lua_pcall (L, narg, 1, 0)) {
+ freelist_free (&freelist);
+ return lua_error (L); /* re-raise the error */
+ }
+ }
+ /*----------------------------------------------------------------*/
+ if (argE.reptype != LUA_TSTRING) {
+ if (lua_tostring (L, -1)) {
+ buffer_addvalue (pBuf, -1);
+ curr_subst = 1;
+ }
+ else if (!lua_toboolean (L, -1))
+ buffer_addlstring (pBuf, argE.text + from, to - from);
+ else {
+ freelist_free (&freelist);
+ luaL_error (L, "invalid replacement value (a %s)", luaL_typename (L, -1));
+ }
+ if (argE.maxmatch != GSUB_CONDITIONAL)
+ lua_pop (L, 1);
+ }
+ /*----------------------------------------------------------------*/
+ if (argE.maxmatch == GSUB_CONDITIONAL) {
+ /* Call the function */
+ lua_pushvalue (L, argE.funcpos2);
+ lua_pushinteger (L, from + 1);
+ lua_pushinteger (L, to);
+ if (argE.reptype == LUA_TSTRING)
+ buffer_pushresult (&BufTemp);
+ else {
+ lua_pushvalue (L, -4);
+ lua_remove (L, -5);
+ }
+ if (0 != lua_pcall (L, 3, 2, 0)) {
+ freelist_free (&freelist);
+ lua_error (L); /* re-raise the error */
+ }
+ /* Handle the 1-st return value */
+ if (lua_isstring (L, -2)) { /* coercion is allowed here */
+ buffer_addvalue (&BufOut, -2); /* rep2 */
+ curr_subst = 1;
+ }
+ else if (lua_toboolean (L, -2))
+ buffer_addbuffer (&BufOut, &BufTemp); /* rep1 */
+ else {
+ buffer_addlstring (&BufOut, argE.text + from, to - from); /* "no" */
+ curr_subst = 0;
+ }
+ /* Handle the 2-nd return value */
+ if (lua_type (L, -1) == LUA_TNUMBER) { /* no coercion is allowed here */
+ int n = lua_tointeger (L, -1);
+ if (n < 0) /* n */
+ n = 0;
+ argE.maxmatch = n_match + n;
+ }
+ else if (lua_toboolean (L, -1)) /* "yes to all" */
+ argE.maxmatch = GSUB_UNLIMITED;
+ else
+ buffer_clear (&BufTemp);
+
+ lua_pop (L, 2);
+ if (argE.maxmatch != GSUB_CONDITIONAL)
+ pBuf = &BufOut;
+ }
+ /*----------------------------------------------------------------*/
+ n_subst += curr_subst;
+ if (st < to) {
+ st = to;
+ SET_RETRY (retry, 0);
+ }
+ else if (st < (int)argE.textlen) {
+#ifdef ALG_USERETRY
+ retry = 1;
+#else
+ /* advance by 1 char (not replaced) */
+ buffer_addlstring (&BufOut, argE.text + st, 1);
+ ++st;
+#endif
+ }
+ else break;
+ }
+ /*------------------------------------------------------------------*/
+ buffer_addlstring (&BufOut, argE.text + st, argE.textlen - st);
+ buffer_pushresult (&BufOut);
+ lua_pushinteger (L, n_match);
+ lua_pushinteger (L, n_subst);
+ freelist_free (&freelist);
+ return 3;
+}
+
+
+static int generic_find (lua_State *L, int find) {
+ int res;
+ TUserdata *ud;
+ TArgComp argC;
+ TArgExec argE;
+
+ checkarg_find_f (L, &argC, &argE);
+ if (argE.startoffset > (int)argE.textlen)
+ return lua_pushnil(L), 1;
+
+ compile_regex (L, &argC, &ud);
+ res = findmatch_exec (ud, &argE);
+ if (ALG_ISMATCH (res)) {
+ if (find)
+ ALG_PUSHOFFSETS (L, ud, ALG_BASE(argE.startoffset), 0);
+ if (ALG_NSUB(ud)) /* push captures */
+ push_substrings (L, ud, argE.text, NULL);
+ else if (!find) {
+ ALG_PUSHSUB (L, ud, argE.text, 0);
+ return 1;
+ }
+ return find ? ALG_NSUB(ud) + 2 : ALG_NSUB(ud);
+ }
+ else if (res == ALG_NOMATCH)
+ return lua_pushnil (L), 1;
+ else
+ return generate_error (L, ud, res);
+}
+
+
+static int find (lua_State *L) {
+ return generic_find (L, 1);
+}
+
+
+static int match (lua_State *L) {
+ return generic_find (L, 0);
+}
+
+
+static int gmatch_iter (lua_State *L) {
+ int retry;
+ TArgExec argE;
+ TUserdata *ud = (TUserdata*) lua_touserdata (L, lua_upvalueindex (1));
+ argE.text = lua_tolstring (L, lua_upvalueindex (2), &argE.textlen);
+ argE.eflags = lua_tointeger (L, lua_upvalueindex (3));
+ argE.startoffset = lua_tointeger (L, lua_upvalueindex (4));
+#ifdef ALG_USERETRY
+ retry = lua_tointeger (L, lua_upvalueindex (5));
+#endif
+
+ if (argE.startoffset > (int)argE.textlen)
+ return 0;
+
+ while (1) {
+ int res = GMATCH_EXEC (ud, &argE, retry);
+ if (ALG_ISMATCH (res)) {
+ int incr = 0;
+ if (ALG_SUBLEN(ud,0)) {
+ SET_RETRY (retry, 0);
+ }
+ else { /* no progress: prevent endless loop */
+#ifdef ALG_USERETRY
+ SET_RETRY (retry, 1);
+#else
+ incr = 1;
+#endif
+ }
+ ALG_PUSHEND (L, ud, ALG_BASE(argE.startoffset)+incr, 0); /* update start offset */
+ lua_replace (L, lua_upvalueindex (4));
+#ifdef ALG_USERETRY
+ lua_pushinteger (L, retry);
+ lua_replace (L, lua_upvalueindex (5)); /* update retry */
+#endif
+ /* push either captures or entire match */
+ if (ALG_NSUB(ud)) {
+ push_substrings (L, ud, argE.text, NULL);
+ return ALG_NSUB(ud);
+ }
+ else {
+ ALG_PUSHSUB (L, ud, argE.text, 0);
+ return 1;
+ }
+ }
+ else if (res == ALG_NOMATCH) {
+#ifdef ALG_USERETRY
+ if (retry) {
+ if (argE.startoffset < (int)argE.textlen) {
+ ++argE.startoffset; /* advance by 1 char */
+ SET_RETRY (retry, 0);
+ continue;
+ }
+ }
+#endif
+ return 0;
+ }
+ else
+ return generate_error (L, ud, res);
+ }
+}
+
+
+static int split_iter (lua_State *L) {
+ int incr, newoffset, res;
+ TArgExec argE;
+ TUserdata *ud = (TUserdata*) lua_touserdata (L, lua_upvalueindex (1));
+ argE.text = lua_tolstring (L, lua_upvalueindex (2), &argE.textlen);
+ argE.eflags = lua_tointeger (L, lua_upvalueindex (3));
+ argE.startoffset = lua_tointeger (L, lua_upvalueindex (4));
+ incr = lua_tointeger (L, lua_upvalueindex (5));
+
+ if (argE.startoffset > (int)argE.textlen)
+ return 0;
+
+ newoffset = argE.startoffset + incr;
+ res = split_exec (ud, &argE, newoffset);
+ if (ALG_ISMATCH (res)) {
+ ALG_PUSHEND (L, ud, ALG_BASE(newoffset), 0); /* update start offset */
+ lua_replace (L, lua_upvalueindex (4));
+ lua_pushinteger (L, ALG_SUBLEN(ud,0) ? 0 : 1); /* update incr */
+ lua_replace (L, lua_upvalueindex (5));
+ /* push text preceding the match */
+ lua_pushlstring (L, argE.text + argE.startoffset,
+ ALG_SUBBEG(ud,0) + ALG_BASE(newoffset) - argE.startoffset);
+ /* push either captures or entire match */
+ if (ALG_NSUB(ud)) {
+ push_substrings (L, ud, argE.text + ALG_BASE(newoffset), NULL);
+ return 1 + ALG_NSUB(ud);
+ }
+ else {
+ ALG_PUSHSUB (L, ud, argE.text + ALG_BASE(newoffset), 0);
+ return 2;
+ }
+ }
+ else if (res == ALG_NOMATCH) {
+ lua_pushinteger (L, argE.textlen + 1); /* mark as last iteration */
+ lua_replace (L, lua_upvalueindex (4)); /* update start offset */
+ lua_pushlstring (L, argE.text+argE.startoffset, argE.textlen-argE.startoffset);
+ return 1;
+ }
+ else
+ return generate_error (L, ud, res);
+}
+
+
+static int gmatch (lua_State *L)
+{
+ TArgComp argC;
+ TArgExec argE;
+ TUserdata *ud;
+ checkarg_gmatch_split (L, &argC, &argE);
+ compile_regex (L, &argC, &ud); /* 1-st upvalue: ud */
+ gmatch_pushsubject (L, &argE); /* 2-nd upvalue: s */
+ lua_pushinteger (L, argE.eflags); /* 3-rd upvalue: ef */
+ lua_pushinteger (L, 0); /* 4-th upvalue: startoffset */
+#ifdef ALG_USERETRY
+ lua_pushinteger (L, 0); /* 5-th upvalue: retry */
+ lua_pushcclosure (L, gmatch_iter, 5);
+#else
+ lua_pushcclosure (L, gmatch_iter, 4);
+#endif
+ return 1;
+}
+
+static int split (lua_State *L)
+{
+ TArgComp argC;
+ TArgExec argE;
+ TUserdata *ud;
+ checkarg_gmatch_split (L, &argC, &argE);
+ compile_regex (L, &argC, &ud); /* 1-st upvalue: ud */
+ gmatch_pushsubject (L, &argE); /* 2-nd upvalue: s */
+ lua_pushinteger (L, argE.eflags); /* 3-rd upvalue: ef */
+ lua_pushinteger (L, 0); /* 4-th upvalue: startoffset */
+ lua_pushinteger (L, 0); /* 5-th upvalue: incr */
+ lua_pushcclosure (L, split_iter, 5);
+ return 1;
+}
+
+
+static void push_substring_table (lua_State *L, TUserdata *ud, const char *text) {
+ int i;
+ lua_newtable (L);
+ for (i = 1; i <= ALG_NSUB(ud); i++) {
+ ALG_PUSHSUB_OR_FALSE (L, ud, text, i);
+ lua_rawseti (L, -2, i);
+ }
+}
+
+
+static void push_offset_table (lua_State *L, TUserdata *ud, int startoffset) {
+ int i, j;
+ lua_newtable (L);
+ for (i=1, j=1; i <= ALG_NSUB(ud); i++) {
+ if (ALG_SUBVALID (ud,i)) {
+ ALG_PUSHSTART (L, ud, startoffset, i);
+ lua_rawseti (L, -2, j++);
+ ALG_PUSHEND (L, ud, startoffset, i);
+ lua_rawseti (L, -2, j++);
+ }
+ else {
+ lua_pushboolean (L, 0);
+ lua_rawseti (L, -2, j++);
+ lua_pushboolean (L, 0);
+ lua_rawseti (L, -2, j++);
+ }
+ }
+}
+
+
+static int generic_tfind (lua_State *L, int tfind) {
+ TUserdata *ud;
+ TArgExec argE;
+ int res;
+
+ checkarg_tfind (L, &argE, &ud);
+ if (argE.startoffset > (int)argE.textlen)
+ return lua_pushnil(L), 1;
+
+ res = tfind_exec (ud, &argE);
+ if (ALG_ISMATCH (res)) {
+ ALG_PUSHOFFSETS (L, ud, ALG_BASE(argE.startoffset), 0);
+ if (tfind)
+ push_substring_table (L, ud, argE.text);
+ else
+ push_offset_table (L, ud, ALG_BASE(argE.startoffset));
+#ifdef DO_NAMED_SUBPATTERNS
+ DO_NAMED_SUBPATTERNS (L, ud, argE.text);
+#endif
+ return 3;
+ }
+ else if (res == ALG_NOMATCH)
+ return lua_pushnil (L), 1;
+ else
+ return generate_error(L, ud, res);
+}
+
+
+static int ud_tfind (lua_State *L) {
+ return generic_tfind (L, 1);
+}
+
+
+static int ud_exec (lua_State *L) {
+ return generic_tfind (L, 0);
+}
+
+
+/* function plainfind (s, p, [st], [ci]) */
+static int plainfind_func (lua_State *L) {
+ size_t textlen, patlen;
+ const char *text = luaL_checklstring (L, 1, &textlen);
+ const char *pattern = luaL_checklstring (L, 2, &patlen);
+ const char *from = text + get_startoffset (L, 3, textlen);
+ int ci = lua_toboolean (L, 4);
+ const char *end = text + textlen;
+
+ for (; from + patlen <= end; ++from) {
+ const char *f = from, *p = pattern;
+ size_t len = patlen + 1;
+ if (ci) {
+ while (--len) {
+ if (toupper (*f++) != toupper (*p++))
+ break;
+ }
+ }
+ else {
+ while (--len) {
+ if (*f++ != *p++)
+ break;
+ }
+ }
+ if (len == 0) {
+ lua_pushinteger (L, from - text + 1);
+ lua_pushinteger (L, from - text + patlen);
+ return 2;
+ }
+ }
+ lua_pushnil (L);
+ return 1;
+}
+
@@ .
patch -p0 <<'@@ .'
Index: lua/local/lrexlib_common.c
============================================================================
$ cvs diff -u -r0 -r1.1 lrexlib_common.c
--- /dev/null 2008-01-12 13:33:00 +0100
+++ lrexlib_common.c 2008-01-12 13:33:34 +0100
@@ -0,0 +1,244 @@
+/* common.c */
+/* See Copyright Notice in the file LICENSE */
+
+#if defined(LUA_USE_POSIX) || defined(LUA_USE_PCRE)
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "lua.h"
+#include "lauxlib.h"
+#include "lrexlib_common.h"
+
+/* the table must be on Lua stack top */
+int get_int_field (lua_State *L, const char* field)
+{
+ int val;
+ lua_getfield (L, -1, field);
+ val = lua_tointeger (L, -1);
+ lua_pop (L, 1);
+ return val;
+}
+
+/* the table must be on Lua stack top */
+void set_int_field (lua_State *L, const char* field, int val)
+{
+ lua_pushinteger (L, val);
+ lua_setfield (L, -2, field);
+}
+
+void *Lmalloc(lua_State *L, size_t size) {
+ void *p = malloc(size);
+ if(p == NULL)
+ luaL_error(L, "malloc failed");
+ return p;
+}
+
+/* This function fills a table with string-number pairs.
+ The table can be passed as the 1-st lua-function parameter,
+ otherwise it is created. The return value is the filled table.
+*/
+int get_flags (lua_State *L, const flag_pair **arrs) {
+ const flag_pair *p;
+ const flag_pair **pp;
+ int nparams = lua_gettop(L);
+
+ if(nparams == 0)
+ lua_newtable(L);
+ else {
+ if(!lua_istable(L, 1))
+ luaL_argerror(L, 1, "not a table");
+ if(nparams > 1)
+ lua_pushvalue(L, 1);
+ }
+
+ for(pp=arrs; *pp; ++pp) {
+ for(p=*pp; p->key; ++p) {
+ lua_pushstring(L, p->key);
+ lua_pushinteger(L, p->val);
+ lua_rawset(L, -3);
+ }
+ }
+ return 1;
+}
+
+const char *get_flag_key (const flag_pair *fp, int val) {
+ for (; fp->key; ++fp) {
+ if (fp->val == val)
+ return fp->key;
+ }
+ return NULL;
+}
+
+/* Classes */
+
+/*
+ * class TFreeList
+ * ***************
+ * Simple array of pointers to TBuffer's.
+ * The array has fixed capacity (not expanded automatically).
+ */
+
+void freelist_init (TFreeList *fl) {
+ fl->top = 0;
+}
+
+void freelist_add (TFreeList *fl, TBuffer *buf) {
+ fl->list[fl->top++] = buf;
+}
+
+void freelist_free (TFreeList *fl) {
+ while (fl->top > 0)
+ buffer_free (fl->list[--fl->top]);
+}
+
+/*
+ * class TBuffer
+ * *************
+ * Auto-extensible array of characters for building long strings incrementally.
+ * * Differs from luaL_Buffer in that:
+ * * it does not use Lua facilities (except luaL_error when malloc fails)
+ * * its operations do not change Lua stack top position
+ * * buffer_addvalue does not extract the value from Lua stack
+ * * buffer_pushresult does not have to be the last operation
+ * * Uses TFreeList class:
+ * * for inserting itself into a TFreeList instance for future clean-up
+ * * calls freelist_free prior to calling luaL_error.
+ * * Has specialized "Z-operations" for maintaining mixed string/integer
+ * array: bufferZ_addlstring, bufferZ_addnum and bufferZ_next.
+ * * if the array is intended to be "mixed", then the methods
+ * buffer_addlstring and buffer_addvalue must not be used
+ * (the application will crash on bufferZ_next).
+ * * conversely, if the array is not intended to be "mixed",
+ * then the method bufferZ_next must not be used.
+ */
+
+enum { ID_NUMBER, ID_STRING };
+
+void buffer_init (TBuffer *buf, size_t sz, lua_State *L, TFreeList *fl) {
+ buf->arr = (char*) malloc (sz);
+ if (!buf->arr) {
+ freelist_free (fl);
+ luaL_error (L, "malloc failed");
+ }
+ buf->size = sz;
+ buf->top = 0;
+ buf->L = L;
+ buf->freelist = fl;
+ freelist_add (fl, buf);
+}
+
+void buffer_free (TBuffer *buf) {
+ free (buf->arr);
+}
+
+void buffer_clear (TBuffer *buf) {
+ buf->top = 0;
+}
+
+void buffer_pushresult (TBuffer *buf) {
+ lua_pushlstring (buf->L, buf->arr, buf->top);
+}
+
+void buffer_addbuffer (TBuffer *trg, TBuffer *src) {
+ buffer_addlstring (trg, src->arr, src->top);
+}
+
+void buffer_addlstring (TBuffer *buf, const void *src, size_t sz) {
+ size_t newtop = buf->top + sz;
+ if (newtop > buf->size) {
+ char *p = (char*) realloc (buf->arr, 2 * newtop); /* 2x expansion */
+ if (!p) {
+ freelist_free (buf->freelist);
+ luaL_error (buf->L, "realloc failed");
+ }
+ buf->arr = p;
+ buf->size = 2 * newtop;
+ }
+ memcpy (buf->arr + buf->top, src, sz);
+ buf->top = newtop;
+}
+
+void buffer_addvalue (TBuffer *buf, int stackpos) {
+ size_t len;
+ const char *p = lua_tolstring (buf->L, stackpos, &len);
+ buffer_addlstring (buf, p, len);
+}
+
+static void bufferZ_addlstring (TBuffer *buf, const void *src, size_t len) {
+ size_t header[2] = { ID_STRING };
+ header[1] = len;
+ buffer_addlstring (buf, header, sizeof (header));
+ buffer_addlstring (buf, src, len);
+}
+
+static void bufferZ_addnum (TBuffer *buf, size_t num) {
+ size_t header[2] = { ID_NUMBER };
+ header[1] = num;
+ buffer_addlstring (buf, header, sizeof (header));
+}
+
+/* 1. When called repeatedly on the same TBuffer, its existing data
+ is discarded and overwritten by the new data.
+ 2. The TBuffer's array is never shrunk by this function.
+*/
+void bufferZ_putrepstring (TBuffer *BufRep, int reppos, int nsub) {
+ char dbuf[] = { 0, 0 };
+ size_t replen;
+ const char *p = lua_tolstring (BufRep->L, reppos, &replen);
+ const char *end = p + replen;
+ BufRep->top = 0;
+ while (p < end) {
+ const char *q;
+ for (q = p; q < end && *q != '%'; ++q)
+ {}
+ if (q != p)
+ bufferZ_addlstring (BufRep, p, q - p);
+ if (q < end) {
+ if (++q < end) { /* skip % */
+ if (isdigit (*q)) {
+ int num;
+ *dbuf = *q;
+ num = atoi (dbuf);
+ if (num == 1 && nsub == 0)
+ num = 0;
+ else if (num > nsub) {
+ freelist_free (BufRep->freelist);
+ luaL_error (BufRep->L, "invalid capture index");
+ }
+ bufferZ_addnum (BufRep, num);
+ }
+ else bufferZ_addlstring (BufRep, q, 1);
+ }
+ p = q + 1;
+ }
+ else break;
+ }
+}
+
+/******************************************************************************
+ The intended use of this function is as follows:
+ size_t iter = 0;
+ while (bufferZ_next (buf, &iter, &num, &str)) {
+ if (str) do_something_with_string (str, num);
+ else do_something_with_number (num);
+ }
+*******************************************************************************
+*/
+int bufferZ_next (TBuffer *buf, size_t *iter, size_t *num, const char **str) {
+ if (*iter < buf->top) {
+ size_t *ptr_header = (size_t*)(buf->arr + *iter);
+ *num = ptr_header[1];
+ *iter += 2 * sizeof (size_t);
+ *str = NULL;
+ if (*ptr_header == ID_STRING) {
+ *str = buf->arr + *iter;
+ *iter += *num;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+#endif
+
@@ .
patch -p0 <<'@@ .'
Index: lua/local/lrexlib_common.h
============================================================================
$ cvs diff -u -r0 -r1.1 lrexlib_common.h
--- /dev/null 2008-01-12 13:33:00 +0100
+++ lrexlib_common.h 2008-01-12 13:33:34 +0100
@@ -0,0 +1,86 @@
+/* common.h */
+/* See Copyright Notice in the file LICENSE */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include "lua.h"
+
+/* REX_API can be overridden from the command line or Makefile */
+#ifndef REX_API
+# define REX_API LUALIB_API
+#endif
+
+/* Special values for maxmatch in gsub. They all must be negative. */
+#define GSUB_UNLIMITED -1
+#define GSUB_CONDITIONAL -2
+
+/* Common structs and functions */
+
+typedef struct {
+ const char* key;
+ int val;
+} flag_pair;
+
+typedef struct { /* compile arguments */
+ const char * pattern;
+ size_t patlen;
+ int cflags;
+ const char * locale;
+ const unsigned char * tables;
+ int tablespos;
+} TArgComp;
+
+typedef struct { /* exec arguments */
+ const char * text;
+ size_t textlen;
+ int startoffset;
+ int eflags;
+ int funcpos;
+ int maxmatch;
+ int funcpos2; /* used with gsub */
+ int reptype; /* used with gsub */
+ size_t ovecsize; /* used with dfa_exec */
+ size_t wscount; /* used with dfa_exec */
+} TArgExec;
+
+struct tagFreeList; /* forward declaration */
+
+struct tagBuffer {
+ size_t size;
+ size_t top;
+ char * arr;
+ lua_State * L;
+ struct tagFreeList * freelist;
+};
+
+struct tagFreeList {
+ struct tagBuffer * list[16];
+ int top;
+};
+
+typedef struct tagBuffer TBuffer;
+typedef struct tagFreeList TFreeList;
+
+void freelist_init (TFreeList *fl);
+void freelist_add (TFreeList *fl, TBuffer *buf);
+void freelist_free (TFreeList *fl);
+
+void buffer_init (TBuffer *buf, size_t sz, lua_State *L, TFreeList *fl);
+void buffer_free (TBuffer *buf);
+void buffer_clear (TBuffer *buf);
+void buffer_addbuffer (TBuffer *trg, TBuffer *src);
+void buffer_addlstring (TBuffer *buf, const void *src, size_t sz);
+void buffer_addvalue (TBuffer *buf, int stackpos);
+void buffer_pushresult (TBuffer *buf);
+
+void bufferZ_putrepstring (TBuffer *buf, int reppos, int nsub);
+int bufferZ_next (TBuffer *buf, size_t *iter, size_t *len, const char **str);
+
+int get_int_field (lua_State *L, const char* field);
+void set_int_field (lua_State *L, const char* field, int val);
+int get_flags (lua_State *L, const flag_pair **arr);
+const char *get_flag_key (const flag_pair *fp, int val);
+void *Lmalloc (lua_State *L, size_t size);
+
+#endif
@@ .
patch -p0 <<'@@ .'
Index: lua/local/lrexlib_lpcre.c
============================================================================
$ cvs diff -u -r0 -r1.1 lrexlib_lpcre.c
--- /dev/null 2008-01-12 13:33:00 +0100
+++ lrexlib_lpcre.c 2008-01-12 13:33:34 +0100
@@ -0,0 +1,446 @@
+/* lpcre.c - Lua binding of PCRE library */
+/* See Copyright Notice in the file LICENSE */
+
+#ifndef REX_LIBNAME
+# define REX_LIBNAME "rex_pcre"
+#endif
+#ifndef REX_OPENLIB
+# define REX_OPENLIB luaopen_rex_pcre
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <ctype.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+#include "lrexlib.h"
+#include "lrexlib_common.h"
+
+#if defined(LUA_USE_PCRE)
+
+#include <pcre.h>
+
+extern int Lpcre_get_flags (lua_State *L);
+extern int Lpcre_config (lua_State *L);
+extern flag_pair pcre_error_flags[];
+
+#define ALG_CFLAGS_DFLT 0
+#define ALG_EFLAGS_DFLT 0
+
+static int getcflags (lua_State *L, int pos);
+#define ALG_GETCFLAGS(L,pos) getcflags(L, pos)
+
+static void optlocale (TArgComp *argC, lua_State *L, int pos);
+#define ALG_OPTLOCALE(a,b,c) optlocale(a,b,c)
+
+#define ALG_NOMATCH PCRE_ERROR_NOMATCH
+#define ALG_ISMATCH(res) ((res) >= 0)
+#define ALG_SUBBEG(ud,n) ud->match[n+n]
+#define ALG_SUBEND(ud,n) ud->match[n+n+1]
+#define ALG_SUBLEN(ud,n) (ALG_SUBEND(ud,n) - ALG_SUBBEG(ud,n))
+#define ALG_SUBVALID(ud,n) (ALG_SUBBEG(ud,n) >= 0)
+#define ALG_NSUB(ud) ((int)ud->ncapt)
+
+#define ALG_PUSHSUB(L,ud,text,n) \
+ lua_pushlstring (L, (text) + ALG_SUBBEG(ud,n), ALG_SUBLEN(ud,n))
+
+#define ALG_PUSHSUB_OR_FALSE(L,ud,text,n) \
+ (ALG_SUBVALID(ud,n) ? ALG_PUSHSUB (L,ud,text,n) : lua_pushboolean (L,0))
+
+#define ALG_PUSHSTART(L,ud,offs,n) lua_pushinteger(L, (offs) + ALG_SUBBEG(ud,n) + 1)
+#define ALG_PUSHEND(L,ud,offs,n) lua_pushinteger(L, (offs) + ALG_SUBEND(ud,n))
+#define ALG_PUSHOFFSETS(L,ud,offs,n) \
+ (ALG_PUSHSTART(L,ud,offs,n), ALG_PUSHEND(L,ud,offs,n))
+
+#define ALG_BASE(st) 0
+#define ALG_PULL
+#define ALG_USERETRY
+
+typedef struct {
+ pcre * pr;
+ pcre_extra * extra;
+ int * match;
+ int ncapt;
+ const unsigned char * tables;
+ int freed;
+} TPcre;
+
+#define TUserdata TPcre
+
+#if PCRE_MAJOR >= 4
+static void do_named_subpatterns (lua_State *L, TPcre *ud, const char *text);
+# define DO_NAMED_SUBPATTERNS do_named_subpatterns
+#endif
+
+const char pcre_typename[] = REX_LIBNAME"_regex";
+
+#include "lrexlib_algo.h"
+
+/* Locations of the 2 permanent tables in the function environment */
+#define INDEX_CHARTABLES_META 1 /* chartables type's metatable */
+#define INDEX_CHARTABLES_LINK 2 /* link chartables to compiled regex */
+
+const char chartables_typename[] = "chartables";
+
+/* Functions
+ ******************************************************************************
+ */
+
+static void push_chartables_meta (lua_State *L) {
+ lua_pushinteger (L, INDEX_CHARTABLES_META);
+ lua_rawget (L, LUA_ENVIRONINDEX);
+}
+
+static int getcflags (lua_State *L, int pos) {
+ switch (lua_type (L, pos)) {
+ case LUA_TNONE:
+ case LUA_TNIL:
+ return ALG_CFLAGS_DFLT;
+ case LUA_TNUMBER:
+ return lua_tointeger (L, pos);
+ case LUA_TSTRING: {
+ const char *s = lua_tostring (L, pos);
+ int res = 0, ch;
+ while ((ch = *s++) != '\0') {
+ if (ch == 'i') res |= PCRE_CASELESS;
+ else if (ch == 'm') res |= PCRE_MULTILINE;
+ else if (ch == 's') res |= PCRE_DOTALL;
+ else if (ch == 'x') res |= PCRE_EXTENDED;
+ else if (ch == 'U') res |= PCRE_UNGREEDY;
+ else if (ch == 'X') res |= PCRE_EXTRA;
+ }
+ return res;
+ }
+ default:
+ return luaL_argerror (L, pos, "number or string expected");
+ }
+}
+
+static int generate_error (lua_State *L, const TPcre *ud, int errcode) {
+ const char *key = get_flag_key (pcre_error_flags, errcode);
+ (void) ud;
+ if (key)
+ return luaL_error (L, "error PCRE_%s", key);
+ else
+ return luaL_error (L, "PCRE error code %d", errcode);
+}
+
+#if PCRE_MAJOR >= 6
+/* method r:dfa_exec (s, [st], [ef], [ovecsize], [wscount]) */
+static void checkarg_dfa_exec (lua_State *L, TArgExec *argE, TPcre **ud) {
+ *ud = check_ud (L);
+ argE->text = luaL_checklstring (L, 2, &argE->textlen);
+ argE->startoffset = get_startoffset (L, 3, argE->textlen);
+ argE->eflags = luaL_optint (L, 4, ALG_EFLAGS_DFLT);
+ argE->ovecsize = luaL_optint (L, 5, 100);
+ argE->wscount = luaL_optint (L, 6, 50);
+}
+#endif
+
+static int Lpcre_maketables (lua_State *L) {
+ *(const void**)lua_newuserdata (L, sizeof(void**)) = pcre_maketables();
+ push_chartables_meta (L);
+ lua_setmetatable (L, -2);
+ return 1;
+}
+
+static void **check_chartables (lua_State *L, int pos) {
+ void **q;
+ /* Compare the metatable against the C function environment. */
+ if (lua_getmetatable(L, pos)) {
+ push_chartables_meta (L);
+ if (lua_rawequal(L, -1, -2) &&
+ (q = (void **)lua_touserdata(L, pos)) != NULL) {
+ lua_pop(L, 2);
+ return q;
+ }
+ }
+ luaL_argerror(L, pos, lua_pushfstring (L, "not a %s", chartables_typename));
+ return NULL;
+}
+
+static int chartables_gc (lua_State *L) {
+ void **ud = check_chartables (L, 1);
+ if (*ud) {
+ pcre_free (*ud);
+ *ud = NULL;
+ }
+ return 0;
+}
+
+static void optlocale (TArgComp *argC, lua_State *L, int pos) {
+ argC->locale = NULL;
+ argC->tables = NULL;
+ if (!lua_isnoneornil (L, pos)) {
+ if (lua_isstring (L, pos))
+ argC->locale = lua_tostring (L, pos);
+ else {
+ argC->tablespos = pos;
+ argC->tables = *check_chartables (L, pos);
+ }
+ }
+}
+
+static int compile_regex (lua_State *L, const TArgComp *argC, TPcre **pud) {
+ const char *error;
+ int erroffset;
+ TPcre *ud;
+ const unsigned char *tables = NULL;
+
+ ud = (TPcre*)lua_newuserdata (L, sizeof (TPcre));
+ memset (ud, 0, sizeof (TPcre)); /* initialize all members to 0 */
+ lua_pushvalue (L, LUA_ENVIRONINDEX);
+ lua_setmetatable (L, -2);
+
+ if (argC->locale) {
+ char old_locale[256];
+ strcpy (old_locale, setlocale (LC_CTYPE, NULL)); /* store the locale */
+ if (NULL == setlocale (LC_CTYPE, argC->locale)) /* set new locale */
+ return luaL_error (L, "cannot set locale");
+ ud->tables = tables = pcre_maketables (); /* make tables with new locale */
+ setlocale (LC_CTYPE, old_locale); /* restore the old locale */
+ }
+ else if (argC->tables) {
+ tables = argC->tables;
+ lua_pushinteger (L, INDEX_CHARTABLES_LINK);
+ lua_rawget (L, LUA_ENVIRONINDEX);
+ lua_pushvalue (L, -2);
+ lua_pushvalue (L, argC->tablespos);
+ lua_rawset (L, -3);
+ lua_pop (L, 1);
+ }
+
+ ud->pr = pcre_compile (argC->pattern, argC->cflags, &error, &erroffset, tables);
+ if (!ud->pr)
+ return luaL_error (L, "%s (pattern offset: %d)", error, erroffset + 1);
+
+ ud->extra = pcre_study (ud->pr, 0, &error);
+ if (error) return luaL_error (L, "%s", error);
+
+ pcre_fullinfo (ud->pr, ud->extra, PCRE_INFO_CAPTURECOUNT, &ud->ncapt);
+ /* need (2 ints per capture, plus one for substring match) * 3/2 */
+ ud->match = (int *) Lmalloc (L, (ALG_NSUB(ud) + 1) * 3 * sizeof (int));
+
+ if (pud) *pud = ud;
+ return 1;
+}
+
+#if PCRE_MAJOR >= 4
+/* the target table must be on lua stack top */
+static void do_named_subpatterns (lua_State *L, TPcre *ud, const char *text) {
+ int i, namecount, name_entry_size;
+ unsigned char *name_table, *tabptr;
+
+ /* do named subpatterns - NJG */
+ pcre_fullinfo (ud->pr, ud->extra, PCRE_INFO_NAMECOUNT, &namecount);
+ if (namecount <= 0)
+ return;
+ pcre_fullinfo (ud->pr, ud->extra, PCRE_INFO_NAMETABLE, &name_table);
+ pcre_fullinfo (ud->pr, ud->extra, PCRE_INFO_NAMEENTRYSIZE, &name_entry_size);
+ tabptr = name_table;
+ for (i = 0; i < namecount; i++) {
+ int n = (tabptr[0] << 8) | tabptr[1]; /* number of the capturing parenthesis */
+ if (n > 0 && n <= ALG_NSUB(ud)) { /* check range */
+ lua_pushstring (L, (char *)tabptr + 2); /* name of the capture, zero terminated */
+ ALG_PUSHSUB_OR_FALSE (L, ud, text, n);
+ lua_rawset (L, -3);
+ }
+ tabptr += name_entry_size;
+ }
+}
+#endif /* #if PCRE_MAJOR >= 4 */
+
+static int tfind_exec (TPcre *ud, TArgExec *argE) {
+ return pcre_exec (ud->pr, ud->extra, argE->text, (int)argE->textlen,
+ argE->startoffset, argE->eflags, ud->match, (ud->ncapt + 1) * 3);
+}
+
+#if PCRE_MAJOR >= 6
+static int Lpcre_dfa_exec (lua_State *L)
+{
+ TArgExec argE;
+ TPcre *ud;
+ int res;
+ int *buf, *ovector, *wspace;
+
+ checkarg_dfa_exec (L, &argE, &ud);
+ buf = (int*) Lmalloc (L, (argE.ovecsize + argE.wscount) * sizeof(int));
+ ovector = buf;
+ wspace = buf + argE.ovecsize;
+
+ res = pcre_dfa_exec (ud->pr, ud->extra, argE.text, (int)argE.textlen,
+ argE.startoffset, argE.eflags, ovector, argE.ovecsize, wspace, argE.wscount);
+
+ if (ALG_ISMATCH (res) || res == PCRE_ERROR_PARTIAL) {
+ int i;
+ int max = (res>0) ? res : (res==0) ? (int)argE.ovecsize/2 : 1;
+ lua_pushinteger (L, ovector[0] + 1); /* 1-st return value */
+ lua_newtable (L); /* 2-nd return value */
+ for (i=0; i<max; i++) {
+ lua_pushinteger (L, ovector[i+i+1]);
+ lua_rawseti (L, -2, i+1);
+ }
+ lua_pushinteger (L, res); /* 3-rd return value */
+ free (buf);
+ return 3;
+ }
+ else {
+ free (buf);
+ if (res == ALG_NOMATCH)
+ return lua_pushnil (L), 1;
+ else
+ return generate_error (L, ud, res);
+ }
+}
+#endif /* #if PCRE_MAJOR >= 6 */
+
+#ifdef ALG_USERETRY
+ static int gmatch_exec (TUserdata *ud, TArgExec *argE, int retry) {
+ int eflags = retry ? (argE->eflags|PCRE_NOTEMPTY|PCRE_ANCHORED) : argE->eflags;
+ return pcre_exec (ud->pr, ud->extra, argE->text, argE->textlen,
+ argE->startoffset, eflags, ud->match, (ALG_NSUB(ud) + 1) * 3);
+ }
+#else
+ static int gmatch_exec (TUserdata *ud, TArgExec *argE) {
+ return pcre_exec (ud->pr, ud->extra, argE->text, argE->textlen,
+ argE->startoffset, argE->eflags, ud->match, (ALG_NSUB(ud) + 1) * 3);
+ }
+#endif
+
+static void gmatch_pushsubject (lua_State *L, TArgExec *argE) {
+ lua_pushlstring (L, argE->text, argE->textlen);
+}
+
+static int findmatch_exec (TPcre *ud, TArgExec *argE) {
+ return pcre_exec (ud->pr, ud->extra, argE->text, argE->textlen,
+ argE->startoffset, argE->eflags, ud->match, (ALG_NSUB(ud) + 1) * 3);
+}
+
+#ifdef ALG_USERETRY
+ static int gsub_exec (TPcre *ud, TArgExec *argE, int st, int retry) {
+ int eflags = retry ? (argE->eflags|PCRE_NOTEMPTY|PCRE_ANCHORED) : argE->eflags;
+ return pcre_exec (ud->pr, ud->extra, argE->text, (int)argE->textlen,
+ st, eflags, ud->match, (ALG_NSUB(ud) + 1) * 3);
+ }
+#else
+ static int gsub_exec (TPcre *ud, TArgExec *argE, int st) {
+ return pcre_exec (ud->pr, ud->extra, argE->text, (int)argE->textlen,
+ st, argE->eflags, ud->match, (ALG_NSUB(ud) + 1) * 3);
+ }
+#endif
+
+static int split_exec (TPcre *ud, TArgExec *argE, int offset) {
+ return pcre_exec (ud->pr, ud->extra, argE->text, argE->textlen, offset,
+ argE->eflags, ud->match, (ALG_NSUB(ud) + 1) * 3);
+}
+
+static int Lpcre_gc (lua_State *L) {
+ TPcre *ud = check_ud (L);
+ if (ud->freed == 0) { /* precaution against "manual" __gc calling */
+ ud->freed = 1;
+ if (ud->pr) pcre_free (ud->pr);
+ if (ud->extra) pcre_free (ud->extra);
+ if (ud->tables) pcre_free ((void *)ud->tables);
+ if (ud->match) free (ud->match);
+ }
+ return 0;
+}
+
+static int Lpcre_tostring (lua_State *L) {
+ TPcre *ud = check_ud (L);
+ if (ud->freed == 0)
+ lua_pushfstring (L, "%s (%p)", pcre_typename, (void*)ud);
+ else
+ lua_pushfstring (L, "%s (deleted)", pcre_typename);
+ return 1;
+}
+
+static int chartables_tostring (lua_State *L) {
+ void **ud = check_chartables (L, 1);
+ lua_pushfstring (L, "%s (%p)", chartables_typename, ud);
+ return 1;
+}
+
+static int Lpcre_version (lua_State *L) {
+ lua_pushstring (L, pcre_version ());
+ return 1;
+}
+
+static const luaL_reg chartables_meta[] = {
+ { "__gc", chartables_gc },
+ { "__tostring", chartables_tostring },
+ { NULL, NULL }
+};
+
+static const luaL_reg regex_meta[] = {
+ { "exec", ud_exec },
+ { "tfind", ud_tfind }, /* old name: match */
+#if PCRE_MAJOR >= 6
+ { "dfa_exec", Lpcre_dfa_exec },
+#endif
+ { "__gc", Lpcre_gc },
+ { "__tostring", Lpcre_tostring },
+ { NULL, NULL }
+};
+
+static const luaL_reg rexlib[] = {
+ { "match", match },
+ { "find", find },
+ { "gmatch", gmatch },
+ { "gsub", gsub },
+ { "split", split },
+ { "new", ud_new },
+ { "plainfind", plainfind_func },
+ { "flags", Lpcre_get_flags },
+ { "version", Lpcre_version },
+ { "maketables", Lpcre_maketables },
+#if PCRE_MAJOR >= 4
+ { "config", Lpcre_config },
+#endif
+ { NULL, NULL }
+};
+
+#endif
+
+/* Open the library */
+REX_API int REX_OPENLIB (lua_State *L) {
+#if defined(LUA_USE_PCRE)
+ if (PCRE_MAJOR > atoi (pcre_version ())) {
+ return luaL_error (L, "%s requires at least version %d of PCRE library",
+ REX_LIBNAME, (int)PCRE_MAJOR);
+ }
+ /* create a new function environment to serve as a metatable for methods */
+ lua_newtable (L);
+ lua_pushvalue (L, -1);
+ lua_replace (L, LUA_ENVIRONINDEX);
+ lua_pushvalue(L, -1); /* mt.__index = mt */
+ lua_setfield(L, -2, "__index");
+ luaL_register (L, NULL, regex_meta);
+
+ /* register functions */
+ luaL_register (L, REX_LIBNAME, rexlib);
+ lua_pushliteral (L, REX_VERSION" (for PCRE)");
+ lua_setfield (L, -2, "_VERSION");
+
+ /* create a table and register it as a metatable for "chartables" userdata */
+ lua_pushinteger (L, INDEX_CHARTABLES_META);
+ lua_newtable (L);
+ lua_pushliteral (L, "access denied");
+ lua_setfield (L, -2, "__metatable");
+ luaL_register (L, NULL, chartables_meta);
+ lua_rawset (L, LUA_ENVIRONINDEX);
+
+ /* create a table for connecting "chartables" userdata to "regex" userdata */
+ lua_pushinteger (L, INDEX_CHARTABLES_LINK);
+ lua_newtable (L);
+ lua_pushliteral (L, "k"); /* weak keys */
+ lua_setfield (L, -2, "__mode");
+ lua_pushvalue (L, -1); /* setmetatable (tb, tb) */
+ lua_setmetatable (L, -2);
+ lua_rawset (L, LUA_ENVIRONINDEX);
+#endif
+ return 1;
+}
+
@@ .
patch -p0 <<'@@ .'
Index: lua/local/lrexlib_lpcre_f.c
============================================================================
$ cvs diff -u -r0 -r1.1 lrexlib_lpcre_f.c
--- /dev/null 2008-01-12 13:33:00 +0100
+++ lrexlib_lpcre_f.c 2008-01-12 13:33:34 +0100
@@ -0,0 +1,194 @@
+/* lpcre.c - PCRE regular expression library */
+/* See Copyright Notice in the file LICENSE */
+
+#if defined(LUA_USE_PCRE)
+
+#include <pcre.h>
+#include "lua.h"
+#include "lauxlib.h"
+#include "lrexlib_common.h"
+
+int Lpcre_get_flags (lua_State *L);
+int Lpcre_config (lua_State *L);
+flag_pair pcre_error_flags[];
+
+#define VERSION_PCRE (PCRE_MAJOR*100 + PCRE_MINOR)
+
+static flag_pair pcre_flags[] = {
+ { "MAJOR", PCRE_MAJOR },
+ { "MINOR", PCRE_MINOR },
+/*---------------------------------------------------------------------------*/
+ { "CASELESS", PCRE_CASELESS },
+ { "MULTILINE", PCRE_MULTILINE },
+ { "DOTALL", PCRE_DOTALL },
+ { "EXTENDED", PCRE_EXTENDED },
+ { "ANCHORED", PCRE_ANCHORED },
+ { "DOLLAR_ENDONLY", PCRE_DOLLAR_ENDONLY },
+ { "EXTRA", PCRE_EXTRA },
+ { "NOTBOL", PCRE_NOTBOL },
+ { "NOTEOL", PCRE_NOTEOL },
+ { "UNGREEDY", PCRE_UNGREEDY },
+ { "NOTEMPTY", PCRE_NOTEMPTY },
+ { "UTF8", PCRE_UTF8 },
+#if VERSION_PCRE >= 400
+ { "NO_AUTO_CAPTURE", PCRE_NO_AUTO_CAPTURE },
+ { "NO_UTF8_CHECK", PCRE_NO_UTF8_CHECK },
+#endif
+#if VERSION_PCRE >= 500
+ { "AUTO_CALLOUT", PCRE_AUTO_CALLOUT },
+ { "PARTIAL", PCRE_PARTIAL },
+#endif
+#if VERSION_PCRE >= 600
+ { "DFA_SHORTEST", PCRE_DFA_SHORTEST },
+ { "DFA_RESTART", PCRE_DFA_RESTART },
+ { "FIRSTLINE", PCRE_FIRSTLINE },
+#endif
+#if VERSION_PCRE >= 607
+ { "DUPNAMES", PCRE_DUPNAMES },
+ { "NEWLINE_CR", PCRE_NEWLINE_CR },
+ { "NEWLINE_LF", PCRE_NEWLINE_LF },
+ { "NEWLINE_CRLF", PCRE_NEWLINE_CRLF },
+#endif
+#if VERSION_PCRE >= 700
+ { "NEWLINE_ANY", PCRE_NEWLINE_ANY },
+#endif
+#if VERSION_PCRE >= 701
+ { "NEWLINE_ANYCRLF", PCRE_NEWLINE_ANYCRLF },
+#endif
+#if VERSION_PCRE >= 704
+ { "BSR_ANYCRLF", PCRE_BSR_ANYCRLF },
+ { "BSR_UNICODE", PCRE_BSR_UNICODE },
+#endif
+/*---------------------------------------------------------------------------*/
+ { "INFO_OPTIONS", PCRE_INFO_OPTIONS },
+ { "INFO_SIZE", PCRE_INFO_SIZE },
+ { "INFO_CAPTURECOUNT", PCRE_INFO_CAPTURECOUNT },
+ { "INFO_BACKREFMAX", PCRE_INFO_BACKREFMAX },
+#if VERSION_PCRE >= 400
+ { "INFO_FIRSTBYTE", PCRE_INFO_FIRSTBYTE },
+#endif
+ { "INFO_FIRSTCHAR", PCRE_INFO_FIRSTCHAR },
+ { "INFO_FIRSTTABLE", PCRE_INFO_FIRSTTABLE },
+ { "INFO_LASTLITERAL", PCRE_INFO_LASTLITERAL },
+#if VERSION_PCRE >= 400
+ { "INFO_NAMEENTRYSIZE", PCRE_INFO_NAMEENTRYSIZE },
+ { "INFO_NAMECOUNT", PCRE_INFO_NAMECOUNT },
+ { "INFO_NAMETABLE", PCRE_INFO_NAMETABLE },
+ { "INFO_STUDYSIZE", PCRE_INFO_STUDYSIZE },
+#endif
+#if VERSION_PCRE >= 500
+ { "INFO_DEFAULT_TABLES", PCRE_INFO_DEFAULT_TABLES },
+#endif
+#ifdef PCRE_INFO_OKPARTIAL
+ { "INFO_OKPARTIAL", PCRE_INFO_OKPARTIAL },
+#endif
+#ifdef PCRE_INFO_JCHANGED
+ { "INFO_JCHANGED", PCRE_INFO_JCHANGED },
+#endif
+#ifdef PCRE_INFO_HASCRORLF
+ { "INFO_HASCRORLF", PCRE_INFO_HASCRORLF },
+#endif
+/*---------------------------------------------------------------------------*/
+#if VERSION_PCRE >= 400
+ { "EXTRA_STUDY_DATA", PCRE_EXTRA_STUDY_DATA },
+ { "EXTRA_MATCH_LIMIT", PCRE_EXTRA_MATCH_LIMIT },
+ { "EXTRA_CALLOUT_DATA", PCRE_EXTRA_CALLOUT_DATA },
+#endif
+#if VERSION_PCRE >= 500
+ { "EXTRA_TABLES", PCRE_EXTRA_TABLES },
+#endif
+#ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION
+ { "EXTRA_MATCH_LIMIT_RECURSION", PCRE_EXTRA_MATCH_LIMIT_RECURSION },
+#endif
+/*---------------------------------------------------------------------------*/
+ { NULL, 0 }
+};
+
+flag_pair pcre_error_flags[] = {
+ { "ERROR_NOMATCH", PCRE_ERROR_NOMATCH },
+ { "ERROR_NULL", PCRE_ERROR_NULL },
+ { "ERROR_BADOPTION", PCRE_ERROR_BADOPTION },
+ { "ERROR_BADMAGIC", PCRE_ERROR_BADMAGIC },
+#if VERSION_PCRE >= 700
+ { "ERROR_UNKNOWN_OPCODE", PCRE_ERROR_UNKNOWN_OPCODE },
+#endif
+ { "ERROR_UNKNOWN_NODE", PCRE_ERROR_UNKNOWN_NODE },
+ { "ERROR_NOMEMORY", PCRE_ERROR_NOMEMORY },
+ { "ERROR_NOSUBSTRING", PCRE_ERROR_NOSUBSTRING },
+#if VERSION_PCRE >= 400
+ { "ERROR_MATCHLIMIT", PCRE_ERROR_MATCHLIMIT },
+ { "ERROR_CALLOUT", PCRE_ERROR_CALLOUT },
+ { "ERROR_BADUTF8", PCRE_ERROR_BADUTF8 },
+ { "ERROR_BADUTF8_OFFSET", PCRE_ERROR_BADUTF8_OFFSET },
+#endif
+#if VERSION_PCRE >= 500
+ { "ERROR_PARTIAL", PCRE_ERROR_PARTIAL },
+ { "ERROR_BADPARTIAL", PCRE_ERROR_BADPARTIAL },
+ { "ERROR_INTERNAL", PCRE_ERROR_INTERNAL },
+ { "ERROR_BADCOUNT", PCRE_ERROR_BADCOUNT },
+#endif
+#if VERSION_PCRE >= 600
+ { "ERROR_DFA_UITEM", PCRE_ERROR_DFA_UITEM },
+ { "ERROR_DFA_UCOND", PCRE_ERROR_DFA_UCOND },
+ { "ERROR_DFA_UMLIMIT", PCRE_ERROR_DFA_UMLIMIT },
+ { "ERROR_DFA_WSSIZE", PCRE_ERROR_DFA_WSSIZE },
+ { "ERROR_DFA_RECURSE", PCRE_ERROR_DFA_RECURSE },
+#endif
+#if VERSION_PCRE >= 607
+ { "ERROR_RECURSIONLIMIT", PCRE_ERROR_RECURSIONLIMIT },
+#endif
+#if VERSION_PCRE >= 700
+ { "ERROR_BADNEWLINE", PCRE_ERROR_BADNEWLINE },
+#endif
+#ifdef PCRE_ERROR_NULLWSLIMIT
+ { "ERROR_NULLWSLIMIT", PCRE_ERROR_NULLWSLIMIT },
+#endif
+/*---------------------------------------------------------------------------*/
+ { NULL, 0 }
+};
+
+#if VERSION_PCRE >= 400
+static flag_pair pcre_config_flags[] = {
+ { "CONFIG_UTF8", PCRE_CONFIG_UTF8 },
+ { "CONFIG_NEWLINE", PCRE_CONFIG_NEWLINE },
+ { "CONFIG_LINK_SIZE", PCRE_CONFIG_LINK_SIZE },
+ { "CONFIG_POSIX_MALLOC_THRESHOLD", PCRE_CONFIG_POSIX_MALLOC_THRESHOLD },
+ { "CONFIG_MATCH_LIMIT", PCRE_CONFIG_MATCH_LIMIT },
+ { "CONFIG_STACKRECURSE", PCRE_CONFIG_STACKRECURSE },
+#if VERSION_PCRE >= 500
+ { "CONFIG_UNICODE_PROPERTIES", PCRE_CONFIG_UNICODE_PROPERTIES },
+#endif
+#if VERSION_PCRE >= 650
+ { "CONFIG_MATCH_LIMIT_RECURSION", PCRE_CONFIG_MATCH_LIMIT_RECURSION },
+#endif
+#if VERSION_PCRE >= 704
+ { "CONFIG_BSR", PCRE_CONFIG_BSR },
+#endif
+/*---------------------------------------------------------------------------*/
+ { NULL, 0 }
+};
+
+int Lpcre_config (lua_State *L) {
+ int val;
+ flag_pair *fp;
+ if (lua_istable (L, 1))
+ lua_settop (L, 1);
+ else
+ lua_newtable (L);
+ for (fp = pcre_config_flags; fp->key; ++fp) {
+ if (0 == pcre_config (fp->val, &val)) {
+ lua_pushinteger (L, val);
+ lua_setfield (L, -2, fp->key);
+ }
+ }
+ return 1;
+}
+#endif /* #if VERSION_PCRE >= 400 */
+
+int Lpcre_get_flags (lua_State *L) {
+ const flag_pair* fps[] = { pcre_flags, pcre_error_flags, NULL };
+ return get_flags (L, fps);
+}
+
+#endif
+
@@ .
patch -p0 <<'@@ .'
Index: lua/local/lrexlib_lposix.c
============================================================================
$ cvs diff -u -r0 -r1.1 lrexlib_lposix.c
--- /dev/null 2008-01-12 13:33:00 +0100
+++ lrexlib_lposix.c 2008-01-12 13:33:34 +0100
@@ -0,0 +1,308 @@
+/* lposix.c - Lua binding of POSIX regular expressions library */
+/* See Copyright Notice in the file LICENSE */
+
+#ifndef REX_LIBNAME
+# define REX_LIBNAME "rex_posix"
+#endif
+#ifndef REX_OPENLIB
+# define REX_OPENLIB luaopen_rex_posix
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+#include "lrexlib.h"
+#include "lrexlib_common.h"
+
+#if defined(LUA_USE_POSIX)
+
+#ifndef REX_POSIX_INCLUDE
+# include <regex.h>
+#else
+# include REX_POSIX_INCLUDE
+#endif
+
+/* Test if regex.h corresponds to the extended POSIX library, i.e. H.Spencer's.
+ This test may not work as intended if regex.h introduced REG_BASIC, etc.
+ via enum rather than #define.
+ If that's the case, add -DREX_POSIX_EXT in the makefile/command line.
+*/
+#ifndef REX_POSIX_EXT
+# if defined(REG_BASIC) && defined(REG_STARTEND)
+# define REX_POSIX_EXT
+# endif
+#endif
+
+#define ALG_CFLAGS_DFLT REG_EXTENDED
+#ifdef REX_POSIX_EXT
+# define ALG_EFLAGS_DFLT REG_STARTEND
+#else
+# define ALG_EFLAGS_DFLT 0
+#endif
+
+#define ALG_NOMATCH REG_NOMATCH
+#define ALG_ISMATCH(res) ((res) == 0)
+#define ALG_SUBBEG(ud,n) ud->match[n].rm_so
+#define ALG_SUBEND(ud,n) ud->match[n].rm_eo
+#define ALG_SUBLEN(ud,n) (ALG_SUBEND(ud,n) - ALG_SUBBEG(ud,n))
+#define ALG_SUBVALID(ud,n) (ALG_SUBBEG(ud,n) >= 0)
+#ifdef REX_NSUB_BASE1
+# define ALG_NSUB(ud) ((int)ud->r.re_nsub - 1)
+#else
+# define ALG_NSUB(ud) ((int)ud->r.re_nsub)
+#endif
+
+#define ALG_PUSHSUB(L,ud,text,n) \
+ lua_pushlstring (L, (text) + ALG_SUBBEG(ud,n), ALG_SUBLEN(ud,n))
+
+#define ALG_PUSHSUB_OR_FALSE(L,ud,text,n) \
+ (ALG_SUBVALID(ud,n) ? ALG_PUSHSUB (L,ud,text,n) : lua_pushboolean (L,0))
+
+#define ALG_PUSHSTART(L,ud,offs,n) lua_pushinteger(L, (offs) + ALG_SUBBEG(ud,n) + 1)
+#define ALG_PUSHEND(L,ud,offs,n) lua_pushinteger(L, (offs) + ALG_SUBEND(ud,n))
+#define ALG_PUSHOFFSETS(L,ud,offs,n) \
+ (ALG_PUSHSTART(L,ud,offs,n), ALG_PUSHEND(L,ud,offs,n))
+
+#define ALG_BASE(st) (st)
+#define ALG_GETCFLAGS(L,pos) luaL_optint(L, pos, ALG_CFLAGS_DFLT)
+
+typedef struct {
+ regex_t r;
+ regmatch_t * match;
+ int freed;
+} TPosix;
+
+#define TUserdata TPosix
+
+const char posix_typename[] = REX_LIBNAME"_regex";
+
+#include "lrexlib_algo.h"
+
+/* Functions
+ ******************************************************************************
+ */
+
+static int generate_error (lua_State *L, const TPosix *ud, int errcode) {
+ char errbuf[80];
+ regerror (errcode, &ud->r, errbuf, sizeof (errbuf));
+ return luaL_error (L, "%s", errbuf);
+}
+
+static int compile_regex (lua_State *L, const TArgComp *argC, TPosix **pud) {
+ int res;
+ TPosix *ud;
+
+ ud = (TPosix *)lua_newuserdata (L, sizeof (TPosix));
+ memset (ud, 0, sizeof (TPosix)); /* initialize all members to 0 */
+
+#ifdef REX_POSIX_EXT
+ if (argC->cflags & REG_PEND)
+ ud->r.re_endp = argC->pattern + argC->patlen;
+#endif
+
+ res = regcomp (&ud->r, argC->pattern, argC->cflags);
+ if (res != 0)
+ return generate_error (L, ud, res);
+
+ if (argC->cflags & REG_NOSUB)
+ ud->r.re_nsub = 0;
+ ud->match = (regmatch_t *) Lmalloc (L, (ALG_NSUB(ud) + 1) * sizeof (regmatch_t));
+ lua_pushvalue (L, LUA_ENVIRONINDEX);
+ lua_setmetatable (L, -2);
+
+ if (pud) *pud = ud;
+ return 1;
+}
+
+#ifdef REX_POSIX_EXT
+static void CheckStartEnd (TArgExec *argE, TPosix *ud) {
+ if (argE->eflags & REG_STARTEND) {
+ ud->match[0].rm_so = argE->startoffset;
+ ud->match[0].rm_eo = argE->textlen;
+ argE->startoffset = 0;
+ }
+ else
+ argE->text += argE->startoffset;
+}
+#endif
+
+static int tfind_exec (TPosix *ud, TArgExec *argE) {
+#ifdef REX_POSIX_EXT
+ CheckStartEnd (argE, ud);
+#else
+ argE->text += argE->startoffset;
+#endif
+ return regexec (&ud->r, argE->text, ALG_NSUB(ud) + 1, ud->match, argE->eflags);
+}
+
+static int gmatch_exec (TUserdata *ud, TArgExec *argE) {
+ if (argE->startoffset > 0)
+ argE->eflags |= REG_NOTBOL;
+
+#ifdef REX_POSIX_EXT
+ if (argE->eflags & REG_STARTEND) {
+ ALG_SUBBEG(ud,0) = 0;
+ ALG_SUBEND(ud,0) = argE->textlen - argE->startoffset;
+ }
+#endif
+
+ argE->text += argE->startoffset;
+ return regexec (&ud->r, argE->text, ALG_NSUB(ud) + 1, ud->match, argE->eflags);
+}
+
+static void gmatch_pushsubject (lua_State *L, TArgExec *argE) {
+#ifdef REX_POSIX_EXT
+ if (argE->eflags & REG_STARTEND)
+ lua_pushlstring (L, argE->text, argE->textlen);
+ else
+ lua_pushlstring (L, argE->text, strlen (argE->text));
+#else
+ lua_pushlstring (L, argE->text, strlen (argE->text));
+#endif
+}
+
+static int findmatch_exec (TPosix *ud, TArgExec *argE) {
+#ifdef REX_POSIX_EXT
+ CheckStartEnd (argE, ud);
+#else
+ argE->text += argE->startoffset;
+#endif
+ return regexec (&ud->r, argE->text, ALG_NSUB(ud) + 1, ud->match, argE->eflags);
+}
+
+static int gsub_exec (TPosix *ud, TArgExec *argE, int st) {
+#ifdef REX_POSIX_EXT
+ if(argE->eflags & REG_STARTEND) {
+ ALG_SUBBEG(ud,0) = 0;
+ ALG_SUBEND(ud,0) = argE->textlen - st;
+ }
+#endif
+ if (st > 0)
+ argE->eflags |= REG_NOTBOL;
+ return regexec (&ud->r, argE->text+st, ALG_NSUB(ud)+1, ud->match, argE->eflags);
+}
+
+static int split_exec (TPosix *ud, TArgExec *argE, int offset) {
+#ifdef REX_POSIX_EXT
+ if (argE->eflags & REG_STARTEND) {
+ ALG_SUBBEG(ud,0) = 0;
+ ALG_SUBEND(ud,0) = argE->textlen - offset;
+ }
+#endif
+ if (offset > 0)
+ argE->eflags |= REG_NOTBOL;
+
+ return regexec (&ud->r, argE->text + offset, ALG_NSUB(ud) + 1, ud->match, argE->eflags);
+}
+
+static int Posix_gc (lua_State *L) {
+ TPosix *ud = check_ud (L);
+ if (ud->freed == 0) { /* precaution against "manual" __gc calling */
+ ud->freed = 1;
+ regfree (&ud->r);
+ if (ud->match)
+ free (ud->match);
+ }
+ return 0;
+}
+
+static int Posix_tostring (lua_State *L) {
+ TPosix *ud = check_ud (L);
+ if (ud->freed == 0)
+ lua_pushfstring (L, "%s (%p)", posix_typename, (void*)ud);
+ else
+ lua_pushfstring (L, "%s (deleted)", posix_typename);
+ return 1;
+}
+
+static flag_pair posix_flags[] =
+{
+#ifdef REX_POSIX_EXT
+ { "BASIC", REG_BASIC },
+ { "NOSPEC", REG_NOSPEC },
+ { "PEND", REG_PEND },
+ { "STARTEND", REG_STARTEND },
+#endif
+ { "EXTENDED", REG_EXTENDED },
+ { "ICASE", REG_ICASE },
+ { "NOSUB", REG_NOSUB },
+ { "NEWLINE", REG_NEWLINE },
+ { "NOTBOL", REG_NOTBOL },
+ { "NOTEOL", REG_NOTEOL },
+/*---------------------------------------------------------------------------*/
+ { NULL, 0 }
+};
+
+static flag_pair posix_error_flags[] = {
+ { "NOMATCH", REG_NOMATCH },
+ { "BADPAT", REG_BADPAT },
+ { "ECOLLATE", REG_ECOLLATE },
+ { "ECTYPE", REG_ECTYPE },
+ { "EESCAPE", REG_EESCAPE },
+ { "ESUBREG", REG_ESUBREG },
+ { "EBRACK", REG_EBRACK },
+ { "EPAREN", REG_EPAREN },
+ { "EBRACE", REG_EBRACE },
+ { "BADBR", REG_BADBR },
+ { "ERANGE", REG_ERANGE },
+ { "ESPACE", REG_ESPACE },
+ { "BADRPT", REG_BADRPT },
+#ifdef REX_POSIX_EXT
+ { "EMPTY", REG_EMPTY },
+ { "ASSERT", REG_ASSERT },
+ { "INVARG", REG_INVARG },
+#endif
+/*---------------------------------------------------------------------------*/
+ { NULL, 0 }
+};
+
+static int Posix_get_flags (lua_State *L) {
+ const flag_pair* fps[] = { posix_flags, posix_error_flags, NULL };
+ return get_flags (L, fps);
+}
+
+static const luaL_reg posixmeta[] = {
+ { "exec", ud_exec },
+ { "tfind", ud_tfind }, /* old match */
+ { "__gc", Posix_gc },
+ { "__tostring", Posix_tostring },
+ { NULL, NULL}
+};
+
+static const luaL_reg rexlib[] = {
+ { "match", match },
+ { "find", find },
+ { "gmatch", gmatch },
+ { "gsub", gsub },
+ { "split", split },
+ { "new", ud_new },
+ { "flags", Posix_get_flags },
+ { "plainfind", plainfind_func },
+ { NULL, NULL }
+};
+
+#endif
+
+/* Open the library */
+REX_API int REX_OPENLIB (lua_State *L)
+{
+#if defined(LUA_USE_POSIX)
+ /* create a new function environment to serve as a metatable for methods */
+ lua_newtable (L);
+ lua_pushvalue (L, -1);
+ lua_replace (L, LUA_ENVIRONINDEX);
+ lua_pushvalue(L, -1); /* mt.__index = mt */
+ lua_setfield(L, -2, "__index");
+ luaL_register (L, NULL, posixmeta);
+
+ /* register functions */
+ luaL_register (L, REX_LIBNAME, rexlib);
+ lua_pushliteral (L, REX_VERSION" (for POSIX regexes)");
+ lua_setfield (L, -2, "_VERSION");
+#endif
+ return 1;
+}
+
@@ .
patch -p0 <<'@@ .'
Index: rpm/rpmio/rpmlua.c
============================================================================
$ cvs diff -u -r2.39 -r2.40 rpmlua.c
--- rpm/rpmio/rpmlua.c 11 Jan 2008 12:57:49 -0000 2.39
+++ rpm/rpmio/rpmlua.c 12 Jan 2008 12:33:34 -0000 2.40
@@ -79,7 +79,8 @@
/* local LUA libraries (RPM only) */
#ifdef WITH_LUA_INTERNAL
{"posix", luaopen_posix},
- {"rex", luaopen_rex},
+ {"rex_posix", luaopen_rex_posix},
+ {"rex_pcre", luaopen_rex_pcre},
{"uuid", luaopen_uuid},
{"local", luaopen_local},
#endif
@@ .
Received on Sat Jan 12 13:33:34 2008