Path: blob/21.2-virgl/src/compiler/glsl/glcpp/pp.c
4547 views
/*1* Copyright © 2010 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER20* DEALINGS IN THE SOFTWARE.21*/2223#include <assert.h>24#include <string.h>25#include <ctype.h>26#include "glcpp.h"27#include "main/mtypes.h"2829void30glcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)31{32va_list ap;3334parser->error = 1;35_mesa_string_buffer_printf(parser->info_log,36"%u:%u(%u): "37"preprocessor error: ",38locp->source,39locp->first_line,40locp->first_column);41va_start(ap, fmt);42_mesa_string_buffer_vprintf(parser->info_log, fmt, ap);43va_end(ap);44_mesa_string_buffer_append_char(parser->info_log, '\n');45}4647void48glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)49{50va_list ap;5152_mesa_string_buffer_printf(parser->info_log,53"%u:%u(%u): "54"preprocessor warning: ",55locp->source,56locp->first_line,57locp->first_column);58va_start(ap, fmt);59_mesa_string_buffer_vprintf(parser->info_log, fmt, ap);60va_end(ap);61_mesa_string_buffer_append_char(parser->info_log, '\n');62}6364/* Given str, (that's expected to start with a newline terminator of some65* sort), return a pointer to the first character in str after the newline.66*67* A newline terminator can be any of the following sequences:68*69* "\r\n"70* "\n\r"71* "\n"72* "\r"73*74* And the longest such sequence will be skipped.75*/76static const char *77skip_newline (const char *str)78{79const char *ret = str;8081if (ret == NULL)82return ret;8384if (*ret == '\0')85return ret;8687if (*ret == '\r') {88ret++;89if (*ret && *ret == '\n')90ret++;91} else if (*ret == '\n') {92ret++;93if (*ret && *ret == '\r')94ret++;95}9697return ret;98}99100/* Initial output buffer size, 4096 minus ralloc() overhead. It was selected101* to minimize total amount of allocated memory during shader-db run.102*/103#define INITIAL_PP_OUTPUT_BUF_SIZE 4048104105/* Remove any line continuation characters in the shader, (whether in106* preprocessing directives or in GLSL code).107*/108static char *109remove_line_continuations(glcpp_parser_t *ctx, const char *shader)110{111struct _mesa_string_buffer *sb =112_mesa_string_buffer_create(ctx, INITIAL_PP_OUTPUT_BUF_SIZE);113114const char *backslash, *newline, *search_start;115const char *cr, *lf;116char newline_separator[3];117int collapsed_newlines = 0;118int separator_len;119120backslash = strchr(shader, '\\');121122/* No line continuations were found in this shader, our job is done */123if (backslash == NULL)124return (char *) shader;125126search_start = shader;127128/* Determine what flavor of newlines this shader is using. GLSL129* provides for 4 different possible ways to separate lines, (using130* one or two characters):131*132* "\n" (line-feed, like Linux, Unix, and new Mac OS)133* "\r" (carriage-return, like old Mac files)134* "\r\n" (carriage-return + line-feed, like DOS files)135* "\n\r" (line-feed + carriage-return, like nothing, really)136*137* This code explicitly supports a shader that uses a mixture of138* newline terminators and will properly handle line continuation139* backslashes followed by any of the above.140*141* But, since we must also insert additional newlines in the output142* (for any collapsed lines) we attempt to maintain consistency by143* examining the first encountered newline terminator, and using the144* same terminator for any newlines we insert.145*/146cr = strchr(search_start, '\r');147lf = strchr(search_start, '\n');148149newline_separator[0] = '\n';150newline_separator[1] = '\0';151newline_separator[2] = '\0';152153if (cr == NULL) {154/* Nothing to do. */155} else if (lf == NULL) {156newline_separator[0] = '\r';157} else if (lf == cr + 1) {158newline_separator[0] = '\r';159newline_separator[1] = '\n';160} else if (cr == lf + 1) {161newline_separator[0] = '\n';162newline_separator[1] = '\r';163}164separator_len = strlen(newline_separator);165166while (true) {167/* If we have previously collapsed any line-continuations,168* then we want to insert additional newlines at the next169* occurrence of a newline character to avoid changing any170* line numbers.171*/172if (collapsed_newlines) {173cr = strchr (search_start, '\r');174lf = strchr (search_start, '\n');175if (cr && lf)176newline = cr < lf ? cr : lf;177else if (cr)178newline = cr;179else180newline = lf;181if (newline &&182(backslash == NULL || newline < backslash))183{184_mesa_string_buffer_append_len(sb, shader,185newline - shader + 1);186while (collapsed_newlines) {187_mesa_string_buffer_append_len(sb,188newline_separator,189separator_len);190collapsed_newlines--;191}192shader = skip_newline (newline);193search_start = shader;194}195}196197if (backslash == NULL)198break;199200search_start = backslash + 1;201202/* At each line continuation, (backslash followed by a203* newline), copy all preceding text to the output, then204* advance the shader pointer to the character after the205* newline.206*/207if (backslash[1] == '\r' || backslash[1] == '\n')208{209collapsed_newlines++;210_mesa_string_buffer_append_len(sb, shader, backslash - shader);211shader = skip_newline (backslash + 1);212search_start = shader;213}214215backslash = strchr(search_start, '\\');216}217218_mesa_string_buffer_append(sb, shader);219220return sb->buf;221}222223int224glcpp_preprocess(void *ralloc_ctx, const char **shader, char **info_log,225glcpp_extension_iterator extensions, void *state,226struct gl_context *gl_ctx)227{228int errors;229glcpp_parser_t *parser =230glcpp_parser_create(gl_ctx, extensions, state);231232if (! gl_ctx->Const.DisableGLSLLineContinuations)233*shader = remove_line_continuations(parser, *shader);234235glcpp_lex_set_source_string (parser, *shader);236237glcpp_parser_parse (parser);238239if (parser->skip_stack)240glcpp_error (&parser->skip_stack->loc, parser, "Unterminated #if\n");241242glcpp_parser_resolve_implicit_version(parser);243244ralloc_strcat(info_log, parser->info_log->buf);245246/* Crimp the buffer first, to conserve memory */247_mesa_string_buffer_crimp_to_fit(parser->output);248249ralloc_steal(ralloc_ctx, parser->output->buf);250*shader = parser->output->buf;251252errors = parser->error;253glcpp_parser_destroy (parser);254return errors;255}256257258