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.
28 #include "main/mtypes.h"
31 glcpp_error (YYLTYPE
*locp
, glcpp_parser_t
*parser
, const char *fmt
, ...)
36 _mesa_string_buffer_printf(parser
->info_log
,
38 "preprocessor error: ",
43 _mesa_string_buffer_vprintf(parser
->info_log
, fmt
, ap
);
45 _mesa_string_buffer_append_char(parser
->info_log
, '\n');
49 glcpp_warning (YYLTYPE
*locp
, glcpp_parser_t
*parser
, const char *fmt
, ...)
53 _mesa_string_buffer_printf(parser
->info_log
,
55 "preprocessor warning: ",
60 _mesa_string_buffer_vprintf(parser
->info_log
, fmt
, ap
);
62 _mesa_string_buffer_append_char(parser
->info_log
, '\n');
65 /* Given str, (that's expected to start with a newline terminator of some
66 * sort), return a pointer to the first character in str after the newline.
68 * A newline terminator can be any of the following sequences:
75 * And the longest such sequence will be skipped.
78 skip_newline (const char *str
)
80 const char *ret
= str
;
90 if (*ret
&& *ret
== '\n')
92 } else if (*ret
== '\n') {
94 if (*ret
&& *ret
== '\r')
101 /* Initial output buffer size, 4096 minus ralloc() overhead. It was selected
102 * to minimize total amount of allocated memory during shader-db run.
104 #define INITIAL_PP_OUTPUT_BUF_SIZE 4048
106 /* Remove any line continuation characters in the shader, (whether in
107 * preprocessing directives or in GLSL code).
110 remove_line_continuations(glcpp_parser_t
*ctx
, const char *shader
)
112 struct _mesa_string_buffer
*sb
=
113 _mesa_string_buffer_create(ctx
, INITIAL_PP_OUTPUT_BUF_SIZE
);
115 const char *backslash
, *newline
, *search_start
;
117 char newline_separator
[3];
118 int collapsed_newlines
= 0;
121 backslash
= strchr(shader
, '\\');
123 /* No line continuations were found in this shader, our job is done */
124 if (backslash
== NULL
)
125 return (char *) shader
;
127 search_start
= shader
;
129 /* Determine what flavor of newlines this shader is using. GLSL
130 * provides for 4 different possible ways to separate lines, (using
131 * one or two characters):
133 * "\n" (line-feed, like Linux, Unix, and new Mac OS)
134 * "\r" (carriage-return, like old Mac files)
135 * "\r\n" (carriage-return + line-feed, like DOS files)
136 * "\n\r" (line-feed + carriage-return, like nothing, really)
138 * This code explicitly supports a shader that uses a mixture of
139 * newline terminators and will properly handle line continuation
140 * backslashes followed by any of the above.
142 * But, since we must also insert additional newlines in the output
143 * (for any collapsed lines) we attempt to maintain consistency by
144 * examining the first encountered newline terminator, and using the
145 * same terminator for any newlines we insert.
147 cr
= strchr(search_start
, '\r');
148 lf
= strchr(search_start
, '\n');
150 newline_separator
[0] = '\n';
151 newline_separator
[1] = '\0';
152 newline_separator
[2] = '\0';
156 } else if (lf
== NULL
) {
157 newline_separator
[0] = '\r';
158 } else if (lf
== cr
+ 1) {
159 newline_separator
[0] = '\r';
160 newline_separator
[1] = '\n';
161 } else if (cr
== lf
+ 1) {
162 newline_separator
[0] = '\n';
163 newline_separator
[1] = '\r';
165 separator_len
= strlen(newline_separator
);
168 /* If we have previously collapsed any line-continuations,
169 * then we want to insert additional newlines at the next
170 * occurrence of a newline character to avoid changing any
173 if (collapsed_newlines
) {
174 cr
= strchr (search_start
, '\r');
175 lf
= strchr (search_start
, '\n');
177 newline
= cr
< lf
? cr
: lf
;
183 (backslash
== NULL
|| newline
< backslash
))
185 _mesa_string_buffer_append_len(sb
, shader
,
186 newline
- shader
+ 1);
187 while (collapsed_newlines
) {
188 _mesa_string_buffer_append_len(sb
,
191 collapsed_newlines
--;
193 shader
= skip_newline (newline
);
194 search_start
= shader
;
198 search_start
= backslash
+ 1;
200 if (backslash
== NULL
)
203 /* At each line continuation, (backslash followed by a
204 * newline), copy all preceding text to the output, then
205 * advance the shader pointer to the character after the
208 if (backslash
[1] == '\r' || backslash
[1] == '\n')
210 collapsed_newlines
++;
211 _mesa_string_buffer_append_len(sb
, shader
, backslash
- shader
);
212 shader
= skip_newline (backslash
+ 1);
213 search_start
= shader
;
216 backslash
= strchr(search_start
, '\\');
219 _mesa_string_buffer_append(sb
, shader
);
225 glcpp_preprocess(void *ralloc_ctx
, const char **shader
, char **info_log
,
226 glcpp_extension_iterator extensions
, void *state
,
227 struct gl_context
*gl_ctx
)
230 glcpp_parser_t
*parser
=
231 glcpp_parser_create(gl_ctx
, extensions
, state
);
233 if (! gl_ctx
->Const
.DisableGLSLLineContinuations
)
234 *shader
= remove_line_continuations(parser
, *shader
);
236 glcpp_lex_set_source_string (parser
, *shader
);
238 glcpp_parser_parse (parser
);
240 if (parser
->skip_stack
)
241 glcpp_error (&parser
->skip_stack
->loc
, parser
, "Unterminated #if\n");
243 glcpp_parser_resolve_implicit_version(parser
);
245 ralloc_strcat(info_log
, parser
->info_log
->buf
);
247 /* Crimp the buffer first, to conserve memory */
248 _mesa_string_buffer_crimp_to_fit(parser
->output
);
250 ralloc_steal(ralloc_ctx
, parser
->output
->buf
);
251 *shader
= parser
->output
->buf
;
253 errors
= parser
->error
;
254 glcpp_parser_destroy (parser
);