summaryrefslogtreecommitdiffstats
path: root/src/boost/tools/build/src/engine/modules/regex.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/boost/tools/build/src/engine/modules/regex.cpp233
1 files changed, 233 insertions, 0 deletions
diff --git a/src/boost/tools/build/src/engine/modules/regex.cpp b/src/boost/tools/build/src/engine/modules/regex.cpp
new file mode 100644
index 000000000..95fe19d14
--- /dev/null
+++ b/src/boost/tools/build/src/engine/modules/regex.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2003. Vladimir Prus
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE.txt or copy at
+ * https://www.bfgroup.xyz/b2/LICENSE.txt)
+ */
+
+#include "../mem.h"
+#include "../native.h"
+#include "../jam_strings.h"
+#include "../subst.h"
+
+/*
+rule split ( string separator )
+{
+ local result ;
+ local s = $(string) ;
+
+ local match = 1 ;
+ while $(match)
+ {
+ match = [ MATCH ^(.*)($(separator))(.*) : $(s) ] ;
+ if $(match)
+ {
+ match += "" ; # in case 3rd item was empty - works around MATCH bug
+ result = $(match[3]) $(result) ;
+ s = $(match[1]) ;
+ }
+ }
+ return $(s) $(result) ;
+}
+*/
+
+LIST * regex_split( FRAME * frame, int flags )
+{
+ LIST * args = lol_get( frame->args, 0 );
+ OBJECT * s;
+ OBJECT * separator;
+ regexp * re;
+ const char * pos, * prev;
+ LIST * result = L0;
+ LISTITER iter = list_begin( args );
+ s = list_item( iter );
+ separator = list_item( list_next( iter ) );
+
+ re = regex_compile( separator );
+
+ prev = pos = object_str( s );
+ while ( regexec( re, pos ) )
+ {
+ result = list_push_back( result, object_new_range( prev, int32_t(re->startp[ 0 ] - prev) ) );
+ prev = re->endp[ 0 ];
+ /* Handle empty matches */
+ if ( *pos == '\0' )
+ break;
+ else if ( pos == re->endp[ 0 ] )
+ pos++;
+ else
+ pos = re->endp[ 0 ];
+ }
+
+ result = list_push_back( result, object_new( pos ) );
+
+ return result;
+}
+
+/*
+rule replace (
+ string # The string to modify.
+ match # The characters to replace.
+ replacement # The string to replace with.
+ )
+{
+ local result = "" ;
+ local parts = 1 ;
+ while $(parts)
+ {
+ parts = [ MATCH ^(.*)($(match))(.*) : $(string) ] ;
+ if $(parts)
+ {
+ parts += "" ;
+ result = "$(replacement)$(parts[3])$(result)" ;
+ string = $(parts[1]) ;
+ }
+ }
+ string ?= "" ;
+ result = "$(string)$(result)" ;
+ return $(result) ;
+}
+*/
+
+LIST * regex_replace( FRAME * frame, int flags )
+{
+ LIST * args = lol_get( frame->args, 0 );
+ OBJECT * s;
+ OBJECT * match;
+ OBJECT * replacement;
+ regexp * re;
+ const char * pos;
+ string buf[ 1 ];
+ LIST * result;
+ LISTITER iter = list_begin( args );
+ s = list_item( iter );
+ iter = list_next( iter );
+ match = list_item( iter );
+ iter = list_next( iter );
+ replacement = list_item(iter );
+
+ re = regex_compile( match );
+
+ string_new( buf );
+
+ pos = object_str( s );
+ while ( regexec( re, pos ) )
+ {
+ string_append_range( buf, pos, re->startp[ 0 ] );
+ string_append( buf, object_str( replacement ) );
+ /* Handle empty matches */
+ if ( *pos == '\0' )
+ break;
+ else if ( pos == re->endp[ 0 ] )
+ string_push_back( buf, *pos++ );
+ else
+ pos = re->endp[ 0 ];
+ }
+ string_append( buf, pos );
+
+ result = list_new( object_new( buf->value ) );
+
+ string_free( buf );
+
+ return result;
+}
+
+/*
+rule transform ( list * : pattern : indices * )
+{
+ indices ?= 1 ;
+ local result ;
+ for local e in $(list)
+ {
+ local m = [ MATCH $(pattern) : $(e) ] ;
+ if $(m)
+ {
+ result += $(m[$(indices)]) ;
+ }
+ }
+ return $(result) ;
+}
+*/
+
+LIST * regex_transform( FRAME * frame, int flags )
+{
+ LIST * const l = lol_get( frame->args, 0 );
+ LIST * const pattern = lol_get( frame->args, 1 );
+ LIST * const indices_list = lol_get( frame->args, 2 );
+ int * indices = 0;
+ int size;
+ LIST * result = L0;
+
+ if ( !list_empty( indices_list ) )
+ {
+ int * p;
+ LISTITER iter = list_begin( indices_list );
+ LISTITER const end = list_end( indices_list );
+ size = list_length( indices_list );
+ indices = (int *)BJAM_MALLOC( size * sizeof( int ) );
+ for ( p = indices; iter != end; iter = list_next( iter ) )
+ *p++ = atoi( object_str( list_item( iter ) ) );
+ }
+ else
+ {
+ size = 1;
+ indices = (int *)BJAM_MALLOC( sizeof( int ) );
+ *indices = 1;
+ }
+
+ {
+ /* Result is cached and intentionally never freed */
+ regexp * const re = regex_compile( list_front( pattern ) );
+
+ LISTITER iter = list_begin( l );
+ LISTITER const end = list_end( l );
+
+ string buf[ 1 ];
+ string_new( buf );
+
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ if ( regexec( re, object_str( list_item( iter ) ) ) )
+ {
+ int i = 0;
+ for ( ; i < size; ++i )
+ {
+ int const index = indices[ i ];
+ /* Skip empty submatches. Not sure it is right in all cases,
+ * but surely is right for the case for which this routine
+ * is optimized -- header scanning.
+ */
+ if ( re->startp[ index ] != re->endp[ index ] )
+ {
+ string_append_range( buf, re->startp[ index ],
+ re->endp[ index ] );
+ result = list_push_back( result, object_new( buf->value
+ ) );
+ string_truncate( buf, 0 );
+ }
+ }
+ }
+ }
+ string_free( buf );
+ }
+
+ BJAM_FREE( indices );
+ return result;
+}
+
+
+void init_regex()
+{
+ {
+ char const * args[] = { "string", "separator", 0 };
+ declare_native_rule( "regex", "split", args, regex_split, 1 );
+ }
+ {
+ char const * args[] = { "string", "match", "replacement", 0 };
+ declare_native_rule( "regex", "replace", args, regex_replace, 1 );
+ }
+ {
+ char const * args[] = { "list", "*", ":", "pattern", ":", "indices", "*", 0 };
+ declare_native_rule( "regex", "transform", args, regex_transform, 2 );
+ }
+}