summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/glsl/glcpp/pp.c109
1 files changed, 66 insertions, 43 deletions
diff --git a/src/glsl/glcpp/pp.c b/src/glsl/glcpp/pp.c
index 427f09ae7d3..11b29417be2 100644
--- a/src/glsl/glcpp/pp.c
+++ b/src/glsl/glcpp/pp.c
@@ -70,59 +70,82 @@ glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
&parser->info_log_length, "\n");
}
-/* Remove any line continuation characters in the shader, (whether in
- * preprocessing directives or in GLSL code).
+/* 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 = ralloc_strdup(ctx, "");
- const char *backslash, *newline;
- int collapsed_newlines = 0;
-
- while (true) {
- backslash = strchr(shader, '\\');
-
- /* If we have previously collapsed any line-continuations,
- * then we want to insert additional newlines at the next
- * occurrence of a newline character to avoid changing any
- * line numbers.
- */
- if (collapsed_newlines) {
- newline = strchr(shader, '\n');
- if (newline &&
- (backslash == NULL || newline < backslash))
- {
- ralloc_strncat(&clean, shader,
- newline - shader + 1);
- while (collapsed_newlines--)
- ralloc_strcat(&clean, "\n");
- shader = newline + 1;
- }
+ const char *search_start = shader;
+ const char *newline;
+ while ((newline = strchr(search_start, '\n')) != NULL) {
+ const char *backslash = NULL;
+
+ /* # of characters preceding the newline. */
+ int n = newline - shader;
+
+ /* Find the preceding '\', if it exists */
+ if (n >= 1 && newline[-1] == '\\')
+ backslash = newline - 1;
+ else if (n >= 2 && 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)
- break;
-
- /* At each line continuation, (backslash followed by a
- * newline), copy all preceding text to the output, then
- * advance the shader pointer to the character after the
- * newline.
- */
- if (backslash[1] == '\n' ||
- (backslash[1] == '\r' && backslash[2] == '\n'))
- {
- collapsed_newlines++;
- ralloc_strncat(&clean, shader, backslash - shader);
- if (backslash[1] == '\n')
- shader = backslash + 2;
- else
- shader = backslash + 3;
+ 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 \ */
+ ralloc_strncat(&clean, shader, backslash - shader);
+ shader = newline + 1;
+ extra_newlines++;
+ }
+ } else if (in_continued_line) {
+ /* Copy everything up to and including the \n */
+ ralloc_strncat(&clean, shader, newline - shader + 1);
+ shader = newline + 1;
+ /* Output extra newlines to make line numbers match */
+ for (; extra_newlines > 0; extra_newlines--)
+ ralloc_strcat(&clean, "\n");
+ in_continued_line = 0;
}
+ search_start = newline + 1;
}
-
ralloc_strcat(&clean, shader);
-
return clean;
}