1 /**************************************************************************
3 * Copyright 2009 VMware, Inc.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
31 #include "sl_pp_purify.h"
35 * Preprocessor purifier performs the following tasks.
36 * - Convert all variants of newlines into a Unix newline.
37 * - Merge continued lines into a single long line.
38 * - Remove line comments and replace block comments with whitespace.
43 _purify_newline(const char *input
,
45 unsigned int *current_line
)
47 if (input
[0] == '\n') {
50 if (input
[1] == '\r') {
52 * The GLSL spec is not explicit about whether this
53 * combination is a valid newline or not.
54 * Let's assume it is acceptable.
60 if (input
[0] == '\r') {
63 if (input
[1] == '\n') {
74 _purify_backslash(const char *input
,
76 unsigned int *current_line
)
78 unsigned int eaten
= 0;
81 if (input
[0] == '\\') {
83 unsigned int next_eaten
;
84 unsigned int next_line
= *current_line
;
89 next_eaten
= _purify_newline(input
, &next
, &next_line
);
92 * If this is really a line continuation sequence, eat
93 * it and do not exit the loop.
97 *current_line
= next_line
;
100 * It is an error to put anything between a backslash
101 * and a newline and still expect it to behave like a line
102 * continuation sequence.
103 * Even if it is an innocent whitespace.
109 eaten
+= _purify_newline(input
, out
, current_line
);
118 _report_error(char *buf
,
126 vsnprintf(buf
, cbbuf
, msg
, args
);
132 sl_pp_purify_state_init(struct sl_pp_purify_state
*state
,
134 const struct sl_pp_purify_options
*options
)
136 state
->options
= *options
;
137 state
->input
= input
;
138 state
->current_line
= 1;
139 state
->inside_c_comment
= 0;
144 _purify_comment(struct sl_pp_purify_state
*state
,
146 unsigned int *current_line
,
148 unsigned int cberrormsg
)
154 eaten
= _purify_backslash(state
->input
, &next
, current_line
);
155 state
->input
+= eaten
;
156 while (next
== '*') {
157 eaten
= _purify_backslash(state
->input
, &next
, current_line
);
158 state
->input
+= eaten
;
161 state
->inside_c_comment
= 0;
167 state
->inside_c_comment
= 1;
171 _report_error(errormsg
, cberrormsg
, "expected `*/' but end of translation unit found");
179 sl_pp_purify_getc(struct sl_pp_purify_state
*state
,
181 unsigned int *current_line
,
183 unsigned int cberrormsg
)
187 if (state
->inside_c_comment
) {
188 return _purify_comment(state
, output
, current_line
, errormsg
, cberrormsg
);
191 eaten
= _purify_backslash(state
->input
, output
, current_line
);
192 state
->input
+= eaten
;
193 if (*output
== '/') {
195 unsigned int next_line
= *current_line
;
197 eaten
= _purify_backslash(state
->input
, &next
, &next_line
);
199 state
->input
+= eaten
;
200 *current_line
= next_line
;
202 /* Replace a line comment with either a newline or nil. */
204 eaten
= _purify_backslash(state
->input
, &next
, current_line
);
205 state
->input
+= eaten
;
206 if (next
== '\n' || next
== '\0') {
211 } else if (next
== '*') {
212 state
->input
+= eaten
;
213 *current_line
= next_line
;
215 return _purify_comment(state
, output
, current_line
, errormsg
, cberrormsg
);
225 unsigned int capacity
;
226 unsigned int current_line
;
228 unsigned int cberrormsg
;
233 _out_buf_putc(struct out_buf
*obuf
,
236 if (obuf
->len
>= obuf
->capacity
) {
237 unsigned int new_max
= obuf
->capacity
;
239 if (new_max
< 0x100) {
241 } else if (new_max
< 0x10000) {
247 obuf
->out
= realloc(obuf
->out
, new_max
);
249 _report_error(obuf
->errormsg
, obuf
->cberrormsg
, "out of memory");
252 obuf
->capacity
= new_max
;
255 obuf
->out
[obuf
->len
++] = c
;
262 sl_pp_purify(const char *input
,
263 const struct sl_pp_purify_options
*options
,
266 unsigned int cberrormsg
,
267 unsigned int *errorline
)
270 struct sl_pp_purify_state state
;
275 obuf
.current_line
= 1;
276 obuf
.errormsg
= errormsg
;
277 obuf
.cberrormsg
= cberrormsg
;
279 sl_pp_purify_state_init(&state
, input
, options
);
285 eaten
= sl_pp_purify_getc(&state
, &c
, &obuf
.current_line
, errormsg
, cberrormsg
);
287 *errorline
= obuf
.current_line
;
290 if (_out_buf_putc(&obuf
, c
)) {
291 *errorline
= obuf
.current_line
;