104ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke/*
204ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * Copyright © 2010 Intel Corporation
304ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke *
404ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * Permission is hereby granted, free of charge, to any person obtaining a
504ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * copy of this software and associated documentation files (the "Software"),
604ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * to deal in the Software without restriction, including without limitation
704ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * the rights to use, copy, modify, merge, publish, distribute, sublicense,
804ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * and/or sell copies of the Software, and to permit persons to whom the
904ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * Software is furnished to do so, subject to the following conditions:
1004ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke *
1104ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * The above copyright notice and this permission notice (including the next
1204ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * paragraph) shall be included in all copies or substantial portions of the
1304ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * Software.
1404ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke *
1504ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1604ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1704ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1804ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1904ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2004ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2104ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke * DEALINGS IN THE SOFTWARE.
2204ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke */
2304ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke
24bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke#include <assert.h>
25204d4cbea0de81f6f162ae0348e476de6c916ca8Jakob Bornecrantz#include <string.h>
26bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke#include <ctype.h>
2704ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke#include "glcpp.h"
28653ddaab2636764b9e7999fa39b37edde7fe7c6dAras Pranckevicius#include "main/core.h" /* for isblank() on MSVC */
2904ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke
30f1e6c069fac93dd2b7b2026ccd24833a066c895aKenneth Graunkevoid
31f1e6c069fac93dd2b7b2026ccd24833a066c895aKenneth Graunkeglcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
32f1e6c069fac93dd2b7b2026ccd24833a066c895aKenneth Graunke{
33d1dda951c85f65612ed6fe080728f67fdc93d232Brian Paul	va_list ap;
34d1dda951c85f65612ed6fe080728f67fdc93d232Brian Paul
3562b4b7785a01f11e7fcd9bf76dae6b3c0a16d537Kenneth Graunke	parser->error = 1;
361db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth	ralloc_asprintf_rewrite_tail(&parser->info_log,
371db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				     &parser->info_log_length,
381db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				     "%u:%u(%u): "
391db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				     "preprocessor error: ",
401db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				     locp->source,
411db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				     locp->first_line,
421db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				     locp->first_column);
4333eaa3e0b3a8f94c2abb23ac3c9cbe571f170fb6Kenneth Graunke	va_start(ap, fmt);
441db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth	ralloc_vasprintf_rewrite_tail(&parser->info_log,
451db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				      &parser->info_log_length,
461db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				      fmt, ap);
4733eaa3e0b3a8f94c2abb23ac3c9cbe571f170fb6Kenneth Graunke	va_end(ap);
481db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth	ralloc_asprintf_rewrite_tail(&parser->info_log,
491db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				     &parser->info_log_length, "\n");
50f1e6c069fac93dd2b7b2026ccd24833a066c895aKenneth Graunke}
51f1e6c069fac93dd2b7b2026ccd24833a066c895aKenneth Graunke
52c9529c4d7727e0ff9da71f0941746e4d213dd689Kenneth Graunkevoid
53c9529c4d7727e0ff9da71f0941746e4d213dd689Kenneth Graunkeglcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
54c9529c4d7727e0ff9da71f0941746e4d213dd689Kenneth Graunke{
55d1dda951c85f65612ed6fe080728f67fdc93d232Brian Paul	va_list ap;
56d1dda951c85f65612ed6fe080728f67fdc93d232Brian Paul
571db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth	ralloc_asprintf_rewrite_tail(&parser->info_log,
581db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				     &parser->info_log_length,
591db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				     "%u:%u(%u): "
601db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				     "preprocessor warning: ",
611db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				     locp->source,
621db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				     locp->first_line,
631db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				     locp->first_column);
64c9529c4d7727e0ff9da71f0941746e4d213dd689Kenneth Graunke	va_start(ap, fmt);
651db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth	ralloc_vasprintf_rewrite_tail(&parser->info_log,
661db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				      &parser->info_log_length,
671db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				      fmt, ap);
68c9529c4d7727e0ff9da71f0941746e4d213dd689Kenneth Graunke	va_end(ap);
691db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth	ralloc_asprintf_rewrite_tail(&parser->info_log,
701db463ce2e2812c4e41ab4096ff16a148d4bcc90Carl Worth				     &parser->info_log_length, "\n");
71c9529c4d7727e0ff9da71f0941746e4d213dd689Kenneth Graunke}
72c9529c4d7727e0ff9da71f0941746e4d213dd689Kenneth Graunke
73bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke/* Searches backwards for '^ *#' from a given starting point. */
74bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunkestatic int
75bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunkein_directive(const char *shader, const char *ptr)
76bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke{
77bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	assert(ptr >= shader);
78bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke
79bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	/* Search backwards for '#'. If we find a \n first, it doesn't count */
80bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	for (; ptr >= shader && *ptr != '#'; ptr--) {
81bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke		if (*ptr == '\n')
82bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			return 0;
83bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	}
84bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	if (ptr >= shader) {
85bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke		/* Found '#'...look for spaces preceded by a newline */
86bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke		for (ptr--; ptr >= shader && isblank(*ptr); ptr--);
87bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke		// FIXME: I don't think the '\n' case can happen
88bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke		if (ptr < shader || *ptr == '\n')
89bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			return 1;
90bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	}
91bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	return 0;
92bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke}
93bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke
94bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke/* Remove any line continuation characters in preprocessing directives.
95bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke * However, ignore any in GLSL code, as "There is no line continuation
96bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke * character" (1.30 page 9) in GLSL.
97bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke */
98bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunkestatic char *
99bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunkeremove_line_continuations(glcpp_parser_t *ctx, const char *shader)
100bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke{
101bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	int in_continued_line = 0;
102bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	int extra_newlines = 0;
103d3073f58c17d8675a2ecdd5dfa83e5520c78e1a8Kenneth Graunke	char *clean = ralloc_strdup(ctx, "");
104bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	const char *search_start = shader;
105bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	const char *newline;
106bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	while ((newline = strchr(search_start, '\n')) != NULL) {
107bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke		const char *backslash = NULL;
108805cbf39224580fdb85b09a21be7cbc658f0ecf6Kenneth Graunke
109805cbf39224580fdb85b09a21be7cbc658f0ecf6Kenneth Graunke		/* # of characters preceding the newline. */
110805cbf39224580fdb85b09a21be7cbc658f0ecf6Kenneth Graunke		int n = newline - shader;
111805cbf39224580fdb85b09a21be7cbc658f0ecf6Kenneth Graunke
112bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke		/* Find the preceding '\', if it exists */
113805cbf39224580fdb85b09a21be7cbc658f0ecf6Kenneth Graunke		if (n >= 1 && newline[-1] == '\\')
114bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			backslash = newline - 1;
115805cbf39224580fdb85b09a21be7cbc658f0ecf6Kenneth Graunke		else if (n >= 2 && newline[-1] == '\r' && newline[-2] == '\\')
116bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			backslash = newline - 2;
117805cbf39224580fdb85b09a21be7cbc658f0ecf6Kenneth Graunke
118bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke		/* Double backslashes don't count (the backslash is escaped) */
119bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke		if (backslash != NULL && backslash[-1] == '\\') {
120bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			backslash = NULL;
121bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke		}
122bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke
123bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke		if (backslash != NULL) {
124bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			/* We found a line continuation, but do we care? */
125bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			if (!in_continued_line) {
126bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke				if (in_directive(shader, backslash)) {
127bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke					in_continued_line = 1;
128bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke					extra_newlines = 0;
129bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke				}
130bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			}
131bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			if (in_continued_line) {
132bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke				/* Copy everything before the \ */
133d3073f58c17d8675a2ecdd5dfa83e5520c78e1a8Kenneth Graunke				ralloc_strncat(&clean, shader, backslash - shader);
134bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke				shader = newline + 1;
135bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke				extra_newlines++;
136bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			}
137bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke		} else if (in_continued_line) {
138bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			/* Copy everything up to and including the \n */
139d3073f58c17d8675a2ecdd5dfa83e5520c78e1a8Kenneth Graunke			ralloc_strncat(&clean, shader, newline - shader + 1);
140bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			shader = newline + 1;
141bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			/* Output extra newlines to make line numbers match */
142bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			for (; extra_newlines > 0; extra_newlines--)
143d3073f58c17d8675a2ecdd5dfa83e5520c78e1a8Kenneth Graunke				ralloc_strcat(&clean, "\n");
144bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke			in_continued_line = 0;
145bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke		}
146bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke		search_start = newline + 1;
147bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	}
148d3073f58c17d8675a2ecdd5dfa83e5520c78e1a8Kenneth Graunke	ralloc_strcat(&clean, shader);
149bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	return clean;
150bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke}
151bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke
1521be5d1c887b3308865c8f4770138a9d70251392fBrian Paulint
1537cfd42cefe1949af51ecced9891f415eca2c0e66Dave Airlieglcpp_preprocess(void *ralloc_ctx, const char **shader, char **info_log,
1547dcfc44b72f00ba5a38cb02123c80113440f0de9Kenneth Graunke	   const struct gl_extensions *extensions, int api)
15504ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke{
15604ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke	int errors;
1577dcfc44b72f00ba5a38cb02123c80113440f0de9Kenneth Graunke	glcpp_parser_t *parser = glcpp_parser_create (extensions, api);
158bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke	*shader = remove_line_continuations(parser, *shader);
159bc1097d151677ace501a1f78c11e40ed5b80fdc6Kenneth Graunke
16004ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke	glcpp_lex_set_source_string (parser, *shader);
16104ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke
16204ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke	glcpp_parser_parse (parser);
16304ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke
164da6b10a7eb26c8a13056cbae9015d5b84f134142Carl Worth	if (parser->skip_stack)
165da6b10a7eb26c8a13056cbae9015d5b84f134142Carl Worth		glcpp_error (&parser->skip_stack->loc, parser, "Unterminated #if\n");
166da6b10a7eb26c8a13056cbae9015d5b84f134142Carl Worth
167d3073f58c17d8675a2ecdd5dfa83e5520c78e1a8Kenneth Graunke	ralloc_strcat(info_log, parser->info_log);
16804ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke
169d3073f58c17d8675a2ecdd5dfa83e5520c78e1a8Kenneth Graunke	ralloc_steal(ralloc_ctx, parser->output);
17004ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke	*shader = parser->output;
17104ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke
17262b4b7785a01f11e7fcd9bf76dae6b3c0a16d537Kenneth Graunke	errors = parser->error;
17304ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke	glcpp_parser_destroy (parser);
17404ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke	return errors;
17504ba86a536d76ef24c749e16c785c1634b9187c9Kenneth Graunke}
176