2 * Copyright © 2010 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
30 glcpp_error (YYLTYPE
*locp
, glcpp_parser_t
*parser
, const char *fmt
, ...)
35 ralloc_asprintf_rewrite_tail(&parser
->info_log
,
36 &parser
->info_log_length
,
38 "preprocessor error: ",
43 ralloc_vasprintf_rewrite_tail(&parser
->info_log
,
44 &parser
->info_log_length
,
47 ralloc_asprintf_rewrite_tail(&parser
->info_log
,
48 &parser
->info_log_length
, "\n");
52 glcpp_warning (YYLTYPE
*locp
, glcpp_parser_t
*parser
, const char *fmt
, ...)
56 ralloc_asprintf_rewrite_tail(&parser
->info_log
,
57 &parser
->info_log_length
,
59 "preprocessor warning: ",
64 ralloc_vasprintf_rewrite_tail(&parser
->info_log
,
65 &parser
->info_log_length
,
68 ralloc_asprintf_rewrite_tail(&parser
->info_log
,
69 &parser
->info_log_length
, "\n");
72 /* Given str, (that's expected to start with a newline terminator of some
73 * sort), return a pointer to the first character in str after the newline.
75 * A newline terminator can be any of the following sequences:
82 * And the longest such sequence will be skipped.
85 skip_newline (const char *str
)
87 const char *ret
= str
;
97 if (*ret
&& *ret
== '\n')
99 } else if (*ret
== '\n') {
101 if (*ret
&& *ret
== '\r')
108 /* Remove any line continuation characters in the shader, (whether in
109 * preprocessing directives or in GLSL code).
112 remove_line_continuations(glcpp_parser_t
*ctx
, const char *shader
)
114 char *clean
= ralloc_strdup(ctx
, "");
115 const char *backslash
, *newline
, *search_start
;
117 char newline_separator
[3];
118 int collapsed_newlines
= 0;
120 search_start
= shader
;
122 /* Determine what flavor of newlines this shader is using. GLSL
123 * provides for 4 different possible ways to separate lines, (using
124 * one or two characters):
126 * "\n" (line-feed, like Linux, Unix, and new Mac OS)
127 * "\r" (carriage-return, like old Mac files)
128 * "\r\n" (carriage-return + line-feed, like DOS files)
129 * "\n\r" (line-feed + carriage-return, like nothing, really)
131 * This code explicitly supports a shader that uses a mixture of
132 * newline terminators and will properly handle line continuation
133 * backslashes followed by any of the above.
135 * But, since we must also insert additional newlines in the output
136 * (for any collapsed lines) we attempt to maintain consistency by
137 * examining the first encountered newline terminator, and using the
138 * same terminator for any newlines we insert.
140 cr
= strchr(search_start
, '\r');
141 lf
= strchr(search_start
, '\n');
143 newline_separator
[0] = '\n';
144 newline_separator
[1] = '\0';
145 newline_separator
[2] = '\0';
149 } else if (lf
== NULL
) {
150 newline_separator
[0] = '\r';
151 } else if (lf
== cr
+ 1) {
152 newline_separator
[0] = '\r';
153 newline_separator
[1] = '\n';
154 } else if (cr
== lf
+ 1) {
155 newline_separator
[0] = '\n';
156 newline_separator
[1] = '\r';
160 backslash
= strchr(search_start
, '\\');
162 /* If we have previously collapsed any line-continuations,
163 * then we want to insert additional newlines at the next
164 * occurrence of a newline character to avoid changing any
167 if (collapsed_newlines
) {
168 cr
= strchr (search_start
, '\r');
169 lf
= strchr (search_start
, '\n');
171 newline
= cr
< lf
? cr
: lf
;
177 (backslash
== NULL
|| newline
< backslash
))
179 ralloc_strncat(&clean
, shader
,
180 newline
- shader
+ 1);
181 while (collapsed_newlines
) {
182 ralloc_strcat(&clean
, newline_separator
);
183 collapsed_newlines
--;
185 shader
= skip_newline (newline
);
186 search_start
= shader
;
190 search_start
= backslash
+ 1;
192 if (backslash
== NULL
)
195 /* At each line continuation, (backslash followed by a
196 * newline), copy all preceding text to the output, then
197 * advance the shader pointer to the character after the
200 if (backslash
[1] == '\r' || backslash
[1] == '\n')
202 collapsed_newlines
++;
203 ralloc_strncat(&clean
, shader
, backslash
- shader
);
204 shader
= skip_newline (backslash
+ 1);
205 search_start
= shader
;
209 ralloc_strcat(&clean
, shader
);
215 glcpp_preprocess(void *ralloc_ctx
, const char **shader
, char **info_log
,
216 glcpp_extension_iterator extensions
, void *state
,
217 struct gl_context
*gl_ctx
)
220 glcpp_parser_t
*parser
=
221 glcpp_parser_create(&gl_ctx
->Extensions
, extensions
, state
, gl_ctx
->API
);
223 if (! gl_ctx
->Const
.DisableGLSLLineContinuations
)
224 *shader
= remove_line_continuations(parser
, *shader
);
226 glcpp_lex_set_source_string (parser
, *shader
);
228 glcpp_parser_parse (parser
);
230 if (parser
->skip_stack
)
231 glcpp_error (&parser
->skip_stack
->loc
, parser
, "Unterminated #if\n");
233 glcpp_parser_resolve_implicit_version(parser
);
235 ralloc_strcat(info_log
, parser
->info_log
);
237 ralloc_steal(ralloc_ctx
, parser
->output
);
238 *shader
= parser
->output
;
240 errors
= parser
->error
;
241 glcpp_parser_destroy (parser
);