1b8e80941Smrg/* 2b8e80941Smrg * Copyright © 2010 Intel Corporation 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the 9b8e80941Smrg * Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21b8e80941Smrg * DEALINGS IN THE SOFTWARE. 22b8e80941Smrg */ 23b8e80941Smrg 24b8e80941Smrg#include <assert.h> 25b8e80941Smrg#include <string.h> 26b8e80941Smrg#include <ctype.h> 27b8e80941Smrg#include "glcpp.h" 28b8e80941Smrg#include "main/mtypes.h" 29b8e80941Smrg 30b8e80941Smrgvoid 31b8e80941Smrgglcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...) 32b8e80941Smrg{ 33b8e80941Smrg va_list ap; 34b8e80941Smrg 35b8e80941Smrg parser->error = 1; 36b8e80941Smrg _mesa_string_buffer_printf(parser->info_log, 37b8e80941Smrg "%u:%u(%u): " 38b8e80941Smrg "preprocessor error: ", 39b8e80941Smrg locp->source, 40b8e80941Smrg locp->first_line, 41b8e80941Smrg locp->first_column); 42b8e80941Smrg va_start(ap, fmt); 43b8e80941Smrg _mesa_string_buffer_vprintf(parser->info_log, fmt, ap); 44b8e80941Smrg va_end(ap); 45b8e80941Smrg _mesa_string_buffer_append_char(parser->info_log, '\n'); 46b8e80941Smrg} 47b8e80941Smrg 48b8e80941Smrgvoid 49b8e80941Smrgglcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...) 50b8e80941Smrg{ 51b8e80941Smrg va_list ap; 52b8e80941Smrg 53b8e80941Smrg _mesa_string_buffer_printf(parser->info_log, 54b8e80941Smrg "%u:%u(%u): " 55b8e80941Smrg "preprocessor warning: ", 56b8e80941Smrg locp->source, 57b8e80941Smrg locp->first_line, 58b8e80941Smrg locp->first_column); 59b8e80941Smrg va_start(ap, fmt); 60b8e80941Smrg _mesa_string_buffer_vprintf(parser->info_log, fmt, ap); 61b8e80941Smrg va_end(ap); 62b8e80941Smrg _mesa_string_buffer_append_char(parser->info_log, '\n'); 63b8e80941Smrg} 64b8e80941Smrg 65b8e80941Smrg/* Given str, (that's expected to start with a newline terminator of some 66b8e80941Smrg * sort), return a pointer to the first character in str after the newline. 67b8e80941Smrg * 68b8e80941Smrg * A newline terminator can be any of the following sequences: 69b8e80941Smrg * 70b8e80941Smrg * "\r\n" 71b8e80941Smrg * "\n\r" 72b8e80941Smrg * "\n" 73b8e80941Smrg * "\r" 74b8e80941Smrg * 75b8e80941Smrg * And the longest such sequence will be skipped. 76b8e80941Smrg */ 77b8e80941Smrgstatic const char * 78b8e80941Smrgskip_newline (const char *str) 79b8e80941Smrg{ 80b8e80941Smrg const char *ret = str; 81b8e80941Smrg 82b8e80941Smrg if (ret == NULL) 83b8e80941Smrg return ret; 84b8e80941Smrg 85b8e80941Smrg if (*ret == '\0') 86b8e80941Smrg return ret; 87b8e80941Smrg 88b8e80941Smrg if (*ret == '\r') { 89b8e80941Smrg ret++; 90b8e80941Smrg if (*ret && *ret == '\n') 91b8e80941Smrg ret++; 92b8e80941Smrg } else if (*ret == '\n') { 93b8e80941Smrg ret++; 94b8e80941Smrg if (*ret && *ret == '\r') 95b8e80941Smrg ret++; 96b8e80941Smrg } 97b8e80941Smrg 98b8e80941Smrg return ret; 99b8e80941Smrg} 100b8e80941Smrg 101b8e80941Smrg/* Initial output buffer size, 4096 minus ralloc() overhead. It was selected 102b8e80941Smrg * to minimize total amount of allocated memory during shader-db run. 103b8e80941Smrg */ 104b8e80941Smrg#define INITIAL_PP_OUTPUT_BUF_SIZE 4048 105b8e80941Smrg 106b8e80941Smrg/* Remove any line continuation characters in the shader, (whether in 107b8e80941Smrg * preprocessing directives or in GLSL code). 108b8e80941Smrg */ 109b8e80941Smrgstatic char * 110b8e80941Smrgremove_line_continuations(glcpp_parser_t *ctx, const char *shader) 111b8e80941Smrg{ 112b8e80941Smrg struct _mesa_string_buffer *sb = 113b8e80941Smrg _mesa_string_buffer_create(ctx, INITIAL_PP_OUTPUT_BUF_SIZE); 114b8e80941Smrg 115b8e80941Smrg const char *backslash, *newline, *search_start; 116b8e80941Smrg const char *cr, *lf; 117b8e80941Smrg char newline_separator[3]; 118b8e80941Smrg int collapsed_newlines = 0; 119b8e80941Smrg int separator_len; 120b8e80941Smrg 121b8e80941Smrg backslash = strchr(shader, '\\'); 122b8e80941Smrg 123b8e80941Smrg /* No line continuations were found in this shader, our job is done */ 124b8e80941Smrg if (backslash == NULL) 125b8e80941Smrg return (char *) shader; 126b8e80941Smrg 127b8e80941Smrg search_start = shader; 128b8e80941Smrg 129b8e80941Smrg /* Determine what flavor of newlines this shader is using. GLSL 130b8e80941Smrg * provides for 4 different possible ways to separate lines, (using 131b8e80941Smrg * one or two characters): 132b8e80941Smrg * 133b8e80941Smrg * "\n" (line-feed, like Linux, Unix, and new Mac OS) 134b8e80941Smrg * "\r" (carriage-return, like old Mac files) 135b8e80941Smrg * "\r\n" (carriage-return + line-feed, like DOS files) 136b8e80941Smrg * "\n\r" (line-feed + carriage-return, like nothing, really) 137b8e80941Smrg * 138b8e80941Smrg * This code explicitly supports a shader that uses a mixture of 139b8e80941Smrg * newline terminators and will properly handle line continuation 140b8e80941Smrg * backslashes followed by any of the above. 141b8e80941Smrg * 142b8e80941Smrg * But, since we must also insert additional newlines in the output 143b8e80941Smrg * (for any collapsed lines) we attempt to maintain consistency by 144b8e80941Smrg * examining the first encountered newline terminator, and using the 145b8e80941Smrg * same terminator for any newlines we insert. 146b8e80941Smrg */ 147b8e80941Smrg cr = strchr(search_start, '\r'); 148b8e80941Smrg lf = strchr(search_start, '\n'); 149b8e80941Smrg 150b8e80941Smrg newline_separator[0] = '\n'; 151b8e80941Smrg newline_separator[1] = '\0'; 152b8e80941Smrg newline_separator[2] = '\0'; 153b8e80941Smrg 154b8e80941Smrg if (cr == NULL) { 155b8e80941Smrg /* Nothing to do. */ 156b8e80941Smrg } else if (lf == NULL) { 157b8e80941Smrg newline_separator[0] = '\r'; 158b8e80941Smrg } else if (lf == cr + 1) { 159b8e80941Smrg newline_separator[0] = '\r'; 160b8e80941Smrg newline_separator[1] = '\n'; 161b8e80941Smrg } else if (cr == lf + 1) { 162b8e80941Smrg newline_separator[0] = '\n'; 163b8e80941Smrg newline_separator[1] = '\r'; 164b8e80941Smrg } 165b8e80941Smrg separator_len = strlen(newline_separator); 166b8e80941Smrg 167b8e80941Smrg while (true) { 168b8e80941Smrg /* If we have previously collapsed any line-continuations, 169b8e80941Smrg * then we want to insert additional newlines at the next 170b8e80941Smrg * occurrence of a newline character to avoid changing any 171b8e80941Smrg * line numbers. 172b8e80941Smrg */ 173b8e80941Smrg if (collapsed_newlines) { 174b8e80941Smrg cr = strchr (search_start, '\r'); 175b8e80941Smrg lf = strchr (search_start, '\n'); 176b8e80941Smrg if (cr && lf) 177b8e80941Smrg newline = cr < lf ? cr : lf; 178b8e80941Smrg else if (cr) 179b8e80941Smrg newline = cr; 180b8e80941Smrg else 181b8e80941Smrg newline = lf; 182b8e80941Smrg if (newline && 183b8e80941Smrg (backslash == NULL || newline < backslash)) 184b8e80941Smrg { 185b8e80941Smrg _mesa_string_buffer_append_len(sb, shader, 186b8e80941Smrg newline - shader + 1); 187b8e80941Smrg while (collapsed_newlines) { 188b8e80941Smrg _mesa_string_buffer_append_len(sb, 189b8e80941Smrg newline_separator, 190b8e80941Smrg separator_len); 191b8e80941Smrg collapsed_newlines--; 192b8e80941Smrg } 193b8e80941Smrg shader = skip_newline (newline); 194b8e80941Smrg search_start = shader; 195b8e80941Smrg } 196b8e80941Smrg } 197b8e80941Smrg 198b8e80941Smrg search_start = backslash + 1; 199b8e80941Smrg 200b8e80941Smrg if (backslash == NULL) 201b8e80941Smrg break; 202b8e80941Smrg 203b8e80941Smrg /* At each line continuation, (backslash followed by a 204b8e80941Smrg * newline), copy all preceding text to the output, then 205b8e80941Smrg * advance the shader pointer to the character after the 206b8e80941Smrg * newline. 207b8e80941Smrg */ 208b8e80941Smrg if (backslash[1] == '\r' || backslash[1] == '\n') 209b8e80941Smrg { 210b8e80941Smrg collapsed_newlines++; 211b8e80941Smrg _mesa_string_buffer_append_len(sb, shader, backslash - shader); 212b8e80941Smrg shader = skip_newline (backslash + 1); 213b8e80941Smrg search_start = shader; 214b8e80941Smrg } 215b8e80941Smrg 216b8e80941Smrg backslash = strchr(search_start, '\\'); 217b8e80941Smrg } 218b8e80941Smrg 219b8e80941Smrg _mesa_string_buffer_append(sb, shader); 220b8e80941Smrg 221b8e80941Smrg return sb->buf; 222b8e80941Smrg} 223b8e80941Smrg 224b8e80941Smrgint 225b8e80941Smrgglcpp_preprocess(void *ralloc_ctx, const char **shader, char **info_log, 226b8e80941Smrg glcpp_extension_iterator extensions, void *state, 227b8e80941Smrg struct gl_context *gl_ctx) 228b8e80941Smrg{ 229b8e80941Smrg int errors; 230b8e80941Smrg glcpp_parser_t *parser = 231b8e80941Smrg glcpp_parser_create(&gl_ctx->Extensions, extensions, state, gl_ctx->API); 232b8e80941Smrg 233b8e80941Smrg if (! gl_ctx->Const.DisableGLSLLineContinuations) 234b8e80941Smrg *shader = remove_line_continuations(parser, *shader); 235b8e80941Smrg 236b8e80941Smrg glcpp_lex_set_source_string (parser, *shader); 237b8e80941Smrg 238b8e80941Smrg glcpp_parser_parse (parser); 239b8e80941Smrg 240b8e80941Smrg if (parser->skip_stack) 241b8e80941Smrg glcpp_error (&parser->skip_stack->loc, parser, "Unterminated #if\n"); 242b8e80941Smrg 243b8e80941Smrg glcpp_parser_resolve_implicit_version(parser); 244b8e80941Smrg 245b8e80941Smrg ralloc_strcat(info_log, parser->info_log->buf); 246b8e80941Smrg 247b8e80941Smrg /* Crimp the buffer first, to conserve memory */ 248b8e80941Smrg _mesa_string_buffer_crimp_to_fit(parser->output); 249b8e80941Smrg 250b8e80941Smrg ralloc_steal(ralloc_ctx, parser->output->buf); 251b8e80941Smrg *shader = parser->output->buf; 252b8e80941Smrg 253b8e80941Smrg errors = parser->error; 254b8e80941Smrg glcpp_parser_destroy (parser); 255b8e80941Smrg return errors; 256b8e80941Smrg} 257