/src/CMake/Utilities/cmllpkgc/llpkgc_file.c
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. |
2 | | See accompanying file LICENSE.rst for details. */ |
3 | | |
4 | | #include <stdint.h> |
5 | | #include <stdlib.h> |
6 | | #include <string.h> |
7 | | |
8 | | #include "llpkgc_file.h" |
9 | | |
10 | | #define CALLBACK_MAYBE(PARSER, NAME) \ |
11 | 3.56k | do { \ |
12 | 3.56k | const llpkgc_file_settings_t* settings; \ |
13 | 3.56k | settings = \ |
14 | 3.56k | (const llpkgc_file_settings_t*) (PARSER)->llpkgc_file__settings; \ |
15 | 3.56k | if(settings == NULL || settings->NAME == NULL) { \ |
16 | 0 | err = 0; \ |
17 | 0 | break; \ |
18 | 0 | } \ |
19 | 3.56k | err = settings->NAME((PARSER)); \ |
20 | 3.56k | } while(0) |
21 | | |
22 | | #define SPAN_CALLBACK_MAYBE(PARSER, NAME, START, LEN) \ |
23 | 1.78k | do { \ |
24 | 1.78k | const llpkgc_file_settings_t* settings; \ |
25 | 1.78k | settings = \ |
26 | 1.78k | (const llpkgc_file_settings_t*) (PARSER)->llpkgc_file__settings; \ |
27 | 1.78k | if(settings == NULL || settings->NAME == NULL) { \ |
28 | 0 | err = 0; \ |
29 | 0 | break; \ |
30 | 0 | } \ |
31 | 1.78k | err = settings->NAME((PARSER), (START), (LEN)); \ |
32 | 1.78k | if(err == -1) { \ |
33 | 0 | err = PFCE_USER; \ |
34 | 0 | llpkgc_file_set_error_reason((PARSER), "Span callback error in " #NAME); \ |
35 | 0 | } \ |
36 | 1.78k | } while(0) |
37 | | |
38 | | enum llpkgc_file_unfinished_state { |
39 | | PFUS_NONE = 0, |
40 | | PFUS_IDENT = 1, |
41 | | PFUS_BAREWORDS = 2, |
42 | | PFUS_EXPECT_VALUE = 3, |
43 | | PFUS_VALUE = 4, |
44 | | PFUS_VALUE_LITERAL = 5, |
45 | | PFUS_VALUE_SUBSTITUTION = 6, |
46 | | }; |
47 | | |
48 | | void llpkgc_file_init(llpkgc_file_t* parser, |
49 | 1 | const llpkgc_file_settings_t* settings) { |
50 | 1 | llpkgc_file__internal_init(parser); |
51 | | |
52 | 1 | parser->llpkgc_file__settings = (void*) settings; |
53 | 1 | } |
54 | | |
55 | 0 | void llpkgc_file_reset(llpkgc_file_t* parser) { |
56 | 0 | llpkgc_file_settings_t* settings = parser->llpkgc_file__settings; |
57 | 0 | void* data = parser->data; |
58 | |
|
59 | 0 | llpkgc_file__internal_init(parser); |
60 | |
|
61 | 0 | parser->llpkgc_file__settings = settings; |
62 | 0 | parser->data = data; |
63 | 0 | } |
64 | | |
65 | 0 | void llpkgc_file_settings_init(llpkgc_file_settings_t* settings) { |
66 | 0 | memset(settings, 0, sizeof(*settings)); |
67 | 0 | } |
68 | | |
69 | | llpkgc_file_errno_t llpkgc_file_execute(llpkgc_file_t* parser, const char* data, |
70 | 1 | size_t len) { |
71 | 1 | return llpkgc_file__internal_execute(parser, data, data + len); |
72 | 1 | } |
73 | | |
74 | | int llpkgc_file__line_begin(llpkgc_file_t* s, const char* p, const char* endp); |
75 | | int llpkgc_file__ident_span(llpkgc_file_t* s, const char* p, const char* endp); |
76 | | |
77 | 1 | llpkgc_file_errno_t llpkgc_file_finish(llpkgc_file_t* parser) { |
78 | 1 | int err = PFCE_OK; |
79 | | |
80 | 1 | if(parser->error == PFCE_LOOKAHEAD) { |
81 | 0 | if(parser->error_pos == NULL) { |
82 | 0 | parser->error = PFCE_INTERNAL; |
83 | 0 | parser->reason = "Missing lookahead error position"; |
84 | 0 | return parser->error; |
85 | 0 | } |
86 | | |
87 | 0 | parser->llpkgc_file__eof = 1; |
88 | 0 | llpkgc_file_resume(parser); |
89 | 0 | err = llpkgc_file_execute(parser, parser->error_pos, 1); |
90 | 0 | parser->llpkgc_file__eof = 0; |
91 | |
|
92 | 0 | if(err != PFCE_OK) { |
93 | 0 | return err; |
94 | 0 | } |
95 | | |
96 | 0 | parser->llpkgc_file__lookahead = 0; |
97 | 1 | } else if(parser->error != 0) { |
98 | 1 | return parser->error; |
99 | 1 | } |
100 | | |
101 | 0 | switch(parser->llpkgc_file__unfinished) { |
102 | 0 | case PFUS_IDENT: |
103 | 0 | case PFUS_BAREWORDS: |
104 | 0 | CALLBACK_MAYBE(parser, on_barewords_complete); |
105 | 0 | if(err != PFCE_OK) { |
106 | 0 | parser->error = err; |
107 | 0 | return err; |
108 | 0 | } |
109 | | |
110 | 0 | CALLBACK_MAYBE(parser, on_value_complete); |
111 | 0 | if(err != PFCE_OK) { |
112 | 0 | parser->error = err; |
113 | 0 | return err; |
114 | 0 | } |
115 | 0 | break; |
116 | | |
117 | 0 | case PFUS_EXPECT_VALUE: |
118 | 0 | case PFUS_VALUE: |
119 | 0 | CALLBACK_MAYBE(parser, on_value_complete); |
120 | 0 | if(err != PFCE_OK) { |
121 | 0 | parser->error = err; |
122 | 0 | return err; |
123 | 0 | } |
124 | 0 | break; |
125 | | |
126 | 0 | case PFUS_VALUE_LITERAL: |
127 | 0 | CALLBACK_MAYBE(parser, on_value_literal_complete); |
128 | 0 | if(err != PFCE_OK) { |
129 | 0 | parser->error = err; |
130 | 0 | return err; |
131 | 0 | } |
132 | | |
133 | 0 | CALLBACK_MAYBE(parser, on_value_complete); |
134 | 0 | if(err != PFCE_OK) { |
135 | 0 | parser->error = err; |
136 | 0 | return err; |
137 | 0 | } |
138 | 0 | break; |
139 | | |
140 | 0 | case PFUS_VALUE_SUBSTITUTION: |
141 | 0 | parser->reason = "Invalid EOF state"; |
142 | 0 | parser->error = PFCE_UNFINISHED; |
143 | 0 | return PFCE_UNFINISHED; |
144 | | |
145 | 0 | case PFUS_NONE: |
146 | 0 | break; |
147 | 0 | } |
148 | | |
149 | 0 | CALLBACK_MAYBE(parser, on_pkgc_complete); |
150 | 0 | return err; |
151 | 0 | } |
152 | | |
153 | 0 | void llpkgc_file_pause(llpkgc_file_t* parser) { |
154 | 0 | if(parser->error != PFCE_OK) { |
155 | 0 | return; |
156 | 0 | } |
157 | | |
158 | 0 | parser->error = PFCE_PAUSED; |
159 | 0 | parser->reason = "Paused"; |
160 | 0 | } |
161 | | |
162 | 0 | void llpkgc_file_resume(llpkgc_file_t* parser) { |
163 | 0 | if(parser->error != PFCE_PAUSED && parser->error != PFCE_LOOKAHEAD) { |
164 | 0 | return; |
165 | 0 | } |
166 | | |
167 | 0 | parser->error = 0; |
168 | 0 | } |
169 | | |
170 | 0 | llpkgc_file_errno_t llpkgc_file_get_errno(const llpkgc_file_t* parser) { |
171 | 0 | return parser->error; |
172 | 0 | } |
173 | | |
174 | 0 | const char* llpkgc_file_get_error_reason(const llpkgc_file_t* parser) { |
175 | 0 | return parser->reason; |
176 | 0 | } |
177 | | |
178 | 0 | void llpkgc_file_set_error_reason(llpkgc_file_t* parser, const char* reason) { |
179 | 0 | parser->reason = reason; |
180 | 0 | } |
181 | | |
182 | 0 | const char* llpkgc_file_get_error_pos(const llpkgc_file_t* parser) { |
183 | 0 | return parser->error_pos; |
184 | 0 | } |
185 | | |
186 | 0 | const char* llpkgc_file_errno_name(llpkgc_file_errno_t err) { |
187 | 0 | switch(err) { |
188 | 0 | case PFCE_OK: |
189 | 0 | return "PFCE_OK"; |
190 | 0 | case PFCE_INTERNAL: |
191 | 0 | return "PFCE_INTERNAL"; |
192 | 0 | case PFCE_PAUSED: |
193 | 0 | return "PFCE_PAUSED"; |
194 | 0 | case PFCE_USER: |
195 | 0 | return "PFCE_USER"; |
196 | 0 | case PFCE_UNFINISHED: |
197 | 0 | return "PFCE_UNFINISHED"; |
198 | 0 | case PFCE_LOOKAHEAD: |
199 | 0 | return "PFCE_LOOKAHEAD"; |
200 | 0 | } |
201 | 0 | return "INVALID_ERRNO"; |
202 | 0 | } |
203 | | |
204 | 0 | int llpkgc_file__lookahead(llpkgc_file_t* s, const char* p, const char* endp) { |
205 | 0 | if(p == endp) { |
206 | 0 | llpkgc_file_set_error_reason(s, "Invalid lookahead state"); |
207 | 0 | return PFCE_INTERNAL; |
208 | 0 | } |
209 | | |
210 | 0 | if(p + 1 == endp) { |
211 | 0 | if(s->llpkgc_file__eof != 0) { |
212 | 0 | s->llpkgc_file__lookahead = 0; |
213 | 0 | return 3; |
214 | 0 | } |
215 | | |
216 | 0 | s->llpkgc_file__lookahead = (uint8_t) *p; |
217 | 0 | return PFCE_LOOKAHEAD; |
218 | 0 | } |
219 | | |
220 | 0 | s->llpkgc_file__lookahead = 0; |
221 | |
|
222 | 0 | if(*p != '$') { |
223 | 0 | llpkgc_file_set_error_reason(s, "Invalid lookahead state"); |
224 | 0 | return PFCE_INTERNAL; |
225 | 0 | } |
226 | | |
227 | 0 | switch(p[1]) { |
228 | 0 | case '{': |
229 | 0 | return 1; |
230 | 0 | case '$': |
231 | 0 | return 2; |
232 | 0 | default: |
233 | 0 | return 0; |
234 | 0 | } |
235 | 0 | } |
236 | | |
237 | | int llpkgc_file__lookahead_backslash(llpkgc_file_t* s, const char* p, |
238 | 6 | const char* endp) { |
239 | 6 | if(p == endp) { |
240 | 0 | llpkgc_file_set_error_reason(s, "Invalid lookahead state"); |
241 | 0 | return PFCE_INTERNAL; |
242 | 0 | } |
243 | | |
244 | 6 | if(p + 1 == endp) { |
245 | 0 | if(s->llpkgc_file__eof != 0) { |
246 | 0 | s->llpkgc_file__lookahead = 0; |
247 | 0 | return 4; |
248 | 0 | } |
249 | | |
250 | 0 | s->llpkgc_file__lookahead = (uint8_t) *p; |
251 | 0 | return 5; |
252 | 0 | } |
253 | | |
254 | 6 | s->llpkgc_file__lookahead = 0; |
255 | | |
256 | 6 | if(*p != '\\') { |
257 | 0 | llpkgc_file_set_error_reason(s, "Invalid lookahead state"); |
258 | 0 | return PFCE_INTERNAL; |
259 | 0 | } |
260 | | |
261 | 6 | switch(p[1]) { |
262 | 0 | case '\r': |
263 | 0 | case '\n': |
264 | 0 | return 1; |
265 | 3 | case '#': |
266 | 3 | return 2; |
267 | 1 | case '\\': |
268 | 1 | return 3; |
269 | 2 | default: |
270 | 2 | return 0; |
271 | 6 | } |
272 | 6 | } |
273 | | |
274 | 0 | int llpkgc_file__line_begin(llpkgc_file_t* s, const char* p, const char* endp) { |
275 | 0 | int err; |
276 | 0 | CALLBACK_MAYBE(s, on_line_begin); |
277 | 0 | return err; |
278 | 0 | } |
279 | | |
280 | 1.77k | int llpkgc_file__ident_span(llpkgc_file_t* s, const char* p, const char* endp) { |
281 | 1.77k | int err; |
282 | 1.77k | SPAN_CALLBACK_MAYBE(s, on_ident, p, endp - p); |
283 | 1.77k | return err; |
284 | 1.77k | } |
285 | | |
286 | | int llpkgc_file__prop_decl_complete(llpkgc_file_t* s, const char* p, |
287 | 4 | const char* endp) { |
288 | 4 | int err; |
289 | 4 | CALLBACK_MAYBE(s, on_property_complete); |
290 | 4 | return err; |
291 | 4 | } |
292 | | |
293 | | int llpkgc_file__var_decl_complete(llpkgc_file_t* s, const char* p, |
294 | 0 | const char* endp) { |
295 | 0 | int err; |
296 | 0 | CALLBACK_MAYBE(s, on_variable_complete); |
297 | 0 | return err; |
298 | 0 | } |
299 | | |
300 | | int llpkgc_file__barewords_decl_complete(llpkgc_file_t* s, const char* p, |
301 | 1.77k | const char* endp) { |
302 | 1.77k | int err; |
303 | 1.77k | CALLBACK_MAYBE(s, on_barewords_complete); |
304 | 1.77k | return err; |
305 | 1.77k | } |
306 | | |
307 | 6 | int llpkgc_file__lit_span(llpkgc_file_t* s, const char* p, const char* endp) { |
308 | 6 | int err; |
309 | 6 | SPAN_CALLBACK_MAYBE(s, on_value_literal, p, endp - p); |
310 | 6 | return err; |
311 | 6 | } |
312 | | |
313 | | int llpkgc_file__lit_complete(llpkgc_file_t* s, const char* p, |
314 | 6 | const char* endp) { |
315 | 6 | int err; |
316 | 6 | CALLBACK_MAYBE(s, on_value_literal_complete); |
317 | 6 | return err; |
318 | 6 | } |
319 | | |
320 | 0 | int llpkgc_file__sub_span(llpkgc_file_t* s, const char* p, const char* endp) { |
321 | 0 | int err; |
322 | 0 | SPAN_CALLBACK_MAYBE(s, on_value_substitution, p, endp - p); |
323 | 0 | return err; |
324 | 0 | } |
325 | | |
326 | | int llpkgc_file__sub_complete(llpkgc_file_t* s, const char* p, |
327 | 0 | const char* endp) { |
328 | 0 | int err; |
329 | 0 | CALLBACK_MAYBE(s, on_value_substitution_complete); |
330 | 0 | return err; |
331 | 0 | } |
332 | | |
333 | | int llpkgc_file__val_complete(llpkgc_file_t* s, const char* p, |
334 | 1.77k | const char* endp) { |
335 | 1.77k | int err; |
336 | | CALLBACK_MAYBE(s, on_value_complete); |
337 | 1.77k | return err; |
338 | 1.77k | } |