Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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