diff options
| -rw-r--r-- | glcpp/pp.c | 79 | 
1 files changed, 79 insertions, 0 deletions
| diff --git a/glcpp/pp.c b/glcpp/pp.c index 5455518c7c..a25b7b72a6 100644 --- a/glcpp/pp.c +++ b/glcpp/pp.c @@ -21,6 +21,8 @@   * DEALINGS IN THE SOFTWARE.   */ +#include <assert.h> +#include <ctype.h>  #include "glcpp.h"  void @@ -56,11 +58,88 @@ glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)  	parser->info_log = talloc_strdup_append(parser->info_log, "\n");  } +/* Searches backwards for '^ *#' from a given starting point. */ +static int +in_directive(const char *shader, const char *ptr) +{ +	assert(ptr >= shader); + +	/* Search backwards for '#'. If we find a \n first, it doesn't count */ +	for (; ptr >= shader && *ptr != '#'; ptr--) { +		if (*ptr == '\n') +			return 0; +	} +	if (ptr >= shader) { +		/* Found '#'...look for spaces preceded by a newline */ +		for (ptr--; ptr >= shader && isblank(*ptr); ptr--); +		// FIXME: I don't think the '\n' case can happen +		if (ptr < shader || *ptr == '\n') +			return 1; +	} +	return 0; +} + +/* Remove any line continuation characters in preprocessing directives. + * However, ignore any in GLSL code, as "There is no line continuation + * character" (1.30 page 9) in GLSL. + */ +static char * +remove_line_continuations(glcpp_parser_t *ctx, const char *shader) +{ +	int in_continued_line = 0; +	int extra_newlines = 0; +	char *clean = talloc_strdup(ctx, ""); +	const char *search_start = shader; +	const char *newline; +	while ((newline = strchr(search_start, '\n')) != NULL) { +		const char *backslash = NULL; +		/* Find the preceding '\', if it exists */ +		if (newline[-1] == '\\') { +			backslash = newline - 1; +		} else if (newline[-1] == '\r' && newline[-2] == '\\') { +			backslash = newline - 2; +		} +		/* Double backslashes don't count (the backslash is escaped) */ +		if (backslash != NULL && backslash[-1] == '\\') { +			backslash = NULL; +		} + +		if (backslash != NULL) { +			/* We found a line continuation, but do we care? */ +			if (!in_continued_line) { +				if (in_directive(shader, backslash)) { +					in_continued_line = 1; +					extra_newlines = 0; +				} +			} +			if (in_continued_line) { +				/* Copy everything before the \ */ +				clean = talloc_strndup_append(clean, shader, backslash - shader); +				shader = newline + 1; +				extra_newlines++; +			} +		} else if (in_continued_line) { +			/* Copy everything up to and including the \n */ +			clean = talloc_strndup_append(clean, shader, newline - shader + 1); +			shader = newline + 1; +			/* Output extra newlines to make line numbers match */ +			for (; extra_newlines > 0; extra_newlines--) +				clean = talloc_strdup_append(clean, "\n"); +			in_continued_line = 0; +		} +		search_start = newline + 1; +	} +	clean = talloc_strdup_append(clean, shader); +	return clean; +} +  extern int  preprocess(void *talloc_ctx, const char **shader, char **info_log)  {  	int errors;  	glcpp_parser_t *parser = glcpp_parser_create (); +	*shader = remove_line_continuations(parser, *shader); +  	glcpp_lex_set_source_string (parser, *shader);  	glcpp_parser_parse (parser); | 
