1 /* |
|
2 * LDForge: LDraw parts authoring CAD |
|
3 * Copyright (C) 2013, 2014 Teemu Piippo |
|
4 * |
|
5 * This program is free software: you can redistribute it and/or modify |
|
6 * it under the terms of the GNU General Public License as published by |
|
7 * the Free Software Foundation, either version 3 of the License, or |
|
8 * (at your option) any later version. |
|
9 * |
|
10 * This program is distributed in the hope that it will be useful, |
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 * GNU General Public License for more details. |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License |
|
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
17 */ |
|
18 |
|
19 #include <sstream> |
|
20 #include <fstream> |
|
21 #include <string> |
|
22 #include <cstring> |
|
23 #include <iostream> |
|
24 #include <vector> |
|
25 #include <algorithm> |
|
26 |
|
27 using std::string; |
|
28 using std::vector; |
|
29 using std::ifstream; |
|
30 using std::size_t; |
|
31 using std::strncmp; |
|
32 using std::getline; |
|
33 using std::cout; |
|
34 using std::endl; |
|
35 |
|
36 struct EntryType |
|
37 { |
|
38 string name; |
|
39 string type; |
|
40 string defvalue; |
|
41 |
|
42 inline bool operator< (EntryType const& other) const |
|
43 { |
|
44 return name < other.name; |
|
45 } |
|
46 |
|
47 inline bool operator== (EntryType const& other) const |
|
48 { |
|
49 return name == other.name and type == other.type; |
|
50 } |
|
51 |
|
52 inline bool operator!= (EntryType const& other) const |
|
53 { |
|
54 return not operator== (other); |
|
55 } |
|
56 }; |
|
57 |
|
58 char AdvancePointer (char const*& ptr) |
|
59 { |
|
60 char a = *ptr++; |
|
61 |
|
62 if (*ptr == '\0') |
|
63 throw false; |
|
64 |
|
65 return a; |
|
66 } |
|
67 |
|
68 void ReadConfigEntries (string const& filename, vector<EntryType>& entries, const char* macroname) |
|
69 { |
|
70 ifstream is (filename.c_str()); |
|
71 string line; |
|
72 size_t const macrolen = strlen (macroname); |
|
73 |
|
74 while (getline (is, line)) |
|
75 { |
|
76 try |
|
77 { |
|
78 if (strncmp (line.c_str(), macroname, macrolen) != 0) |
|
79 continue; |
|
80 |
|
81 char const* ptr = &line[macrolen]; |
|
82 EntryType entry; |
|
83 |
|
84 // Skip to paren |
|
85 while (*ptr != '(') |
|
86 AdvancePointer (ptr); |
|
87 |
|
88 // Skip whitespace |
|
89 while (isspace (*ptr)) |
|
90 AdvancePointer (ptr); |
|
91 |
|
92 // Skip paren |
|
93 AdvancePointer (ptr); |
|
94 |
|
95 // Read type |
|
96 while (*ptr != ',') |
|
97 entry.type += AdvancePointer (ptr); |
|
98 |
|
99 // Skip comma and whitespace |
|
100 for (AdvancePointer (ptr); isspace (*ptr); AdvancePointer (ptr)) |
|
101 ; |
|
102 |
|
103 // Read name |
|
104 while (*ptr != ',') |
|
105 entry.name += AdvancePointer (ptr); |
|
106 |
|
107 // Skip comma and whitespace |
|
108 for (AdvancePointer (ptr); isspace (*ptr); AdvancePointer (ptr)) |
|
109 ; |
|
110 |
|
111 // Read default |
|
112 while (*ptr != ')') |
|
113 entry.defvalue += AdvancePointer (ptr); |
|
114 |
|
115 entries.push_back (entry); |
|
116 } |
|
117 catch (bool) {} |
|
118 } |
|
119 } |
|
120 |
|
121 bool CheckEquality (vector<EntryType> a, vector<EntryType> b) |
|
122 { |
|
123 if (a.size() != b.size()) |
|
124 return false; |
|
125 |
|
126 std::sort (a.begin(), a.end()); |
|
127 std::sort (b.begin(), b.end()); |
|
128 |
|
129 for (size_t i = 0; i < a.size(); ++i) |
|
130 { |
|
131 if (a[i] != b[i]) |
|
132 return false; |
|
133 } |
|
134 |
|
135 return true; |
|
136 } |
|
137 |
|
138 int main (int argc, char* argv[]) |
|
139 { |
|
140 vector<EntryType> entries; |
|
141 vector<EntryType> oldentries; |
|
142 ReadConfigEntries (argv[argc - 1], oldentries, "CODEGEN_CACHE"); |
|
143 |
|
144 for (int arg = 1; arg < argc - 1; ++arg) |
|
145 ReadConfigEntries (argv[arg], entries, "CFGENTRY"); |
|
146 |
|
147 if (CheckEquality (entries, oldentries)) |
|
148 { |
|
149 cout << "Configuration options unchanged" << endl; |
|
150 return 0; |
|
151 } |
|
152 |
|
153 std::ofstream os (argv[argc - 1]); |
|
154 os << "#pragma once" << endl; |
|
155 os << "#define CODEGEN_CACHE(A,B,C)" << endl; |
|
156 |
|
157 for (vector<EntryType>::const_iterator it = entries.begin(); it != entries.end(); ++it) |
|
158 { |
|
159 os << "CODEGEN_CACHE (" << it->type << ", " << it->name << ", " << |
|
160 it->defvalue << ")" << endl; |
|
161 } |
|
162 |
|
163 os << endl; |
|
164 for (vector<EntryType>::const_iterator it = entries.begin(); it != entries.end(); ++it) |
|
165 os << "EXTERN_CFGENTRY (" << it->type << ", " << it->name << ")" << endl; |
|
166 |
|
167 os << endl; |
|
168 os << "static void InitConfigurationEntry (AbstractConfigEntry* entry);" << endl; |
|
169 os << "static void SetupConfigurationLists()" << endl; |
|
170 os << "{" << endl; |
|
171 |
|
172 for (vector<EntryType>::const_iterator it = entries.begin(); it != entries.end(); ++it) |
|
173 { |
|
174 os << "\tInitConfigurationEntry (new " << it->type << "ConfigEntry (&cfg::" << |
|
175 it->name << ", \"" << it->name << "\", " << it->defvalue << "));" << endl; |
|
176 } |
|
177 |
|
178 os << "}" << endl; |
|
179 cout << "Wrote configuration options list to " << argv[argc - 1] << "." << endl; |
|
180 return 0; |
|
181 } |
|