stash 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,267 @@
1
+ #include "intern.h"
2
+
3
+ /* forward declare helper functions */
4
+ static void append_node(mustache_node_t* parent, mustache_node_t* src);
5
+ static mustache_error_t* create_error(mustache_token_t* last_token, enum mustache_token_type expected_token, char* error_text);
6
+
7
+ /*
8
+
9
+ template := block
10
+ block := statement | block
11
+ statement := [text] | [newline] | command
12
+ command := variable | section | inverse_section | partial | comment
13
+ variable := [raw] [identifier] | [identifier]
14
+ section := [section_start] [identifier] block [section_end]
15
+ inverse_section := [inverse_section_start] [identifier] block [section_end]
16
+ partial := [partial] [identifier]
17
+
18
+ */
19
+
20
+ void build_template(mustache_token_t* tokens, mustache_node_t* root, mustache_error_t** error)
21
+ {
22
+ root->type = NODE_BLOCK;
23
+ root->execute = execute_block;
24
+ root->optimize = optimize_block;
25
+ append_node(root, build_block(&tokens, error));
26
+
27
+ if (tokens) {
28
+ *error = create_error(tokens, TOKEN_ERROR, tokens->text);
29
+ }
30
+ }
31
+
32
+ mustache_node_t* build_block(mustache_token_t** tokens, mustache_error_t** error)
33
+ {
34
+ mustache_node_t* block;
35
+ mustache_node_t* next;
36
+
37
+ block = mustache_create_node();
38
+ block->type = NODE_BLOCK;
39
+ block->execute = execute_block;
40
+ block->optimize = optimize_block;
41
+
42
+ while ((next = build_statement(tokens, error))) {
43
+ append_node(block, next);
44
+ }
45
+
46
+ return block;
47
+ }
48
+
49
+ mustache_node_t* build_statement(mustache_token_t** tokens, mustache_error_t** error)
50
+ {
51
+ mustache_node_t* next = build_text(tokens, error);
52
+
53
+ if (!next) {
54
+ next = build_newline(tokens, error);
55
+ }
56
+
57
+ if (!next) {
58
+ next = build_command(tokens, error);
59
+ }
60
+
61
+ return next;
62
+ }
63
+
64
+ mustache_node_t* build_text(mustache_token_t** tokens, mustache_error_t** error)
65
+ {
66
+ mustache_node_t* next;
67
+
68
+ if (!is_token(*tokens, TOKEN_TEXT)) {
69
+ return NULL;
70
+ }
71
+
72
+ next = mustache_create_node();
73
+ next->type = NODE_TEXT;
74
+ next->token = pop_token(tokens);
75
+ next->execute = execute_text;
76
+ next->optimize = optimize_text;
77
+ return next;
78
+ }
79
+
80
+ mustache_node_t* build_newline(mustache_token_t** tokens, mustache_error_t** error)
81
+ {
82
+ mustache_node_t* next;
83
+
84
+ if (!is_token(*tokens, TOKEN_NEWLINE)) {
85
+ return NULL;
86
+ }
87
+
88
+ next = mustache_create_node();
89
+ next->type = NODE_NEWLINE;
90
+ next->token = pop_token(tokens);
91
+ next->execute = execute_newline;
92
+ next->optimize = optimize_newline;
93
+ return next;
94
+ }
95
+
96
+ mustache_node_t* build_command(mustache_token_t** tokens, mustache_error_t** error)
97
+ {
98
+ mustache_node_t* next = build_raw_variable(tokens, error);
99
+
100
+ if (!next) {
101
+ next = build_variable(tokens, error);
102
+ }
103
+
104
+ if (!next) {
105
+ next = build_section(tokens, error);
106
+ }
107
+
108
+ if (!next) {
109
+ next = build_partial(tokens, error);
110
+ }
111
+
112
+ if (!next) {
113
+ next = build_comment(tokens, error);
114
+ }
115
+
116
+ return next;
117
+ }
118
+
119
+ mustache_node_t* build_raw_variable(mustache_token_t** tokens, mustache_error_t** error)
120
+ {
121
+ mustache_node_t* next;
122
+
123
+ if (!is_token(*tokens, TOKEN_RAW)) {
124
+ return NULL;
125
+ }
126
+
127
+ free_token(pop_token(tokens));
128
+
129
+ if (!is_token(*tokens, TOKEN_IDENTIFIER)) {
130
+ *error = create_error(*tokens, TOKEN_IDENTIFIER, "Expected identifier");
131
+ }
132
+
133
+ next = mustache_create_node();
134
+ next->type = NODE_RAW_VARIABLE;
135
+ next->token = pop_token(tokens);
136
+ next->execute = execute_raw_variable;
137
+ next->optimize = optimize_variable;
138
+ return next;
139
+ }
140
+
141
+ mustache_node_t* build_variable(mustache_token_t** tokens, mustache_error_t** error)
142
+ {
143
+ mustache_node_t* next;
144
+
145
+ if (!is_token(*tokens, TOKEN_IDENTIFIER)) {
146
+ return NULL;
147
+ }
148
+
149
+ next = mustache_create_node();
150
+ next->type = NODE_VARIABLE;
151
+ next->token = pop_token(tokens);
152
+ next->execute = execute_variable;
153
+ next->optimize = optimize_variable;
154
+ return next;
155
+ }
156
+
157
+ mustache_node_t* build_section(mustache_token_t** tokens, mustache_error_t** error)
158
+ {
159
+ mustache_node_t* section;
160
+ mustache_token_t* token;
161
+ bool is_inverted;
162
+
163
+ if (!is_token(*tokens, TOKEN_SECTION_START) &&
164
+ !is_token(*tokens, TOKEN_ISECTION_START)) {
165
+ return NULL;
166
+ }
167
+
168
+ token = pop_token(tokens);
169
+ is_inverted = token->type == TOKEN_ISECTION_START;
170
+ free_token(token);
171
+
172
+ if (!is_token(*tokens, TOKEN_IDENTIFIER)) {
173
+ *error = create_error(*tokens, TOKEN_IDENTIFIER, "Expected identifier");
174
+ return NULL;
175
+ }
176
+
177
+ section = mustache_create_node();
178
+ section->type = is_inverted ? NODE_INVERTED_SECTION : NODE_SECTION;
179
+ section->token = pop_token(tokens);
180
+ section->execute = execute_section;
181
+ section->optimize = optimize_section;
182
+ append_node(section, build_block(tokens, error));
183
+
184
+ if (!is_token(*tokens, TOKEN_SECTION_END)) {
185
+ *error = create_error(*tokens, TOKEN_SECTION_END, "Expected section end");
186
+ return NULL;
187
+ }
188
+
189
+ free_token(pop_token(tokens));
190
+
191
+ if (!is_token(*tokens, TOKEN_IDENTIFIER)) {
192
+ *error = create_error(*tokens, TOKEN_IDENTIFIER, "Expected identifier");
193
+ return NULL;
194
+ }
195
+
196
+ free_token(pop_token(tokens));
197
+
198
+ return section;
199
+ }
200
+
201
+ mustache_node_t* build_partial(mustache_token_t** tokens, mustache_error_t** error)
202
+ {
203
+ mustache_node_t* node;
204
+
205
+ if (!is_token(*tokens, TOKEN_PARTIAL)) {
206
+ return NULL;
207
+ }
208
+
209
+ free_token(pop_token(tokens));
210
+
211
+ if (!is_token(*tokens, TOKEN_IDENTIFIER)) {
212
+ *error = create_error(*tokens, TOKEN_IDENTIFIER, "Expected identifier");
213
+ return NULL;
214
+ }
215
+
216
+ node = mustache_create_node();
217
+ node->type = NODE_PARTIAL;
218
+ node->token = pop_token(tokens);
219
+ node->execute = execute_partial;
220
+ node->optimize = optimize_partial;
221
+ return node;
222
+ }
223
+
224
+ mustache_node_t* build_comment(mustache_token_t** tokens, mustache_error_t** error)
225
+ {
226
+ mustache_node_t* node;
227
+
228
+ if (!is_token(*tokens, TOKEN_COMMENT)) {
229
+ return NULL;
230
+ }
231
+
232
+ node = mustache_create_node();
233
+ node->type = NODE_COMMENT;
234
+ node->token = pop_token(tokens);
235
+ node->execute = execute_comment;
236
+ node->optimize = optimize_comment;
237
+ return node;
238
+ }
239
+
240
+
241
+ /* Helper functions */
242
+
243
+ static void append_node(mustache_node_t* parent, mustache_node_t* src)
244
+ {
245
+ mustache_node_t* child = parent->first_child;
246
+
247
+ if (!child) {
248
+ parent->first_child = src;
249
+ }
250
+ else {
251
+ while (child->next_sibling) {
252
+ child = child->next_sibling;
253
+ }
254
+ child->next_sibling = src;
255
+ src->prv_sibling = child;
256
+ }
257
+
258
+ src->parent = parent;
259
+ }
260
+
261
+ static mustache_error_t* create_error(mustache_token_t* last_token, enum mustache_token_type expected_token, char* error_text)
262
+ {
263
+ mustache_error_t* error = mustache_malloc(sizeof(mustache_error_t));
264
+ error->last_token = last_token;
265
+ error->error_text = error_text;
266
+ return error;
267
+ }
@@ -0,0 +1,248 @@
1
+ #include "intern.h"
2
+
3
+ /* forward declare helper functions */
4
+ static bool html_encode(char* non_terminated_input, size_t length, mustache_context_t* ctx);
5
+ static mustache_value_t* get_variable_value(char* key, mustache_context_t* ctx);
6
+ static mustache_value_t* get_value(char* key, mustache_context_t* ctx);
7
+ bool is_whitespace(mustache_node_t* text_node);
8
+
9
+ bool execute_block(mustache_node_t* node, mustache_context_t* ctx)
10
+ {
11
+ mustache_node_t* child = node->first_child;
12
+
13
+ while (child) {
14
+ if (!child->execute(child, ctx)) {
15
+ return false;
16
+ }
17
+ child = child->next_sibling;
18
+ }
19
+ return true;
20
+ }
21
+
22
+ bool execute_text(mustache_node_t* node, mustache_context_t* ctx)
23
+ {
24
+ return mustache_write_to_buffer(ctx, node->token->text, strlen(node->token->text));
25
+ }
26
+
27
+ bool execute_newline(mustache_node_t* node, mustache_context_t* ctx)
28
+ {
29
+ if (!mustache_write_to_buffer(ctx, node->token->text, strlen(node->token->text))) {
30
+ return false;
31
+ }
32
+
33
+ if (*ctx->prefix && node->next_sibling) {
34
+ if (!mustache_write_to_buffer(ctx, ctx->prefix, strlen(ctx->prefix))) {
35
+ return false;
36
+ }
37
+ }
38
+
39
+ return true;
40
+ }
41
+
42
+ bool execute_raw_variable(mustache_node_t* node, mustache_context_t* ctx)
43
+ {
44
+ mustache_value_t* value = get_variable_value(node->token->text, ctx);
45
+ if (value) {
46
+ if (value->type == VALUE_VALUE) {
47
+ if (!mustache_write_to_buffer(ctx, value->data.value, value->length)) {
48
+ value->destroy(value);
49
+ return false;
50
+ }
51
+ }
52
+ value->destroy(value);
53
+ }
54
+
55
+ return true;
56
+ }
57
+
58
+ bool execute_variable(mustache_node_t* node, mustache_context_t* ctx)
59
+ {
60
+ mustache_value_t* value = get_variable_value(node->token->text, ctx);
61
+ if (value) {
62
+ if (value->type == VALUE_VALUE) {
63
+ if (!html_encode(value->data.value, value->length, ctx)) {
64
+ printf("html_encode failed\n");
65
+ value->destroy(value);
66
+ return false;
67
+ }
68
+ }
69
+ value->destroy(value);
70
+ }
71
+
72
+ return true;
73
+ }
74
+ size_t foo = 0;
75
+
76
+ bool execute_section(mustache_node_t* node, mustache_context_t* ctx)
77
+ {
78
+ mustache_value_t* value = get_variable_value(node->token->text, ctx);
79
+ mustache_context_t** list_contexts = NULL;
80
+ mustache_context_t* list_context = NULL;
81
+ bool response = true;
82
+
83
+ bool is_true;
84
+
85
+ // If the variable doesn't exist, don't execute the template
86
+ if (!value && node->type == NODE_SECTION) {
87
+ return true;
88
+ } else if (!value && node->type == NODE_INVERTED_SECTION) {
89
+ return node->first_child->execute(node->first_child, ctx);
90
+ }
91
+
92
+ switch (value->type) {
93
+ case VALUE_LIST:
94
+ list_contexts = value->data.list;
95
+
96
+ if (node->type == NODE_INVERTED_SECTION) {
97
+ if (value->length) {
98
+ return true;
99
+ } else {
100
+ return node->first_child->execute(node->first_child, ctx);
101
+ }
102
+ }
103
+
104
+ for (size_t i = 0; i < value->length; i++) {
105
+ list_context = list_contexts[i];
106
+ list_context->parent = ctx;
107
+ list_context->partials = ctx->partials;
108
+ list_context->get_partial = ctx->get_partial;
109
+ response = node->first_child->execute(node->first_child, list_context);
110
+
111
+ if (!response) {
112
+ break;
113
+ }
114
+ }
115
+
116
+ break;
117
+ case VALUE_OBJECT:
118
+ is_true = value->data.object != NULL;
119
+ if (is_true == (node->type == NODE_SECTION)) {
120
+ value->data.object->parent = ctx;
121
+ response = node->first_child->execute(node->first_child, value->data.object);
122
+ value->data.object->parent = NULL;
123
+ }
124
+ break;
125
+ case VALUE_VALUE:
126
+ is_true = value->length > 0;
127
+ if (is_true == (node->type == NODE_SECTION)) {
128
+ response = node->first_child->execute(node->first_child, ctx);
129
+ } else {
130
+ response = true;
131
+ }
132
+ break;
133
+ }
134
+
135
+ value->destroy(value);
136
+
137
+ if (!response) {
138
+ // TODO: truncate
139
+ }
140
+ return true;
141
+ }
142
+
143
+ bool execute_partial(mustache_node_t* node, mustache_context_t* ctx)
144
+ {
145
+ mustache_node_t* partial = ctx->get_partial(node->token->text, ctx->partials);
146
+
147
+ // add indentation
148
+ char* indentation = NULL;
149
+
150
+ if (node->prv_sibling &&
151
+ node->prv_sibling->type == NODE_TEXT &&
152
+ is_whitespace(node->prv_sibling) &&
153
+ (!node->prv_sibling->prv_sibling || node->prv_sibling->prv_sibling->type == NODE_NEWLINE)) {
154
+
155
+ // Save existing indentation, it will be replaced after partial execution
156
+ indentation = ctx->prefix;
157
+ size_t current_length = *ctx->prefix ? strlen(ctx->prefix) : 0;
158
+ size_t sibling_length = strlen(node->prv_sibling->token->text);
159
+
160
+ ctx->prefix = malloc(sizeof(char) * (current_length + sibling_length + 1));
161
+
162
+ if (current_length) {
163
+ strncpy(ctx->prefix, ctx->prefix, current_length);
164
+ }
165
+ strncpy(ctx->prefix + current_length, node->prv_sibling->token->text, sibling_length);
166
+ }
167
+
168
+ bool ret_val = true;
169
+ if (partial) {
170
+ ret_val = partial->execute(partial, ctx);
171
+ }
172
+
173
+ // restore indentation
174
+ if (indentation) {
175
+ free(ctx->prefix);
176
+ ctx->prefix = indentation;
177
+ }
178
+
179
+ return ret_val;
180
+ }
181
+
182
+ bool execute_comment(mustache_node_t* node, mustache_context_t* ctx)
183
+ {
184
+ return true;
185
+ }
186
+
187
+ /* helper functions */
188
+
189
+ static bool html_encode(
190
+ char* non_terminated_input,
191
+ size_t length,
192
+ mustache_context_t* ctx)
193
+ {
194
+ char current;
195
+ char* replacement;
196
+ size_t replacement_length;
197
+
198
+ for (int i = 0; i < length; i++) {
199
+ current = non_terminated_input[i];
200
+
201
+ switch (current) {
202
+ case '&': replacement = "&amp;"; replacement_length = 5; break;
203
+ case '"': replacement = "&quot;"; replacement_length = 6; break;
204
+ case '<': replacement = "&lt;"; replacement_length = 4; break;
205
+ case '>': replacement = "&gt;"; replacement_length = 4; break;
206
+ default:
207
+ replacement = &current;
208
+ replacement_length = 1;
209
+ break;
210
+ }
211
+
212
+ if (!mustache_write_to_buffer(ctx, replacement, replacement_length)) {
213
+ return false;
214
+ }
215
+ }
216
+
217
+ return true;
218
+ }
219
+
220
+ static mustache_value_t* get_variable_value(char* key, mustache_context_t* ctx)
221
+ {
222
+ // special case for implicit variables
223
+ if (key[0] == '.') {
224
+ return ctx->get_data(key, ctx->data, ctx, ctx);
225
+ }
226
+
227
+ char* context_identifier = strtok(key, ".");
228
+ mustache_value_t* result = NULL;
229
+ while (context_identifier) {
230
+ result = get_value(context_identifier, ctx);
231
+ if (result && result->type == VALUE_OBJECT) {
232
+ ctx = result->data.object;
233
+ }
234
+ context_identifier = strtok(NULL, ".");
235
+ }
236
+ return result;
237
+ }
238
+
239
+ static mustache_value_t* get_value(char* key, mustache_context_t* ctx)
240
+ {
241
+ mustache_value_t* value = ctx->get_data(key, ctx->data, ctx, ctx);
242
+ mustache_context_t* current_context = ctx;
243
+ while (!value && current_context->parent) {
244
+ current_context = current_context->parent;
245
+ value = current_context->get_data(key, current_context->data, current_context, ctx);
246
+ }
247
+ return value;
248
+ }