codec cleanup
[platform/upstream/boost-jam.git] / subst.c
1 #include <stddef.h>
2 #include "jam.h"
3 #include "regexp.h"
4 #include "hash.h"
5
6 #include "newstr.h"
7 #include "lists.h"
8 #include "parse.h"
9 #include "compile.h"
10 #include "frames.h"
11
12 struct regex_entry
13 {
14     const char* pattern;
15     regexp* regex;
16 };
17 typedef struct regex_entry regex_entry;
18
19 static struct hash* regex_hash;
20
21 regexp* regex_compile( const char* pattern )
22 {
23     regex_entry entry, *e = &entry;
24     entry.pattern = pattern;
25
26     if ( !regex_hash )
27         regex_hash = hashinit(sizeof(regex_entry), "regex");
28
29     if ( hashenter( regex_hash, (HASHDATA **)&e ) )
30         e->regex = regcomp( (char*)pattern );
31
32     return e->regex;
33 }
34
35 LIST*
36 builtin_subst(
37     PARSE    *parse,
38     FRAME      *frame )
39 {
40   LIST* result = L0;
41   LIST* arg1 = lol_get( frame->args, 0 );
42
43   if ( arg1 && list_next(arg1) && list_next(list_next(arg1)) )
44   {
45
46       const char* source = arg1->string;
47       const char* pattern = list_next(arg1)->string;
48       regexp* repat = regex_compile( pattern );
49
50       if ( regexec( repat, (char*)source) )
51       {
52           LIST* subst = list_next(arg1);
53
54           while ((subst = list_next(subst)) != L0)
55           {
56 # define BUFLEN 4096
57               char buf[BUFLEN + 1];
58               const char* in = subst->string;
59               char* out = buf;
60
61               for ( in = subst->string; *in && out < buf + BUFLEN; ++in )
62               {
63                   if ( *in == '\\' || *in == '$' )
64                   {
65                       ++in;
66                       if ( *in == 0 )
67                       {
68                           break;
69                       }
70                       else if ( *in >= '0' && *in <= '9' )
71                       {
72                           unsigned n = *in - '0';
73                           const size_t srclen = repat->endp[n] - repat->startp[n];
74                           const size_t remaining = buf + BUFLEN - out;
75                           const size_t len = srclen < remaining ? srclen : remaining;
76                           memcpy( out, repat->startp[n], len );
77                           out += len;
78                           continue;
79                       }
80                       /* fall through and copy the next character */
81                   }
82                   *out++ = *in;
83               }
84               *out = 0;
85
86               result = list_new( result, newstr( buf ) );
87 #undef BUFLEN
88           }
89       }
90   }
91
92   return result;
93 }
94