1
2
3
4
5 :(scenarios run_mu_scenario)
6 :(scenario simple_filesystem)
7 scenario simple-filesystem [
8 local-scope
9 assume-resources [
10 ¦
11 ¦ [a] <- [
12 ¦ ¦ |a bc|
13 ¦ ¦ |de f|
14 ¦ ]
15 ¦
16 ¦ [b/c] <- []
17 ¦ [b/d] <- [
18 ¦ ¦ |xyz|
19 ¦ ]
20 ]
21 data:&:@:resource <- get *resources, data:offset
22 file1:resource <- index *data, 0
23 file1-name:text <- get file1, name:offset
24 10:@:char/raw <- copy *file1-name
25 file1-contents:text <- get file1, contents:offset
26 100:@:char/raw <- copy *file1-contents
27 file2:resource <- index *data, 1
28 file2-name:text <- get file2, name:offset
29 30:@:char/raw <- copy *file2-name
30 file2-contents:text <- get file2, contents:offset
31 40:@:char/raw <- copy *file2-contents
32 file3:resource <- index *data, 2
33 file3-name:text <- get file3, name:offset
34 50:@:char/raw <- copy *file3-name
35 file3-contents:text <- get file3, contents:offset
36 60:@:char/raw <- copy *file3-contents
37 memory-should-contain [
38 ¦ 10:array:character <- [a]
39 ¦ 100:array:character <- [a bc
40 de f
41 ]
42 ¦ 30:array:character <- [b/c]
43 ¦ 40:array:character <- []
44 ¦ 50:array:character <- [b/d]
45 ¦ 60:array:character <- [xyz
46 ]
47 ]
48 ]
49
50 :(scenario escaping_file_contents)
51 scenario escaping-file-contents [
52 local-scope
53 assume-resources [
54 ¦
55 ¦
56 ¦ [a] <- [
57 ¦ ¦ |x\\\\|yz|
58 ¦ ]
59 ]
60 data:&:@:resource <- get *resources, data:offset
61 file1:resource <- index *data, 0
62 file1-name:text <- get file1, name:offset
63 10:@:char/raw <- copy *file1-name
64 file1-contents:text <- get file1, contents:offset
65 20:@:char/raw <- copy *file1-contents
66 memory-should-contain [
67 ¦ 10:array:character <- [a]
68 ¦ 20:array:character <- [x|yz
69 ]
70 ]
71 ]
72
73 :(before "End Globals")
74 extern const int RESOURCES = Next_predefined_global_for_scenarios++;
75
76 :(before "End Special Scenario Variable Names(r)")
77 Name[r]["resources"] = RESOURCES;
78
79 :(before "End is_special_name Special-cases")
80 if (s == "resources") return true;
81 :(before "End Initialize Type Of Special Name In Scenario(r)")
82 if (r.name == "resources") r.type = new_type_tree("address:resources");
83
84 :(before "End initialize_transform_rewrite_literal_string_to_text()")
85 recipes_taking_literal_strings.insert("assume-resources");
86
87
88 :(before "End Primitive Recipe Declarations")
89 ASSUME_RESOURCES,
90 :(before "End Primitive Recipe Numbers")
91 put(Recipe_ordinal, "assume-resources", ASSUME_RESOURCES);
92 :(before "End Primitive Recipe Checks")
93 case ASSUME_RESOURCES: {
94 break;
95 }
96 :(before "End Primitive Recipe Implementations")
97 case ASSUME_RESOURCES: {
98 assert(scalar(ingredients.at(0)));
99 assume_resources(current_instruction().ingredients.at(0).name, current_recipe_name());
100 break;
101 }
102
103 :(code)
104 void assume_resources(const string& data, const string& caller) {
105 map<string, string> contents;
106 parse_resources(data, contents, caller);
107 construct_resources_object(contents);
108 }
109
110 void parse_resources(const string& data, map<string, string>& out, const string& caller) {
111 istringstream in(data);
112 in >> std::noskipws;
113 while (true) {
114 ¦ if (!has_data(in)) break;
115 ¦ skip_whitespace_and_comments(in);
116 ¦ if (!has_data(in)) break;
117 ¦ string filename = next_word(in);
118 ¦ if (filename.empty()) {
119 ¦ ¦ assert(!has_data(in));
120 ¦ ¦ raise << "incomplete 'resources' block at end of file (0)\n" << end();
121 ¦ ¦ return;
122 ¦ }
123 ¦ if (*filename.begin() != '[') {
124 ¦ ¦ raise << caller << ": assume-resources: filename '" << filename << "' must begin with a '['\n" << end();
125 ¦ ¦ break;
126 ¦ }
127 ¦ if (*filename.rbegin() != ']') {
128 ¦ ¦ raise << caller << ": assume-resources: filename '" << filename << "' must end with a ']'\n" << end();
129 ¦ ¦ break;
130 ¦ }
131 ¦ filename.erase(0, 1);
132 ¦ filename.erase(SIZE(filename)-1);
133 ¦ if (!has_data(in)) {
134 ¦ ¦ raise << caller << ": assume-resources: no data for filename '" << filename << "'\n" << end();
135 ¦ ¦ break;
136 ¦ }
137 ¦ string arrow = next_word(in);
138 ¦ if (arrow.empty()) {
139 ¦ ¦ assert(!has_data(in));
140 ¦ ¦ raise << "incomplete 'resources' block at end of file (1)\n" << end();
141 ¦ ¦ return;
142 ¦ }
143 ¦ if (arrow != "<-") {
144 ¦ ¦ raise << caller << ": assume-resources: expected '<-' after filename '" << filename << "' but got '" << arrow << "'\n" << end();
145 ¦ ¦ break;
146 ¦ }
147 ¦ if (!has_data(in)) {
148 ¦ ¦ raise << caller << ": assume-resources: no data for filename '" << filename << "' after '<-'\n" << end();
149 ¦ ¦ break;
150 ¦ }
151 ¦ string contents = next_word(in);
152 ¦ if (contents.empty()) {
153 ¦ ¦ assert(!has_data(in));
154 ¦ ¦ raise << "incomplete 'resources' block at end of file (2)\n" << end();
155 ¦ ¦ return;
156 ¦ }
157 ¦ if (*contents.begin() != '[') {
158 ¦ ¦ raise << caller << ": assume-resources: file contents '" << contents << "' for filename '" << filename << "' must begin with a '['\n" << end();
159 ¦ ¦ break;
160 ¦ }
161 ¦ if (*contents.rbegin() != ']') {
162 ¦ ¦ raise << caller << ": assume-resources: file contents '" << contents << "' for filename '" << filename << "' must end with a ']'\n" << end();
163 ¦ ¦ break;
164 ¦ }
165 ¦ contents.erase(0, 1);
166 ¦ contents.erase(SIZE(contents)-1);
167 ¦ put(out, filename, munge_resources_contents(contents, filename, caller));
168 }
169 }
170
171 string munge_resources_contents(const string& data, const string& filename, const string& caller) {
172 if (data.empty()) return "";
173 istringstream in(data);
174 in >> std::noskipws;
175 skip_whitespace_and_comments(in);
176 ostringstream out;
177 while (true) {
178 ¦ if (!has_data(in)) break;
179 ¦ skip_whitespace(in);
180 ¦ if (!has_data(in)) break;
181 ¦ if (in.peek() != '|') {
182 ¦ ¦ raise << caller << ": assume-resources: file contents for filename '" << filename << "' must be delimited in '|'s\n" << end();
183 ¦ ¦ break;
184 ¦ }
185 ¦ in.get();
186 ¦ string line;
187 ¦ getline(in, line);
188 ¦ for (int i = 0; i < SIZE(line); ++i) {
189 ¦ ¦ if (line.at(i) == '|') break;
190 ¦ ¦ if (line.at(i) == '\\') {
191 ¦ ¦ ¦ ++i;
192 ¦ ¦ ¦ if (i == SIZE(line)) {
193 ¦ ¦ ¦ ¦ raise << caller << ": assume-resources: file contents can't end a line with '\\'\n" << end();
194 ¦ ¦ ¦ ¦ break;
195 ¦ ¦ ¦ }
196 ¦ ¦ }
197 ¦ ¦ out << line.at(i);
198 ¦ }
199 ¦
200 ¦ out << '\n';
201 }
202 return out.str();
203 }
204
205 void construct_resources_object(const map<string, string>& contents) {
206 int resources_data_address = allocate(SIZE(contents)*2 + 1);
207 int curr = resources_data_address + 2;
208 for (map<string, string>::const_iterator p = contents.begin(); p != contents.end(); ++p) {
209 ¦ put(Memory, curr, new_mu_text(p->first));
210 ¦ trace("mem") << "storing file name " << get(Memory, curr) << " in location " << curr << end();
211 ¦ put(Memory, get(Memory, curr), 1);
212 ¦ trace("mem") << "storing refcount 1 in location " << get(Memory, curr) << end();
213 ¦ ++curr;
214 ¦ put(Memory, curr, new_mu_text(p->second));
215 ¦ trace("mem") << "storing file contents " << get(Memory, curr) << " in location " << curr << end();
216 ¦ put(Memory, get(Memory, curr), 1);
217 ¦ trace("mem") << "storing refcount 1 in location " << get(Memory, curr) << end();
218 ¦ ++curr;
219 }
220 curr = resources_data_address+1;
221 put(Memory, curr, SIZE(contents));
222 trace("mem") << "storing resources size " << get(Memory, curr) << " in location " << curr << end();
223 put(Memory, resources_data_address, 1);
224 trace("mem") << "storing refcount 1 in location " << resources_data_address << end();
225
226 int resources_address = allocate(size_of_resources());
227 curr = resources_address+1+1;
228 put(Memory, curr, resources_data_address);
229 trace("mem") << "storing resources data address " << resources_data_address << " in location " << curr << end();
230 put(Memory, resources_address, 1);
231 trace("mem") << "storing refcount 1 in location " << resources_address << end();
232
233 put(Memory, RESOURCES, resources_address);
234 trace("mem") << "storing resources address " << resources_address << " in location " << RESOURCES << end();
235 }
236
237 int size_of_resources() {
238
239 static int result = 0;
240 if (result) return result;
241 assert(get(Type_ordinal, "resources"));
242 type_tree* type = new type_tree("resources");
243 result = size_of(type)+1;
244 delete type;
245 return result;
246 }