1 #include "jam.h"
2 #include "subst.h"
3 
4 #include "builtins.h"
5 #include "frames.h"
6 #include "hash.h"
7 #include "lists.h"
8 
9 #include <stddef.h>
10 
11 
12 typedef struct regex_entry
13 {
14     OBJECT * pattern;
15     regexp * regex;
16 } regex_entry;
17 
18 static struct hash * regex_hash;
19 
20 
regex_compile(OBJECT * pattern)21 regexp * regex_compile( OBJECT * pattern )
22 {
23     int found;
24     regex_entry * e ;
25 
26     if ( !regex_hash )
27         regex_hash = hashinit( sizeof( regex_entry ), "regex" );
28 
29     e = (regex_entry *)hash_insert( regex_hash, pattern, &found );
30     if ( !found )
31     {
32         e->pattern = object_copy( pattern );
33         e->regex = regcomp( (char *)pattern );
34     }
35 
36     return e->regex;
37 }
38 
39 
builtin_subst(FRAME * frame,int flags)40 LIST * builtin_subst( FRAME * frame, int flags )
41 {
42     LIST * result = L0;
43     LIST * const arg1 = lol_get( frame->args, 0 );
44     LISTITER iter = list_begin( arg1 );
45     LISTITER const end = list_end( arg1 );
46 
47     if ( iter != end && list_next( iter ) != end && list_next( list_next( iter )
48         ) != end )
49     {
50         char const * const source = object_str( list_item( iter ) );
51         OBJECT * const pattern = list_item( list_next( iter ) );
52         regexp * const repat = regex_compile( pattern );
53 
54         if ( regexec( repat, (char *)source) )
55         {
56             LISTITER subst = list_next( iter );
57 
58             while ( ( subst = list_next( subst ) ) != end )
59             {
60 #define BUFLEN 4096
61                 char buf[ BUFLEN + 1 ];
62                 char const * in = object_str( list_item( subst ) );
63                 char * out = buf;
64 
65                 for ( ; *in && out < buf + BUFLEN; ++in )
66                 {
67                     if ( *in == '\\' || *in == '$' )
68                     {
69                         ++in;
70                         if ( *in == 0 )
71                             break;
72                         if ( *in >= '0' && *in <= '9' )
73                         {
74                             unsigned int const n = *in - '0';
75                             size_t const srclen = repat->endp[ n ] -
76                                 repat->startp[ n ];
77                             size_t const remaining = buf + BUFLEN - out;
78                             size_t const len = srclen < remaining
79                                 ? srclen
80                                 : remaining;
81                             memcpy( out, repat->startp[ n ], len );
82                             out += len;
83                             continue;
84                         }
85                         /* fall through and copy the next character */
86                     }
87                     *out++ = *in;
88                 }
89                 *out = 0;
90 
91                 result = list_push_back( result, object_new( buf ) );
92 #undef BUFLEN
93             }
94         }
95     }
96 
97     return result;
98 }
99 
100 
free_regex(void * xregex,void * data)101 static void free_regex( void * xregex, void * data )
102 {
103     regex_entry * const regex = (regex_entry *)xregex;
104     object_free( regex->pattern );
105     BJAM_FREE( regex->regex );
106 }
107 
108 
regex_done()109 void regex_done()
110 {
111     if ( regex_hash )
112     {
113         hashenumerate( regex_hash, free_regex, (void *)0 );
114         hashdone( regex_hash );
115     }
116 }
117