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 backslash
= strchr(shader
, '\\');
122 /* No line continuations were found in this shader, our job is done */
123 if (backslash
== NULL
)
124 return (char *) shader
;
126 search_start
= shader
;
128 /* Determine what flavor of newlines this shader is using. GLSL
129 * provides for 4 different possible ways to separate lines, (using
130 * one or two characters):
132 * "\n" (line-feed, like Linux, Unix, and new Mac OS)
133 * "\r" (carriage-return, like old Mac files)
134 * "\r\n" (carriage-return + line-feed, like DOS files)
135 * "\n\r" (line-feed + carriage-return, like nothing, really)
137 * This code explicitly supports a shader that uses a mixture of
138 * newline terminators and will properly handle line continuation
139 * backslashes followed by any of the above.
141 * But, since we must also insert additional newlines in the output
142 * (for any collapsed lines) we attempt to maintain consistency by
143 * examining the first encountered newline terminator, and using the
144 * same terminator for any newlines we insert.
146 cr
= strchr(search_start
, '\r');
147 lf
= strchr(search_start
, '\n');
149 newline_separator
[0] = '\n';
150 newline_separator
[1] = '\0';
151 newline_separator
[2] = '\0';
155 } else if (lf
== NULL
) {
156 newline_separator
[0] = '\r';
157 } else if (lf
== cr
+ 1) {
158 newline_separator
[0] = '\r';
159 newline_separator
[1] = '\n';
160 } else if (cr
== lf
+ 1) {
161 newline_separator
[0] = '\n';
162 newline_separator
[1] = '\r';
166 /* If we have previously collapsed any line-continuations,
167 * then we want to insert additional newlines at the next
168 * occurrence of a newline character to avoid changing any
171 if (collapsed_newlines
) {
172 cr
= strchr (search_start
, '\r');
173 lf
= strchr (search_start
, '\n');
175 newline
= cr
< lf
? cr
: lf
;
181 (backslash
== NULL
|| newline
< backslash
))
183 ralloc_strncat(&clean
, shader
,
184 newline
- shader
+ 1);
185 while (collapsed_newlines
) {
186 ralloc_strcat(&clean
, newline_separator
);
187 collapsed_newlines
--;
189 shader
= skip_newline (newline
);
190 search_start
= shader
;
194 search_start
= backslash
+ 1;
196 if (backslash
== NULL
)
199 /* At each line continuation, (backslash followed by a
200 * newline), copy all preceding text to the output, then
201 * advance the shader pointer to the character after the
204 if (backslash
[1] == '\r' || backslash
[1] == '\n')
206 collapsed_newlines
++;
207 ralloc_strncat(&clean
, shader
, backslash
- shader
);
208 shader
= skip_newline (backslash
+ 1);
209 search_start
= shader
;
212 backslash
= strchr(search_start
, '\\');
215 ralloc_strcat(&clean
, shader
);
221 glcpp_preprocess(void *ralloc_ctx
, const char **shader
, char **info_log
,
222 glcpp_extension_iterator extensions
, void *state
,
223 struct gl_context
*gl_ctx
)
226 glcpp_parser_t
*parser
=
227 glcpp_parser_create(&gl_ctx
->Extensions
, extensions
, state
, gl_ctx
->API
);
229 if (! gl_ctx
->Const
.DisableGLSLLineContinuations
)
230 *shader
= remove_line_continuations(parser
, *shader
);
232 glcpp_lex_set_source_string (parser
, *shader
);
234 glcpp_parser_parse (parser
);
236 if (parser
->skip_stack
)
237 glcpp_error (&parser
->skip_stack
->loc
, parser
, "Unterminated #if\n");
239 glcpp_parser_resolve_implicit_version(parser
);
241 ralloc_strcat(info_log
, parser
->info_log
);
243 ralloc_steal(ralloc_ctx
, parser
->output
);
244 *shader
= parser
->output
;
246 errors
= parser
->error
;
247 glcpp_parser_destroy (parser
);