101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2010 Intel Corporation 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2101e04c3fSmrg * DEALINGS IN THE SOFTWARE. 2201e04c3fSmrg */ 2301e04c3fSmrg 2401e04c3fSmrg#include <assert.h> 2501e04c3fSmrg#include <string.h> 2601e04c3fSmrg#include <ctype.h> 2701e04c3fSmrg#include "glcpp.h" 2801e04c3fSmrg#include "main/mtypes.h" 2901e04c3fSmrg 3001e04c3fSmrgvoid 3101e04c3fSmrgglcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...) 3201e04c3fSmrg{ 3301e04c3fSmrg va_list ap; 3401e04c3fSmrg 3501e04c3fSmrg parser->error = 1; 3601e04c3fSmrg _mesa_string_buffer_printf(parser->info_log, 3701e04c3fSmrg "%u:%u(%u): " 3801e04c3fSmrg "preprocessor error: ", 3901e04c3fSmrg locp->source, 4001e04c3fSmrg locp->first_line, 4101e04c3fSmrg locp->first_column); 4201e04c3fSmrg va_start(ap, fmt); 4301e04c3fSmrg _mesa_string_buffer_vprintf(parser->info_log, fmt, ap); 4401e04c3fSmrg va_end(ap); 4501e04c3fSmrg _mesa_string_buffer_append_char(parser->info_log, '\n'); 4601e04c3fSmrg} 4701e04c3fSmrg 4801e04c3fSmrgvoid 4901e04c3fSmrgglcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...) 5001e04c3fSmrg{ 5101e04c3fSmrg va_list ap; 5201e04c3fSmrg 5301e04c3fSmrg _mesa_string_buffer_printf(parser->info_log, 5401e04c3fSmrg "%u:%u(%u): " 5501e04c3fSmrg "preprocessor warning: ", 5601e04c3fSmrg locp->source, 5701e04c3fSmrg locp->first_line, 5801e04c3fSmrg locp->first_column); 5901e04c3fSmrg va_start(ap, fmt); 6001e04c3fSmrg _mesa_string_buffer_vprintf(parser->info_log, fmt, ap); 6101e04c3fSmrg va_end(ap); 6201e04c3fSmrg _mesa_string_buffer_append_char(parser->info_log, '\n'); 6301e04c3fSmrg} 6401e04c3fSmrg 6501e04c3fSmrg/* Given str, (that's expected to start with a newline terminator of some 6601e04c3fSmrg * sort), return a pointer to the first character in str after the newline. 6701e04c3fSmrg * 6801e04c3fSmrg * A newline terminator can be any of the following sequences: 6901e04c3fSmrg * 7001e04c3fSmrg * "\r\n" 7101e04c3fSmrg * "\n\r" 7201e04c3fSmrg * "\n" 7301e04c3fSmrg * "\r" 7401e04c3fSmrg * 7501e04c3fSmrg * And the longest such sequence will be skipped. 7601e04c3fSmrg */ 7701e04c3fSmrgstatic const char * 7801e04c3fSmrgskip_newline (const char *str) 7901e04c3fSmrg{ 8001e04c3fSmrg const char *ret = str; 8101e04c3fSmrg 8201e04c3fSmrg if (ret == NULL) 8301e04c3fSmrg return ret; 8401e04c3fSmrg 8501e04c3fSmrg if (*ret == '\0') 8601e04c3fSmrg return ret; 8701e04c3fSmrg 8801e04c3fSmrg if (*ret == '\r') { 8901e04c3fSmrg ret++; 9001e04c3fSmrg if (*ret && *ret == '\n') 9101e04c3fSmrg ret++; 9201e04c3fSmrg } else if (*ret == '\n') { 9301e04c3fSmrg ret++; 9401e04c3fSmrg if (*ret && *ret == '\r') 9501e04c3fSmrg ret++; 9601e04c3fSmrg } 9701e04c3fSmrg 9801e04c3fSmrg return ret; 9901e04c3fSmrg} 10001e04c3fSmrg 10101e04c3fSmrg/* Initial output buffer size, 4096 minus ralloc() overhead. It was selected 10201e04c3fSmrg * to minimize total amount of allocated memory during shader-db run. 10301e04c3fSmrg */ 10401e04c3fSmrg#define INITIAL_PP_OUTPUT_BUF_SIZE 4048 10501e04c3fSmrg 10601e04c3fSmrg/* Remove any line continuation characters in the shader, (whether in 10701e04c3fSmrg * preprocessing directives or in GLSL code). 10801e04c3fSmrg */ 10901e04c3fSmrgstatic char * 11001e04c3fSmrgremove_line_continuations(glcpp_parser_t *ctx, const char *shader) 11101e04c3fSmrg{ 11201e04c3fSmrg struct _mesa_string_buffer *sb = 11301e04c3fSmrg _mesa_string_buffer_create(ctx, INITIAL_PP_OUTPUT_BUF_SIZE); 11401e04c3fSmrg 11501e04c3fSmrg const char *backslash, *newline, *search_start; 11601e04c3fSmrg const char *cr, *lf; 11701e04c3fSmrg char newline_separator[3]; 11801e04c3fSmrg int collapsed_newlines = 0; 11901e04c3fSmrg int separator_len; 12001e04c3fSmrg 12101e04c3fSmrg backslash = strchr(shader, '\\'); 12201e04c3fSmrg 12301e04c3fSmrg /* No line continuations were found in this shader, our job is done */ 12401e04c3fSmrg if (backslash == NULL) 12501e04c3fSmrg return (char *) shader; 12601e04c3fSmrg 12701e04c3fSmrg search_start = shader; 12801e04c3fSmrg 12901e04c3fSmrg /* Determine what flavor of newlines this shader is using. GLSL 13001e04c3fSmrg * provides for 4 different possible ways to separate lines, (using 13101e04c3fSmrg * one or two characters): 13201e04c3fSmrg * 13301e04c3fSmrg * "\n" (line-feed, like Linux, Unix, and new Mac OS) 13401e04c3fSmrg * "\r" (carriage-return, like old Mac files) 13501e04c3fSmrg * "\r\n" (carriage-return + line-feed, like DOS files) 13601e04c3fSmrg * "\n\r" (line-feed + carriage-return, like nothing, really) 13701e04c3fSmrg * 13801e04c3fSmrg * This code explicitly supports a shader that uses a mixture of 13901e04c3fSmrg * newline terminators and will properly handle line continuation 14001e04c3fSmrg * backslashes followed by any of the above. 14101e04c3fSmrg * 14201e04c3fSmrg * But, since we must also insert additional newlines in the output 14301e04c3fSmrg * (for any collapsed lines) we attempt to maintain consistency by 14401e04c3fSmrg * examining the first encountered newline terminator, and using the 14501e04c3fSmrg * same terminator for any newlines we insert. 14601e04c3fSmrg */ 14701e04c3fSmrg cr = strchr(search_start, '\r'); 14801e04c3fSmrg lf = strchr(search_start, '\n'); 14901e04c3fSmrg 15001e04c3fSmrg newline_separator[0] = '\n'; 15101e04c3fSmrg newline_separator[1] = '\0'; 15201e04c3fSmrg newline_separator[2] = '\0'; 15301e04c3fSmrg 15401e04c3fSmrg if (cr == NULL) { 15501e04c3fSmrg /* Nothing to do. */ 15601e04c3fSmrg } else if (lf == NULL) { 15701e04c3fSmrg newline_separator[0] = '\r'; 15801e04c3fSmrg } else if (lf == cr + 1) { 15901e04c3fSmrg newline_separator[0] = '\r'; 16001e04c3fSmrg newline_separator[1] = '\n'; 16101e04c3fSmrg } else if (cr == lf + 1) { 16201e04c3fSmrg newline_separator[0] = '\n'; 16301e04c3fSmrg newline_separator[1] = '\r'; 16401e04c3fSmrg } 16501e04c3fSmrg separator_len = strlen(newline_separator); 16601e04c3fSmrg 16701e04c3fSmrg while (true) { 16801e04c3fSmrg /* If we have previously collapsed any line-continuations, 16901e04c3fSmrg * then we want to insert additional newlines at the next 17001e04c3fSmrg * occurrence of a newline character to avoid changing any 17101e04c3fSmrg * line numbers. 17201e04c3fSmrg */ 17301e04c3fSmrg if (collapsed_newlines) { 17401e04c3fSmrg cr = strchr (search_start, '\r'); 17501e04c3fSmrg lf = strchr (search_start, '\n'); 17601e04c3fSmrg if (cr && lf) 17701e04c3fSmrg newline = cr < lf ? cr : lf; 17801e04c3fSmrg else if (cr) 17901e04c3fSmrg newline = cr; 18001e04c3fSmrg else 18101e04c3fSmrg newline = lf; 18201e04c3fSmrg if (newline && 18301e04c3fSmrg (backslash == NULL || newline < backslash)) 18401e04c3fSmrg { 18501e04c3fSmrg _mesa_string_buffer_append_len(sb, shader, 18601e04c3fSmrg newline - shader + 1); 18701e04c3fSmrg while (collapsed_newlines) { 18801e04c3fSmrg _mesa_string_buffer_append_len(sb, 18901e04c3fSmrg newline_separator, 19001e04c3fSmrg separator_len); 19101e04c3fSmrg collapsed_newlines--; 19201e04c3fSmrg } 19301e04c3fSmrg shader = skip_newline (newline); 19401e04c3fSmrg search_start = shader; 19501e04c3fSmrg } 19601e04c3fSmrg } 19701e04c3fSmrg 19801e04c3fSmrg if (backslash == NULL) 19901e04c3fSmrg break; 20001e04c3fSmrg 2017ec681f3Smrg search_start = backslash + 1; 2027ec681f3Smrg 20301e04c3fSmrg /* At each line continuation, (backslash followed by a 20401e04c3fSmrg * newline), copy all preceding text to the output, then 20501e04c3fSmrg * advance the shader pointer to the character after the 20601e04c3fSmrg * newline. 20701e04c3fSmrg */ 20801e04c3fSmrg if (backslash[1] == '\r' || backslash[1] == '\n') 20901e04c3fSmrg { 21001e04c3fSmrg collapsed_newlines++; 21101e04c3fSmrg _mesa_string_buffer_append_len(sb, shader, backslash - shader); 21201e04c3fSmrg shader = skip_newline (backslash + 1); 21301e04c3fSmrg search_start = shader; 21401e04c3fSmrg } 21501e04c3fSmrg 21601e04c3fSmrg backslash = strchr(search_start, '\\'); 21701e04c3fSmrg } 21801e04c3fSmrg 21901e04c3fSmrg _mesa_string_buffer_append(sb, shader); 22001e04c3fSmrg 22101e04c3fSmrg return sb->buf; 22201e04c3fSmrg} 22301e04c3fSmrg 22401e04c3fSmrgint 22501e04c3fSmrgglcpp_preprocess(void *ralloc_ctx, const char **shader, char **info_log, 22601e04c3fSmrg glcpp_extension_iterator extensions, void *state, 22701e04c3fSmrg struct gl_context *gl_ctx) 22801e04c3fSmrg{ 22901e04c3fSmrg int errors; 23001e04c3fSmrg glcpp_parser_t *parser = 2317ec681f3Smrg glcpp_parser_create(gl_ctx, extensions, state); 23201e04c3fSmrg 23301e04c3fSmrg if (! gl_ctx->Const.DisableGLSLLineContinuations) 23401e04c3fSmrg *shader = remove_line_continuations(parser, *shader); 23501e04c3fSmrg 23601e04c3fSmrg glcpp_lex_set_source_string (parser, *shader); 23701e04c3fSmrg 23801e04c3fSmrg glcpp_parser_parse (parser); 23901e04c3fSmrg 24001e04c3fSmrg if (parser->skip_stack) 24101e04c3fSmrg glcpp_error (&parser->skip_stack->loc, parser, "Unterminated #if\n"); 24201e04c3fSmrg 24301e04c3fSmrg glcpp_parser_resolve_implicit_version(parser); 24401e04c3fSmrg 24501e04c3fSmrg ralloc_strcat(info_log, parser->info_log->buf); 24601e04c3fSmrg 24701e04c3fSmrg /* Crimp the buffer first, to conserve memory */ 24801e04c3fSmrg _mesa_string_buffer_crimp_to_fit(parser->output); 24901e04c3fSmrg 25001e04c3fSmrg ralloc_steal(ralloc_ctx, parser->output->buf); 25101e04c3fSmrg *shader = parser->output->buf; 25201e04c3fSmrg 25301e04c3fSmrg errors = parser->error; 25401e04c3fSmrg glcpp_parser_destroy (parser); 25501e04c3fSmrg return errors; 25601e04c3fSmrg} 257