#include #include "jam.h" #include "regexp.h" #include "hash.h" #include "object.h" #include "lists.h" #include "compile.h" #include "frames.h" #include "builtins.h" struct regex_entry { OBJECT* pattern; regexp* regex; }; typedef struct regex_entry 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* arg1 = lol_get( frame->args, 0 ); LISTITER iter = list_begin( arg1 ), end = list_end( arg1 ); if ( iter != end && list_next( iter ) != end && list_next( list_next( iter ) ) != end ) { const char* source = object_str( list_item( iter ) ); OBJECT * pattern = list_item( list_next( iter ) ); regexp* 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]; const char* in = object_str( list_item( subst ) ); char* out = buf; for ( ; *in && out < buf + BUFLEN; ++in ) { if ( *in == '\\' || *in == '$' ) { ++in; if ( *in == 0 ) { break; } else if ( *in >= '0' && *in <= '9' ) { unsigned n = *in - '0'; const size_t srclen = repat->endp[n] - repat->startp[n]; const size_t remaining = buf + BUFLEN - out; const size_t 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 * 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 ); } }