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