Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | 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.  
  29. void
  30. glcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
  31. {
  32.         va_list ap;
  33.  
  34.         parser->error = 1;
  35.         ralloc_asprintf_rewrite_tail(&parser->info_log,
  36.                                      &parser->info_log_length,
  37.                                      "%u:%u(%u): "
  38.                                      "preprocessor error: ",
  39.                                      locp->source,
  40.                                      locp->first_line,
  41.                                      locp->first_column);
  42.         va_start(ap, fmt);
  43.         ralloc_vasprintf_rewrite_tail(&parser->info_log,
  44.                                       &parser->info_log_length,
  45.                                       fmt, ap);
  46.         va_end(ap);
  47.         ralloc_asprintf_rewrite_tail(&parser->info_log,
  48.                                      &parser->info_log_length, "\n");
  49. }
  50.  
  51. void
  52. glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
  53. {
  54.         va_list ap;
  55.  
  56.         ralloc_asprintf_rewrite_tail(&parser->info_log,
  57.                                      &parser->info_log_length,
  58.                                      "%u:%u(%u): "
  59.                                      "preprocessor warning: ",
  60.                                      locp->source,
  61.                                      locp->first_line,
  62.                                      locp->first_column);
  63.         va_start(ap, fmt);
  64.         ralloc_vasprintf_rewrite_tail(&parser->info_log,
  65.                                       &parser->info_log_length,
  66.                                       fmt, ap);
  67.         va_end(ap);
  68.         ralloc_asprintf_rewrite_tail(&parser->info_log,
  69.                                      &parser->info_log_length, "\n");
  70. }
  71.  
  72. /* Given str, (that's expected to start with a newline terminator of some
  73.  * sort), return a pointer to the first character in str after the newline.
  74.  *
  75.  * A newline terminator can be any of the following sequences:
  76.  *
  77.  *      "\r\n"
  78.  *      "\n\r"
  79.  *      "\n"
  80.  *      "\r"
  81.  *
  82.  * And the longest such sequence will be skipped.
  83.  */
  84. static const char *
  85. skip_newline (const char *str)
  86. {
  87.         const char *ret = str;
  88.  
  89.         if (ret == NULL)
  90.                 return ret;
  91.  
  92.         if (*ret == '\0')
  93.                 return ret;
  94.  
  95.         if (*ret == '\r') {
  96.                 ret++;
  97.                 if (*ret && *ret == '\n')
  98.                         ret++;
  99.         } else if (*ret == '\n') {
  100.                 ret++;
  101.                 if (*ret && *ret == '\r')
  102.                         ret++;
  103.         }
  104.  
  105.         return ret;
  106. }
  107.  
  108. /* Remove any line continuation characters in the shader, (whether in
  109.  * preprocessing directives or in GLSL code).
  110.  */
  111. static char *
  112. remove_line_continuations(glcpp_parser_t *ctx, const char *shader)
  113. {
  114.         char *clean = ralloc_strdup(ctx, "");
  115.         const char *backslash, *newline, *search_start;
  116.         const char *cr, *lf;
  117.         char newline_separator[3];
  118.         int collapsed_newlines = 0;
  119.  
  120.         search_start = shader;
  121.  
  122.         /* Determine what flavor of newlines this shader is using. GLSL
  123.          * provides for 4 different possible ways to separate lines, (using
  124.          * one or two characters):
  125.          *
  126.          *      "\n" (line-feed, like Linux, Unix, and new Mac OS)
  127.          *      "\r" (carriage-return, like old Mac files)
  128.          *      "\r\n" (carriage-return + line-feed, like DOS files)
  129.          *      "\n\r" (line-feed + carriage-return, like nothing, really)
  130.          *
  131.          * This code explicitly supports a shader that uses a mixture of
  132.          * newline terminators and will properly handle line continuation
  133.          * backslashes followed by any of the above.
  134.          *
  135.          * But, since we must also insert additional newlines in the output
  136.          * (for any collapsed lines) we attempt to maintain consistency by
  137.          * examining the first encountered newline terminator, and using the
  138.          * same terminator for any newlines we insert.
  139.          */
  140.         cr = strchr(search_start, '\r');
  141.         lf = strchr(search_start, '\n');
  142.  
  143.         newline_separator[0] = '\n';
  144.         newline_separator[1] = '\0';
  145.         newline_separator[2] = '\0';
  146.  
  147.         if (cr == NULL) {
  148.                 /* Nothing to do. */
  149.         } else if (lf == NULL) {
  150.                 newline_separator[0] = '\r';
  151.         } else if (lf == cr + 1) {
  152.                 newline_separator[0] = '\r';
  153.                 newline_separator[1] = '\n';
  154.         } else if (cr == lf + 1) {
  155.                 newline_separator[0] = '\n';
  156.                 newline_separator[1] = '\r';
  157.         }
  158.  
  159.         while (true) {
  160.                 backslash = strchr(search_start, '\\');
  161.  
  162.                 /* If we have previously collapsed any line-continuations,
  163.                  * then we want to insert additional newlines at the next
  164.                  * occurrence of a newline character to avoid changing any
  165.                  * line numbers.
  166.                  */
  167.                 if (collapsed_newlines) {
  168.                         cr = strchr (search_start, '\r');
  169.                         lf = strchr (search_start, '\n');
  170.                         if (cr && lf)
  171.                                 newline = cr < lf ? cr : lf;
  172.                         else if (cr)
  173.                                 newline = cr;
  174.                         else
  175.                                 newline = lf;
  176.                         if (newline &&
  177.                             (backslash == NULL || newline < backslash))
  178.                         {
  179.                                 ralloc_strncat(&clean, shader,
  180.                                                newline - shader + 1);
  181.                                 while (collapsed_newlines) {
  182.                                         ralloc_strcat(&clean, newline_separator);
  183.                                         collapsed_newlines--;
  184.                                 }
  185.                                 shader = skip_newline (newline);
  186.                                 search_start = shader;
  187.                         }
  188.                 }
  189.  
  190.                 search_start = backslash + 1;
  191.  
  192.                 if (backslash == NULL)
  193.                         break;
  194.  
  195.                 /* At each line continuation, (backslash followed by a
  196.                  * newline), copy all preceding text to the output, then
  197.                  * advance the shader pointer to the character after the
  198.                  * newline.
  199.                  */
  200.                 if (backslash[1] == '\r' || backslash[1] == '\n')
  201.                 {
  202.                         collapsed_newlines++;
  203.                         ralloc_strncat(&clean, shader, backslash - shader);
  204.                         shader = skip_newline (backslash + 1);
  205.                         search_start = shader;
  206.                 }
  207.         }
  208.  
  209.         ralloc_strcat(&clean, shader);
  210.  
  211.         return clean;
  212. }
  213.  
  214. int
  215. glcpp_preprocess(void *ralloc_ctx, const char **shader, char **info_log,
  216.            const struct gl_extensions *extensions, struct gl_context *gl_ctx)
  217. {
  218.         int errors;
  219.         glcpp_parser_t *parser = glcpp_parser_create (extensions, gl_ctx->API);
  220.  
  221.         if (! gl_ctx->Const.DisableGLSLLineContinuations)
  222.                 *shader = remove_line_continuations(parser, *shader);
  223.  
  224.         glcpp_lex_set_source_string (parser, *shader);
  225.  
  226.         glcpp_parser_parse (parser);
  227.  
  228.         if (parser->skip_stack)
  229.                 glcpp_error (&parser->skip_stack->loc, parser, "Unterminated #if\n");
  230.  
  231.         glcpp_parser_resolve_implicit_version(parser);
  232.  
  233.         ralloc_strcat(info_log, parser->info_log);
  234.  
  235.         ralloc_steal(ralloc_ctx, parser->output);
  236.         *shader = parser->output;
  237.  
  238.         errors = parser->error;
  239.         glcpp_parser_destroy (parser);
  240.         return errors;
  241. }
  242.