#include "jam.h" #include "subst.h" #include "builtins.h" #include "frames.h" #include "hash.h" #include "lists.h" #include 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 ); } }