glsl: Correctly handle line numbering.
[mesa.git] / src / glsl / pp / sl_pp_line.c
1 /**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include <stdlib.h>
29 #include "sl_pp_process.h"
30
31
32 static int
33 _parse_integer(const char *input,
34 unsigned int *number)
35 {
36 unsigned int n = 0;
37
38 while (*input >= '0' && *input <= '9') {
39 if (n * 10 < n) {
40 /* Overflow. */
41 return -1;
42 }
43
44 n = n * 10 + (*input++ - '0');
45 }
46
47 if (*input != '\0') {
48 /* Invalid decimal number. */
49 return -1;
50 }
51
52 *number = n;
53 return 0;
54 }
55
56
57 int
58 sl_pp_process_line(struct sl_pp_context *context,
59 const struct sl_pp_token_info *input,
60 unsigned int first,
61 unsigned int last,
62 struct sl_pp_process_state *pstate)
63 {
64 unsigned int i;
65 struct sl_pp_process_state state;
66 int line_number = -1;
67 int file_number = -1;
68 const char *str;
69 unsigned int line;
70
71 memset(&state, 0, sizeof(state));
72 for (i = first; i < last;) {
73 switch (input[i].token) {
74 case SL_PP_WHITESPACE:
75 i++;
76 break;
77
78 case SL_PP_IDENTIFIER:
79 if (sl_pp_macro_expand(context, input, &i, NULL, &state, 0)) {
80 free(state.out);
81 return -1;
82 }
83 break;
84
85 default:
86 if (sl_pp_process_out(&state, &input[i])) {
87 free(state.out);
88 return -1;
89 }
90 i++;
91 }
92 }
93
94 if (state.out_len > 0 && state.out[0].token == SL_PP_NUMBER) {
95 line_number = state.out[0].data.number;
96 } else {
97 strcpy(context->error_msg, "expected number after `#line'");
98 free(state.out);
99 return -1;
100 }
101
102 if (state.out_len > 1) {
103 if (state.out[1].token == SL_PP_NUMBER) {
104 file_number = state.out[1].data.number;
105 } else {
106 strcpy(context->error_msg, "expected number after line number");
107 free(state.out);
108 return -1;
109 }
110
111 if (state.out_len > 2) {
112 strcpy(context->error_msg, "expected end of line after file number");
113 free(state.out);
114 return -1;
115 }
116 }
117
118 free(state.out);
119
120 str = sl_pp_context_cstr(context, line_number);
121 if (_parse_integer(str, &line)) {
122 return -1;
123 }
124
125 if (context->line != line) {
126 struct sl_pp_token_info ti;
127
128 ti.token = SL_PP_LINE;
129 ti.data.line = line;
130 if (sl_pp_process_out(pstate, &ti)) {
131 return -1;
132 }
133 }
134
135 /* TODO: Do something with the file number. */
136
137 return 0;
138 }