summaryrefslogtreecommitdiff
path: root/tools/build/src/engine/subst.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/build/src/engine/subst.c')
-rw-r--r--tools/build/src/engine/subst.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/tools/build/src/engine/subst.c b/tools/build/src/engine/subst.c
new file mode 100644
index 0000000000..a5fcee08cb
--- /dev/null
+++ b/tools/build/src/engine/subst.c
@@ -0,0 +1,116 @@
+#include "jam.h"
+#include "subst.h"
+
+#include "builtins.h"
+#include "frames.h"
+#include "hash.h"
+#include "lists.h"
+
+#include <stddef.h>
+
+
+typedef struct regex_entry
+{
+ OBJECT * pattern;
+ regexp * regex;
+} regex_entry;
+
+static struct hash * regex_hash;
+
+
+regexp * regex_compile( OBJECT * pattern )
+{
+ int found;
+ regex_entry * e ;
+
+ if ( !regex_hash )
+ regex_hash = hashinit( sizeof( regex_entry ), "regex" );
+
+ e = (regex_entry *)hash_insert( regex_hash, pattern, &found );
+ if ( !found )
+ {
+ e->pattern = object_copy( pattern );
+ e->regex = regcomp( (char *)pattern );
+ }
+
+ return e->regex;
+}
+
+
+LIST * builtin_subst( FRAME * frame, int flags )
+{
+ LIST * result = L0;
+ LIST * const arg1 = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( arg1 );
+ LISTITER const end = list_end( arg1 );
+
+ if ( iter != end && list_next( iter ) != end && list_next( list_next( iter )
+ ) != end )
+ {
+ char const * const source = object_str( list_item( iter ) );
+ OBJECT * const pattern = list_item( list_next( iter ) );
+ regexp * const repat = regex_compile( pattern );
+
+ if ( regexec( repat, (char *)source) )
+ {
+ LISTITER subst = list_next( iter );
+
+ while ( ( subst = list_next( subst ) ) != end )
+ {
+#define BUFLEN 4096
+ char buf[ BUFLEN + 1 ];
+ char const * in = object_str( list_item( subst ) );
+ char * out = buf;
+
+ for ( ; *in && out < buf + BUFLEN; ++in )
+ {
+ if ( *in == '\\' || *in == '$' )
+ {
+ ++in;
+ if ( *in == 0 )
+ break;
+ if ( *in >= '0' && *in <= '9' )
+ {
+ unsigned int const n = *in - '0';
+ size_t const srclen = repat->endp[ n ] -
+ repat->startp[ n ];
+ size_t const remaining = buf + BUFLEN - out;
+ size_t const len = srclen < remaining
+ ? srclen
+ : remaining;
+ memcpy( out, repat->startp[ n ], len );
+ out += len;
+ continue;
+ }
+ /* fall through and copy the next character */
+ }
+ *out++ = *in;
+ }
+ *out = 0;
+
+ result = list_push_back( result, object_new( buf ) );
+#undef BUFLEN
+ }
+ }
+ }
+
+ return result;
+}
+
+
+static void free_regex( void * xregex, void * data )
+{
+ regex_entry * const regex = (regex_entry *)xregex;
+ object_free( regex->pattern );
+ BJAM_FREE( regex->regex );
+}
+
+
+void regex_done()
+{
+ if ( regex_hash )
+ {
+ hashenumerate( regex_hash, free_regex, (void *)0 );
+ hashdone( regex_hash );
+ }
+}