]> git.tdb.fi Git - libs/datafile.git/blob - tool/compiler.cpp
Add a compile mode to mspdatatool
[libs/datafile.git] / tool / compiler.cpp
1 /* $Id$
2
3 This file is part of libmspdatafile
4 Copyright © 2008  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <msp/datafile/parser.h>
9 #include <msp/fs/dir.h>
10 #include <msp/fs/utils.h>
11 #include <msp/strings/regex.h>
12 #include "compiler.h"
13
14 using namespace std;
15 using namespace Msp;
16
17 Compiler::Compiler(DataFile::Writer &w):
18         writer(w)
19 {
20         add("file",     &Compiler::file);
21         add("for_each", &Compiler::for_each);
22         add("write",    &Compiler::write);
23 }
24
25 void Compiler::file(const string &fn)
26 {
27         File fl(*this, FS::dirname(get_source())/fn);
28         load_sub_with(fl);
29 }
30
31 void Compiler::for_each(const vector<string> &patterns)
32 {
33         ForEach fe(*this, FS::dirname(get_source()), list<string>(patterns.begin(), patterns.end()));
34         load_sub_with(fe);
35 }
36
37 void Compiler::write(const DataFile::Statement &st)
38 {
39         for(list<DataFile::Statement>::const_iterator i=st.sub.begin(); i!=st.sub.end(); ++i)
40                 writer.write(*i);
41 }
42
43 bool Compiler::process_statement(const FS::Path &fn, DataFile::Statement &st)
44 {
45         if(st.keyword=="_content")
46                 return true;
47
48         for(vector<DataFile::Value>::iterator i=st.args.begin(); i!=st.args.end(); ++i)
49                 if(i->get_type()==DataFile::STRING)
50                 {
51                         if(i->get_raw()=="$filename")
52                                 *i=DataFile::Value(FS::basename(fn.str()));
53                         else if(i->get_raw()=="$content")
54                         {
55                                 IO::File in(fn.str());
56                                 string data;
57                                 while(!in.eof())
58                                 {
59                                         char buf[4096];
60                                         unsigned len=in.read(buf, sizeof(buf));
61                                         data.append(buf, len);
62                                 }
63                                 *i=DataFile::Value(data);
64                         }
65                 }
66
67         for(list<DataFile::Statement>::iterator i=st.sub.begin(); i!=st.sub.end();)
68         {
69                 if(process_statement(fn, *i))
70                 {
71                         IO::File in(fn.str());
72                         IO::Buffered buf(in);
73
74                         DataFile::Parser parser(in, fn.str());
75                         while(parser)
76                         {
77                                 DataFile::Statement ss=parser.parse();
78                                 if(ss.valid)
79                                         st.sub.insert(i, ss);
80                         }
81                         i=st.sub.erase(i);
82                 }
83                 else
84                         ++i;
85         }
86
87         return false;
88 }
89
90 void Compiler::process_file(const FS::Path &fn, const list<DataFile::Statement> &st)
91 {
92         for(list<DataFile::Statement>::const_iterator i=st.begin(); i!=st.end(); ++i)
93         {
94                 if(i->keyword=="_content")
95                         process_file(fn);
96                 else
97                 {
98                         DataFile::Statement s=*i;
99                         process_statement(fn, s);
100                         writer.write(s);
101                 }
102         }
103 }
104
105 void Compiler::process_file(const FS::Path &fn)
106 {
107         IO::File in(fn.str());
108         IO::Buffered buf(in);
109
110         DataFile::Parser parser(in, fn.str());
111         while(parser)
112         {
113                 DataFile::Statement st=parser.parse();
114                 if(st.valid)
115                         writer.write(st);
116         }
117 }
118
119
120 File::File(Compiler &c, const FS::Path &fn):
121         compiler(c),
122         filename(fn)
123 {
124         add("write", &File::write);
125 }
126
127 void File::finish()
128 {
129         if(write_st.empty())
130                 compiler.process_file(filename);
131         else
132                 compiler.process_file(filename, write_st);
133 }
134
135 void File::write(const DataFile::Statement &st)
136 {
137         write_st.insert(write_st.end(), st.sub.begin(), st.sub.end());
138 }
139
140
141 ForEach::ForEach(Compiler &c, const FS::Path &b, const list<string> &p):
142         compiler(c),
143         base(b),
144         patterns(p)
145 {
146         add("exclude", &ForEach::exclude);
147         add("pattern", &ForEach::pattern);
148         add("write",   &ForEach::write);
149 }
150
151 void ForEach::finish()
152 {
153         list<string> files=FS::list_files(base);
154         for(list<string>::iterator i=files.begin(); i!=files.end(); ++i)
155         {
156                 bool match=false;
157                 for(list<string>::const_iterator j=patterns.begin(); (j!=patterns.end() && !match); ++j)
158                         match=Regex(*j).match(*i);
159                 for(list<string>::const_iterator j=excludes.begin(); (j!=excludes.end() && match); ++j)
160                         match=!Regex(*j).match(*i);
161                 if(match)
162                         compiler.process_file(base / *i, write_st);
163         }
164 }
165
166 void ForEach::exclude(const string &p)
167 {
168         excludes.push_back(p);
169 }
170
171 void ForEach::pattern(const string &p)
172 {
173         patterns.push_back(p);
174 }
175
176 void ForEach::write(const DataFile::Statement &st)
177 {
178         write_st.insert(write_st.end(), st.sub.begin(), st.sub.end());
179 }