diff options
Diffstat (limited to 'tools/build/src/engine/subst.c')
-rw-r--r-- | tools/build/src/engine/subst.c | 116 |
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 ); + } +} |