• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2010 Intel Corporation
3  *
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:
10  *
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
13  * Software.
14  *
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.
22  */
23 
24 #include <assert.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include "glcpp.h"
28 #include "main/core.h" /* for isblank() on MSVC */
29 
30 void
glcpp_error(YYLTYPE * locp,glcpp_parser_t * parser,const char * fmt,...)31 glcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
32 {
33 	va_list ap;
34 
35 	parser->error = 1;
36 	ralloc_asprintf_rewrite_tail(&parser->info_log,
37 				     &parser->info_log_length,
38 				     "%u:%u(%u): "
39 				     "preprocessor error: ",
40 				     locp->source,
41 				     locp->first_line,
42 				     locp->first_column);
43 	va_start(ap, fmt);
44 	ralloc_vasprintf_rewrite_tail(&parser->info_log,
45 				      &parser->info_log_length,
46 				      fmt, ap);
47 	va_end(ap);
48 	ralloc_asprintf_rewrite_tail(&parser->info_log,
49 				     &parser->info_log_length, "\n");
50 }
51 
52 void
glcpp_warning(YYLTYPE * locp,glcpp_parser_t * parser,const char * fmt,...)53 glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
54 {
55 	va_list ap;
56 
57 	ralloc_asprintf_rewrite_tail(&parser->info_log,
58 				     &parser->info_log_length,
59 				     "%u:%u(%u): "
60 				     "preprocessor warning: ",
61 				     locp->source,
62 				     locp->first_line,
63 				     locp->first_column);
64 	va_start(ap, fmt);
65 	ralloc_vasprintf_rewrite_tail(&parser->info_log,
66 				      &parser->info_log_length,
67 				      fmt, ap);
68 	va_end(ap);
69 	ralloc_asprintf_rewrite_tail(&parser->info_log,
70 				     &parser->info_log_length, "\n");
71 }
72 
73 /* Searches backwards for '^ *#' from a given starting point. */
74 static int
in_directive(const char * shader,const char * ptr)75 in_directive(const char *shader, const char *ptr)
76 {
77 	assert(ptr >= shader);
78 
79 	/* Search backwards for '#'. If we find a \n first, it doesn't count */
80 	for (; ptr >= shader && *ptr != '#'; ptr--) {
81 		if (*ptr == '\n')
82 			return 0;
83 	}
84 	if (ptr >= shader) {
85 		/* Found '#'...look for spaces preceded by a newline */
86 		for (ptr--; ptr >= shader && isblank(*ptr); ptr--);
87 		// FIXME: I don't think the '\n' case can happen
88 		if (ptr < shader || *ptr == '\n')
89 			return 1;
90 	}
91 	return 0;
92 }
93 
94 /* Remove any line continuation characters in preprocessing directives.
95  * However, ignore any in GLSL code, as "There is no line continuation
96  * character" (1.30 page 9) in GLSL.
97  */
98 static char *
remove_line_continuations(glcpp_parser_t * ctx,const char * shader)99 remove_line_continuations(glcpp_parser_t *ctx, const char *shader)
100 {
101 	int in_continued_line = 0;
102 	int extra_newlines = 0;
103 	char *clean = ralloc_strdup(ctx, "");
104 	const char *search_start = shader;
105 	const char *newline;
106 	while ((newline = strchr(search_start, '\n')) != NULL) {
107 		const char *backslash = NULL;
108 
109 		/* # of characters preceding the newline. */
110 		int n = newline - shader;
111 
112 		/* Find the preceding '\', if it exists */
113 		if (n >= 1 && newline[-1] == '\\')
114 			backslash = newline - 1;
115 		else if (n >= 2 && newline[-1] == '\r' && newline[-2] == '\\')
116 			backslash = newline - 2;
117 
118 		/* Double backslashes don't count (the backslash is escaped) */
119 		if (backslash != NULL && backslash[-1] == '\\') {
120 			backslash = NULL;
121 		}
122 
123 		if (backslash != NULL) {
124 			/* We found a line continuation, but do we care? */
125 			if (!in_continued_line) {
126 				if (in_directive(shader, backslash)) {
127 					in_continued_line = 1;
128 					extra_newlines = 0;
129 				}
130 			}
131 			if (in_continued_line) {
132 				/* Copy everything before the \ */
133 				ralloc_strncat(&clean, shader, backslash - shader);
134 				shader = newline + 1;
135 				extra_newlines++;
136 			}
137 		} else if (in_continued_line) {
138 			/* Copy everything up to and including the \n */
139 			ralloc_strncat(&clean, shader, newline - shader + 1);
140 			shader = newline + 1;
141 			/* Output extra newlines to make line numbers match */
142 			for (; extra_newlines > 0; extra_newlines--)
143 				ralloc_strcat(&clean, "\n");
144 			in_continued_line = 0;
145 		}
146 		search_start = newline + 1;
147 	}
148 	ralloc_strcat(&clean, shader);
149 	return clean;
150 }
151 
152 int
glcpp_preprocess(void * ralloc_ctx,const char ** shader,char ** info_log,const struct gl_extensions * extensions,int api)153 glcpp_preprocess(void *ralloc_ctx, const char **shader, char **info_log,
154 	   const struct gl_extensions *extensions, int api)
155 {
156 	int errors;
157 	glcpp_parser_t *parser = glcpp_parser_create (extensions, api);
158 	*shader = remove_line_continuations(parser, *shader);
159 
160 	glcpp_lex_set_source_string (parser, *shader);
161 
162 	glcpp_parser_parse (parser);
163 
164 	if (parser->skip_stack)
165 		glcpp_error (&parser->skip_stack->loc, parser, "Unterminated #if\n");
166 
167 	ralloc_strcat(info_log, parser->info_log);
168 
169 	ralloc_steal(ralloc_ctx, parser->output);
170 	*shader = parser->output;
171 
172 	errors = parser->error;
173 	glcpp_parser_destroy (parser);
174 	return errors;
175 }
176