/src/CMake/Utilities/cmllpkgc/llpkgc_frag.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_frag.h" |
9 | | |
10 | | #define CALLBACK_MAYBE(PARSER, NAME) \ |
11 | 0 | do { \ |
12 | 0 | const llpkgc_frag_settings_t* settings; \ |
13 | 0 | settings = \ |
14 | 0 | (const llpkgc_frag_settings_t*) (PARSER)->llpkgc_frag__settings; \ |
15 | 0 | if(settings == NULL || settings->NAME == NULL) { \ |
16 | 0 | err = 0; \ |
17 | 0 | break; \ |
18 | 0 | } \ |
19 | 0 | err = settings->NAME((PARSER)); \ |
20 | 0 | } while(0) |
21 | | |
22 | | #define SPAN_CALLBACK_MAYBE(PARSER, NAME, START, LEN) \ |
23 | 0 | do { \ |
24 | 0 | const llpkgc_frag_settings_t* settings; \ |
25 | 0 | settings = \ |
26 | 0 | (const llpkgc_frag_settings_t*) (PARSER)->llpkgc_frag__settings; \ |
27 | 0 | if(settings == NULL || settings->NAME == NULL) { \ |
28 | 0 | err = 0; \ |
29 | 0 | break; \ |
30 | 0 | } \ |
31 | 0 | err = settings->NAME((PARSER), (START), (LEN)); \ |
32 | 0 | if(err == -1) { \ |
33 | 0 | err = PFFE_USER; \ |
34 | 0 | llpkgc_frag_set_error_reason((PARSER), "Span callback error in " #NAME); \ |
35 | 0 | } \ |
36 | 0 | } while(0) |
37 | | |
38 | | enum llpkgc_frag_state { |
39 | | PFFS_START = 0, |
40 | | PFFS_UNQUOTED = 1, |
41 | | PFFS_DOUBLE_QUOTED = 2, |
42 | | PFFS_SINGLE_QUOTED = 3, |
43 | | }; |
44 | | |
45 | | void llpkgc_frag_init(llpkgc_frag_t* parser, |
46 | 0 | const llpkgc_frag_settings_t* settings) { |
47 | 0 | llpkgc_frag__internal_init(parser); |
48 | 0 | parser->llpkgc_frag__settings = (void*) settings; |
49 | 0 | } |
50 | | |
51 | 0 | void llpkgc_frag_reset(llpkgc_frag_t* parser) { |
52 | 0 | llpkgc_frag_settings_t* settings = parser->llpkgc_frag__settings; |
53 | 0 | void* data = parser->data; |
54 | 0 | llpkgc_frag__internal_init(parser); |
55 | 0 | parser->llpkgc_frag__settings = settings; |
56 | 0 | parser->data = data; |
57 | 0 | } |
58 | | |
59 | 0 | void llpkgc_frag_settings_init(llpkgc_frag_settings_t* settings) { |
60 | 0 | memset(settings, 0, sizeof(*settings)); |
61 | 0 | } |
62 | | |
63 | | llpkgc_frag_errno_t llpkgc_frag_execute(llpkgc_frag_t* parser, const char* data, |
64 | 0 | size_t len) { |
65 | 0 | return llpkgc_frag__internal_execute(parser, data, data + len); |
66 | 0 | } |
67 | | |
68 | 0 | llpkgc_frag_errno_t llpkgc_frag_finish(llpkgc_frag_t* parser) { |
69 | 0 | int err = PFFE_OK; |
70 | |
|
71 | 0 | if(parser->error == PFFE_LOOKAHEAD) { |
72 | 0 | if(parser->error_pos == NULL) { |
73 | 0 | parser->error = PFFE_INTERNAL; |
74 | 0 | parser->reason = "Missing lookahead error position"; |
75 | 0 | return parser->error; |
76 | 0 | } |
77 | | |
78 | 0 | parser->llpkgc_frag__eof = 1; |
79 | 0 | llpkgc_frag_resume(parser); |
80 | 0 | err = llpkgc_frag_execute(parser, parser->error_pos, 1); |
81 | 0 | parser->llpkgc_frag__eof = 0; |
82 | |
|
83 | 0 | if(err != PFFE_OK) { |
84 | 0 | return err; |
85 | 0 | } |
86 | | |
87 | 0 | parser->llpkgc_frag__lookahead = 0; |
88 | 0 | } else if(parser->error != 0) { |
89 | 0 | return parser->error; |
90 | 0 | } |
91 | | |
92 | 0 | switch(parser->llpkgc_frag__state) { |
93 | 0 | case PFFS_UNQUOTED: |
94 | 0 | CALLBACK_MAYBE(parser, on_frag_complete); |
95 | 0 | if(err != PFFE_OK) { |
96 | 0 | parser->error = err; |
97 | 0 | return err; |
98 | 0 | } |
99 | 0 | break; |
100 | | |
101 | 0 | case PFFS_DOUBLE_QUOTED: |
102 | 0 | case PFFS_SINGLE_QUOTED: |
103 | 0 | parser->reason = "Unterminated quote at end of input"; |
104 | 0 | parser->error = PFFE_UNFINISHED; |
105 | 0 | return PFFE_UNFINISHED; |
106 | | |
107 | 0 | case PFFS_START: |
108 | 0 | break; |
109 | 0 | } |
110 | | |
111 | 0 | CALLBACK_MAYBE(parser, on_fraglist_complete); |
112 | 0 | if(err != PFFE_OK) { |
113 | 0 | parser->error = err; |
114 | 0 | return err; |
115 | 0 | } |
116 | | |
117 | 0 | return PFFE_OK; |
118 | 0 | } |
119 | | |
120 | 0 | void llpkgc_frag_pause(llpkgc_frag_t* parser) { |
121 | 0 | if(parser->error != PFFE_OK) { |
122 | 0 | return; |
123 | 0 | } |
124 | 0 | parser->error = PFFE_PAUSED; |
125 | 0 | parser->reason = "Paused"; |
126 | 0 | } |
127 | | |
128 | 0 | void llpkgc_frag_resume(llpkgc_frag_t* parser) { |
129 | 0 | if(parser->error != PFFE_PAUSED && parser->error != PFFE_LOOKAHEAD) { |
130 | 0 | return; |
131 | 0 | } |
132 | 0 | parser->error = 0; |
133 | 0 | } |
134 | | |
135 | 0 | llpkgc_frag_errno_t llpkgc_frag_get_errno(const llpkgc_frag_t* parser) { |
136 | 0 | return parser->error; |
137 | 0 | } |
138 | | |
139 | 0 | const char* llpkgc_frag_get_error_reason(const llpkgc_frag_t* parser) { |
140 | 0 | return parser->reason; |
141 | 0 | } |
142 | | |
143 | 0 | void llpkgc_frag_set_error_reason(llpkgc_frag_t* parser, const char* reason) { |
144 | 0 | parser->reason = reason; |
145 | 0 | } |
146 | | |
147 | 0 | const char* llpkgc_frag_get_error_pos(const llpkgc_frag_t* parser) { |
148 | 0 | return parser->error_pos; |
149 | 0 | } |
150 | | |
151 | 0 | const char* llpkgc_frag_errno_name(llpkgc_frag_errno_t err) { |
152 | 0 | switch(err) { |
153 | 0 | case PFFE_OK: |
154 | 0 | return "PFFE_OK"; |
155 | 0 | case PFFE_INTERNAL: |
156 | 0 | return "PFFE_INTERNAL"; |
157 | 0 | case PFFE_PAUSED: |
158 | 0 | return "PFFE_PAUSED"; |
159 | 0 | case PFFE_USER: |
160 | 0 | return "PFFE_USER"; |
161 | 0 | case PFFE_UNFINISHED: |
162 | 0 | return "PFFE_UNFINISHED"; |
163 | 0 | case PFFE_LOOKAHEAD: |
164 | 0 | return "PFFE_LOOKAHEAD"; |
165 | 0 | } |
166 | 0 | return "INVALID_ERRNO"; |
167 | 0 | } |
168 | | |
169 | | int llpkgc_frag__lookahead_dq_backslash(llpkgc_frag_t* s, const char* p, |
170 | 0 | const char* endp) { |
171 | 0 | if(p == endp) { |
172 | 0 | llpkgc_frag_set_error_reason(s, "Invalid lookahead state"); |
173 | 0 | return PFFE_INTERNAL; |
174 | 0 | } |
175 | | |
176 | 0 | if(p + 1 == endp) { |
177 | 0 | if(s->llpkgc_frag__eof != 0) { |
178 | 0 | s->llpkgc_frag__lookahead = 0; |
179 | 0 | return 1; |
180 | 0 | } |
181 | 0 | s->llpkgc_frag__lookahead = (uint8_t) *p; |
182 | 0 | return PFFE_LOOKAHEAD; |
183 | 0 | } |
184 | | |
185 | 0 | s->llpkgc_frag__lookahead = 0; |
186 | |
|
187 | 0 | if(*p != '\\') { |
188 | 0 | llpkgc_frag_set_error_reason(s, "Invalid lookahead state"); |
189 | 0 | return PFFE_INTERNAL; |
190 | 0 | } |
191 | | |
192 | 0 | switch(p[1]) { |
193 | 0 | case '$': |
194 | 0 | case '`': |
195 | 0 | case '"': |
196 | 0 | case '\\': |
197 | 0 | return 0; |
198 | 0 | default: |
199 | 0 | return 1; |
200 | 0 | } |
201 | 0 | } |
202 | | |
203 | | int llpkgc_frag__fragment_text(llpkgc_frag_t* s, const char* p, |
204 | 0 | const char* endp) { |
205 | 0 | int err; |
206 | 0 | SPAN_CALLBACK_MAYBE(s, on_fragment_text, p, endp - p); |
207 | 0 | return err; |
208 | 0 | } |
209 | | |
210 | | int llpkgc_frag__frag_complete(llpkgc_frag_t* s, const char* p, |
211 | 0 | const char* endp) { |
212 | 0 | int err; |
213 | | CALLBACK_MAYBE(s, on_frag_complete); |
214 | 0 | return err; |
215 | 0 | } |