glsl/pp: Add asserts to check for null pointer deferences.
[mesa.git] / src / glsl / pp / sl_pp_process.c
1 /**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include "sl_pp_context.h"
31 #include "sl_pp_process.h"
32 #include "sl_pp_public.h"
33
34
35 int
36 sl_pp_process_out(struct sl_pp_process_state *state,
37 const struct sl_pp_token_info *token)
38 {
39 if (state->out_len >= state->out_max) {
40 unsigned int new_max = state->out_max;
41
42 if (new_max < 0x100) {
43 new_max = 0x100;
44 } else if (new_max < 0x10000) {
45 new_max *= 2;
46 } else {
47 new_max += 0x10000;
48 }
49
50 state->out = realloc(state->out, new_max * sizeof(struct sl_pp_token_info));
51 if (!state->out) {
52 return -1;
53 }
54 state->out_max = new_max;
55 }
56
57 state->out[state->out_len++] = *token;
58 return 0;
59 }
60
61 int
62 sl_pp_process_get(struct sl_pp_context *context,
63 struct sl_pp_token_info *output)
64 {
65 if (!context->process_state.out) {
66 if (context->line > 1) {
67 struct sl_pp_token_info ti;
68
69 ti.token = SL_PP_LINE;
70 ti.data.line.lineno = context->line - 1;
71 ti.data.line.fileno = context->file;
72 if (sl_pp_process_out(&context->process_state, &ti)) {
73 strcpy(context->error_msg, "out of memory");
74 return -1;
75 }
76
77 ti.token = SL_PP_NEWLINE;
78 if (sl_pp_process_out(&context->process_state, &ti)) {
79 strcpy(context->error_msg, "out of memory");
80 return -1;
81 }
82 }
83 }
84
85 for (;;) {
86 struct sl_pp_token_info input;
87 int found_eof = 0;
88
89 if (context->process_state.out_len) {
90 assert(context->process_state.out);
91 *output = context->process_state.out[0];
92
93 if (context->process_state.out_len > 1) {
94 unsigned int i;
95
96 for (i = 1; i < context->process_state.out_len; i++) {
97 context->process_state.out[i - 1] = context->process_state.out[i];
98 }
99 }
100 context->process_state.out_len--;
101
102 return 0;
103 }
104
105 if (sl_pp_token_buffer_skip_white(&context->tokens, &input)) {
106 return -1;
107 }
108 if (input.token == SL_PP_HASH) {
109 if (sl_pp_token_buffer_skip_white(&context->tokens, &input)) {
110 return -1;
111 }
112 switch (input.token) {
113 case SL_PP_IDENTIFIER:
114 {
115 int name;
116 int found_eol = 0;
117 struct sl_pp_token_info endof;
118 struct sl_pp_token_peek peek;
119 int result = 0;
120
121 /* Directive name. */
122 name = input.data.identifier;
123
124 if (sl_pp_token_buffer_skip_white(&context->tokens, &input)) {
125 return -1;
126 }
127 sl_pp_token_buffer_unget(&context->tokens, &input);
128
129 if (sl_pp_token_peek_init(&peek, &context->tokens)) {
130 return -1;
131 }
132
133 while (!found_eol) {
134 if (sl_pp_token_peek_get(&peek, &input)) {
135 sl_pp_token_peek_destroy(&peek);
136 return -1;
137 }
138 switch (input.token) {
139 case SL_PP_NEWLINE:
140 /* Preserve newline just for the sake of line numbering. */
141 endof = input;
142 found_eol = 1;
143 break;
144
145 case SL_PP_EOF:
146 endof = input;
147 found_eof = 1;
148 found_eol = 1;
149 break;
150
151 default:
152 break;
153 }
154 }
155
156 if (name == context->dict._if) {
157 struct sl_pp_token_buffer buffer;
158
159 result = sl_pp_token_peek_to_buffer(&peek, &buffer);
160 if (result == 0) {
161 result = sl_pp_process_if(context, &buffer);
162 sl_pp_token_buffer_destroy(&buffer);
163 }
164 } else if (name == context->dict.ifdef) {
165 result = sl_pp_process_ifdef(context, peek.tokens, 0, peek.size - 1);
166 } else if (name == context->dict.ifndef) {
167 result = sl_pp_process_ifndef(context, peek.tokens, 0, peek.size - 1);
168 } else if (name == context->dict.elif) {
169 struct sl_pp_token_buffer buffer;
170
171 result = sl_pp_token_peek_to_buffer(&peek, &buffer);
172 if (result == 0) {
173 result = sl_pp_process_elif(context, &buffer);
174 sl_pp_token_buffer_destroy(&buffer);
175 }
176 } else if (name == context->dict._else) {
177 result = sl_pp_process_else(context, peek.tokens, 0, peek.size - 1);
178 } else if (name == context->dict.endif) {
179 result = sl_pp_process_endif(context, peek.tokens, 0, peek.size - 1);
180 } else if (context->if_value) {
181 if (name == context->dict.define) {
182 result = sl_pp_process_define(context, peek.tokens, 0, peek.size - 1);
183 } else if (name == context->dict.error) {
184 sl_pp_process_error(context, peek.tokens, 0, peek.size - 1);
185 result = -1;
186 } else if (name == context->dict.extension) {
187 result = sl_pp_process_extension(context, peek.tokens, 0, peek.size - 1, &context->process_state);
188 } else if (name == context->dict.line) {
189 struct sl_pp_token_buffer buffer;
190
191 result = sl_pp_token_peek_to_buffer(&peek, &buffer);
192 if (result == 0) {
193 result = sl_pp_process_line(context, &buffer, &context->process_state);
194 sl_pp_token_buffer_destroy(&buffer);
195 }
196 } else if (name == context->dict.pragma) {
197 result = sl_pp_process_pragma(context, peek.tokens, 0, peek.size - 1, &context->process_state);
198 } else if (name == context->dict.undef) {
199 result = sl_pp_process_undef(context, peek.tokens, 0, peek.size - 1);
200 } else {
201 strcpy(context->error_msg, "unrecognised directive name");
202 result = -1;
203 }
204 }
205
206 sl_pp_token_peek_commit(&peek);
207 sl_pp_token_peek_destroy(&peek);
208
209 if (result) {
210 return result;
211 }
212
213 if (sl_pp_process_out(&context->process_state, &endof)) {
214 strcpy(context->error_msg, "out of memory");
215 return -1;
216 }
217 context->line++;
218 }
219 break;
220
221 case SL_PP_NEWLINE:
222 /* Empty directive. */
223 if (sl_pp_process_out(&context->process_state, &input)) {
224 strcpy(context->error_msg, "out of memory");
225 return -1;
226 }
227 context->line++;
228 break;
229
230 case SL_PP_EOF:
231 /* Empty directive. */
232 if (sl_pp_process_out(&context->process_state, &input)) {
233 strcpy(context->error_msg, "out of memory");
234 return -1;
235 }
236 found_eof = 1;
237 break;
238
239 default:
240 strcpy(context->error_msg, "expected a directive name");
241 return -1;
242 }
243 } else {
244 int found_eol = 0;
245
246 sl_pp_token_buffer_unget(&context->tokens, &input);
247
248 while (!found_eol) {
249 if (sl_pp_token_buffer_get(&context->tokens, &input)) {
250 return -1;
251 }
252
253 switch (input.token) {
254 case SL_PP_WHITESPACE:
255 /* Drop whitespace all together at this point. */
256 break;
257
258 case SL_PP_NEWLINE:
259 /* Preserve newline just for the sake of line numbering. */
260 if (sl_pp_process_out(&context->process_state, &input)) {
261 strcpy(context->error_msg, "out of memory");
262 return -1;
263 }
264 context->line++;
265 found_eol = 1;
266 break;
267
268 case SL_PP_EOF:
269 if (sl_pp_process_out(&context->process_state, &input)) {
270 strcpy(context->error_msg, "out of memory");
271 return -1;
272 }
273 found_eof = 1;
274 found_eol = 1;
275 break;
276
277 case SL_PP_IDENTIFIER:
278 sl_pp_token_buffer_unget(&context->tokens, &input);
279 if (sl_pp_macro_expand(context, &context->tokens, NULL, &context->process_state,
280 context->if_value ? sl_pp_macro_expand_normal : sl_pp_macro_expand_mute)) {
281 return -1;
282 }
283 break;
284
285 default:
286 if (context->if_value) {
287 if (sl_pp_process_out(&context->process_state, &input)) {
288 strcpy(context->error_msg, "out of memory");
289 return -1;
290 }
291 }
292 }
293 }
294 }
295
296 if (found_eof) {
297 if (context->if_ptr != SL_PP_MAX_IF_NESTING) {
298 strcpy(context->error_msg, "expected `#endif' directive");
299 return -1;
300 }
301 }
302 }
303 }
304
305 int
306 sl_pp_process(struct sl_pp_context *context,
307 struct sl_pp_token_info **output)
308 {
309 struct sl_pp_process_state state;
310
311 memset(&state, 0, sizeof(state));
312 for (;;) {
313 struct sl_pp_token_info input;
314
315 if (sl_pp_process_get(context, &input)) {
316 free(state.out);
317 return -1;
318 }
319 if (sl_pp_process_out(&state, &input)) {
320 free(state.out);
321 return -1;
322 }
323 if (input.token == SL_PP_EOF) {
324 *output = state.out;
325 return 0;
326 }
327 }
328 }