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 _mesa_string_buffer_printf(parser
->info_log
,
37 "preprocessor error: ",
42 _mesa_string_buffer_vprintf(parser
->info_log
, fmt
, ap
);
44 _mesa_string_buffer_append_char(parser
->info_log
, '\n');
48 glcpp_warning (YYLTYPE
*locp
, glcpp_parser_t
*parser
, const char *fmt
, ...)
52 _mesa_string_buffer_printf(parser
->info_log
,
54 "preprocessor warning: ",
59 _mesa_string_buffer_vprintf(parser
->info_log
, fmt
, ap
);
61 _mesa_string_buffer_append_char(parser
->info_log
, '\n');
64 /* Given str, (that's expected to start with a newline terminator of some
65 * sort), return a pointer to the first character in str after the newline.
67 * A newline terminator can be any of the following sequences:
74 * And the longest such sequence will be skipped.
77 skip_newline (const char *str
)
79 const char *ret
= str
;
89 if (*ret
&& *ret
== '\n')
91 } else if (*ret
== '\n') {
93 if (*ret
&& *ret
== '\r')
100 /* Initial output buffer size, 4096 minus ralloc() overhead. It was selected
101 * to minimize total amount of allocated memory during shader-db run.
103 #define INITIAL_PP_OUTPUT_BUF_SIZE 4048
105 /* Remove any line continuation characters in the shader, (whether in
106 * preprocessing directives or in GLSL code).
109 remove_line_continuations(glcpp_parser_t
*ctx
, const char *shader
)
111 struct _mesa_string_buffer
*sb
=
112 _mesa_string_buffer_create(ctx
, INITIAL_PP_OUTPUT_BUF_SIZE
);
114 const char *backslash
, *newline
, *search_start
;
116 char newline_separator
[3];
117 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';
164 separator_len
= strlen(newline_separator
);
167 /* If we have previously collapsed any line-continuations,
168 * then we want to insert additional newlines at the next
169 * occurrence of a newline character to avoid changing any
172 if (collapsed_newlines
) {
173 cr
= strchr (search_start
, '\r');
174 lf
= strchr (search_start
, '\n');
176 newline
= cr
< lf
? cr
: lf
;
182 (backslash
== NULL
|| newline
< backslash
))
184 _mesa_string_buffer_append_len(sb
, shader
,
185 newline
- shader
+ 1);
186 while (collapsed_newlines
) {
187 _mesa_string_buffer_append_len(sb
,
190 collapsed_newlines
--;
192 shader
= skip_newline (newline
);
193 search_start
= shader
;
197 search_start
= backslash
+ 1;
199 if (backslash
== NULL
)
202 /* At each line continuation, (backslash followed by a
203 * newline), copy all preceding text to the output, then
204 * advance the shader pointer to the character after the
207 if (backslash
[1] == '\r' || backslash
[1] == '\n')
209 collapsed_newlines
++;
210 _mesa_string_buffer_append_len(sb
, shader
, backslash
- shader
);
211 shader
= skip_newline (backslash
+ 1);
212 search_start
= shader
;
215 backslash
= strchr(search_start
, '\\');
218 _mesa_string_buffer_append(sb
, shader
);
224 glcpp_preprocess(void *ralloc_ctx
, const char **shader
, char **info_log
,
225 glcpp_extension_iterator extensions
, void *state
,
226 struct gl_context
*gl_ctx
)
229 glcpp_parser_t
*parser
=
230 glcpp_parser_create(&gl_ctx
->Extensions
, extensions
, state
, gl_ctx
->API
);
232 if (! gl_ctx
->Const
.DisableGLSLLineContinuations
)
233 *shader
= remove_line_continuations(parser
, *shader
);
235 glcpp_lex_set_source_string (parser
, *shader
);
237 glcpp_parser_parse (parser
);
239 if (parser
->skip_stack
)
240 glcpp_error (&parser
->skip_stack
->loc
, parser
, "Unterminated #if\n");
242 glcpp_parser_resolve_implicit_version(parser
);
244 ralloc_strcat(info_log
, parser
->info_log
->buf
);
246 /* Crimp the buffer first, to conserve memory */
247 _mesa_string_buffer_crimp_to_fit(parser
->output
);
249 ralloc_steal(ralloc_ctx
, parser
->output
->buf
);
250 *shader
= parser
->output
->buf
;
252 errors
= parser
->error
;
253 glcpp_parser_destroy (parser
);