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