diff options
Diffstat (limited to 'src/glsl')
-rw-r--r-- | src/glsl/glcpp/pp.c | 109 |
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; } |