]> git.saurik.com Git - bison.git/blame - src/location.c
c++: support wide strings for file names
[bison.git] / src / location.c
CommitLineData
8efe435c 1/* Locations for Bison
6e30ede8 2
c932d613 3 Copyright (C) 2002, 2005-2012 Free Software Foundation, Inc.
8efe435c
AD
4
5 This file is part of Bison, the GNU Compiler Compiler.
6
f16b0819 7 This program is free software: you can redistribute it and/or modify
8efe435c 8 it under the terms of the GNU General Public License as published by
f16b0819
PE
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
8efe435c 11
f16b0819 12 This program is distributed in the hope that it will be useful,
8efe435c
AD
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
f16b0819 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
8efe435c 19
2cec9080 20#include <config.h>
1a715ef2 21#include "system.h"
81ebdef9 22
0c8e079f 23#include <mbswidth.h>
b17a1fc5 24#include <quotearg.h>
8efe435c 25
0c8e079f 26#include "complain.h"
81ebdef9
PE
27#include "location.h"
28
28e52c0d 29location const empty_location = EMPTY_LOCATION_INIT;
b17a1fc5 30
e9071366
AD
31/* If BUF is null, add BUFSIZE (which in this case must be less than
32 INT_MAX) to COLUMN; otherwise, add mbsnwidth (BUF, BUFSIZE, 0) to
33 COLUMN. If an overflow occurs, or might occur but is undetectable,
34 return INT_MAX. Assume COLUMN is nonnegative. */
35
36static inline int
37add_column_width (int column, char const *buf, size_t bufsize)
38{
39 size_t width;
40 unsigned int remaining_columns = INT_MAX - column;
41
42 if (buf)
43 {
44 if (INT_MAX / 2 <= bufsize)
45 return INT_MAX;
46 width = mbsnwidth (buf, bufsize, 0);
47 }
48 else
49 width = bufsize;
50
51 return width <= remaining_columns ? column + width : INT_MAX;
52}
53
54/* Set *LOC and adjust scanner cursor to account for token TOKEN of
55 size SIZE. */
56
57void
58location_compute (location *loc, boundary *cur, char const *token, size_t size)
59{
60 int line = cur->line;
61 int column = cur->column;
62 char const *p0 = token;
63 char const *p = token;
64 char const *lim = token + size;
65
66 loc->start = *cur;
67
68 for (p = token; p < lim; p++)
69 switch (*p)
70 {
71 case '\n':
72 line += line < INT_MAX;
73 column = 1;
74 p0 = p + 1;
75 break;
76
77 case '\t':
78 column = add_column_width (column, p0, p - p0);
79 column = add_column_width (column, NULL, 8 - ((column - 1) & 7));
80 p0 = p + 1;
81 break;
82
83 default:
84 break;
85 }
86
87 cur->line = line;
88 cur->column = column = add_column_width (column, p0, p - p0);
89
90 loc->end = *cur;
91
92 if (line == INT_MAX && loc->start.line != INT_MAX)
93 warn_at (*loc, _("line number overflow"));
94 if (column == INT_MAX && loc->start.column != INT_MAX)
95 warn_at (*loc, _("column number overflow"));
96}
97
98
b17a1fc5
PE
99/* Output to OUT the location LOC.
100 Warning: it uses quotearg's slot 3. */
348f5608 101unsigned
81ebdef9 102location_print (FILE *out, location loc)
b17a1fc5 103{
348f5608 104 unsigned res = 0;
580c075d 105 int end_col = 0 != loc.end.column ? loc.end.column - 1 : 0;
348f5608
AR
106 res += fprintf (out, "%s",
107 quotearg_n_style (3, escape_quoting_style, loc.start.file));
580c075d
JD
108 if (0 <= loc.start.line)
109 {
4c36bc2b 110 res += fprintf (out, ":%d", loc.start.line);
580c075d 111 if (0 <= loc.start.column)
348f5608 112 res += fprintf (out, ".%d", loc.start.column);
580c075d 113 }
b17a1fc5 114 if (loc.start.file != loc.end.file)
580c075d 115 {
348f5608
AR
116 res += fprintf (out, "-%s",
117 quotearg_n_style (3, escape_quoting_style,
118 loc.end.file));
580c075d
JD
119 if (0 <= loc.end.line)
120 {
4c36bc2b 121 res += fprintf (out, ":%d", loc.end.line);
580c075d 122 if (0 <= end_col)
348f5608 123 res += fprintf (out, ".%d", end_col);
580c075d
JD
124 }
125 }
126 else if (0 <= loc.end.line)
127 {
128 if (loc.start.line < loc.end.line)
129 {
348f5608 130 res += fprintf (out, "-%d", loc.end.line);
580c075d 131 if (0 <= end_col)
348f5608 132 res += fprintf (out, ".%d", end_col);
580c075d
JD
133 }
134 else if (0 <= end_col && loc.start.column < end_col)
348f5608 135 res += fprintf (out, "-%d", end_col);
580c075d 136 }
348f5608
AR
137
138 return res;
b17a1fc5 139}
3fc65ead 140
3f5d1b2c
TR
141
142/* Persistant data used by location_caret to avoid reopening and rereading the
143 same file all over for each error. */
144struct caret_info
145{
146 FILE* source;
147 size_t line;
148 size_t offset;
149};
150
151static struct caret_info caret_info = { NULL, 1, 0 };
152
153/* Free any allocated ressources and close any open file handles that are
154 left-over by the usage of location_caret. */
155void
156cleanup_caret ()
157{
158 if (caret_info.source)
159 fclose (caret_info.source);
160}
161
162/* Output to OUT the line and caret corresponding to location LOC. */
163void
164location_caret (FILE *out, location loc)
165{
166 /* FIXME: find a way to support X-file locations, and only open once each
167 file. That would make the procedure future-proof. */
168 if (! (caret_info.source
169 || (caret_info.source = fopen (loc.start.file, "r")))
170 || loc.start.column == -1 || loc.start.line == -1)
171 return;
172
173 /* If the line we want to quote is seekable (the same line as the previous
174 location), just seek it. If it was before, we lost track of it, so
175 return to the start of file. */
176 if (caret_info.line <= loc.start.line)
177 fseek (caret_info.source, caret_info.offset, SEEK_SET);
178 else
179 {
180 caret_info.line = 1;
181 caret_info.offset = 0;
182 fseek (caret_info.source, caret_info.offset, SEEK_SET);
183 }
184
185 /* Advance to the line's position, keeping track of the offset. */
186 {
187 int i;
188 for (i = caret_info.line; i < loc.start.line; caret_info.offset++)
189 if (fgetc (caret_info.source) == '\n')
190 ++i;
191 }
192 caret_info.line = loc.start.line;
193
194 /* Read the actual line. Don't update the offset, so that we keep a pointer
195 to the start of the line. */
196 {
197 ssize_t len = 0;
198 char *buf = NULL;
199 if ((len = getline (&buf, (size_t*) &len, caret_info.source)) != -1)
200 {
201 /* The caret of a multiline location ends with the first line. */
202 int end = loc.start.line != loc.end.line ? len : loc.end.column;
203
204 if (len)
205 {
206 int i = loc.start.column;
207 /* Quote the file, indent by a single column. */
208 fputc (' ', out);
209 fwrite (buf, 1, len, out);
210
211 /* Print the caret, with the same indent as above. */
212 fputc (' ', out);
213 fprintf (out, "%*s", loc.start.column - 1, "");
214 do {
215 fputc ('^', out);
216 } while (++i < end);
217 }
218 fputc ('\n', out);
219 free (buf);
220 }
221 }
222}
223
3fc65ead
JD
224void
225boundary_set_from_string (boundary *bound, char *loc_str)
226{
227 /* Must search in reverse since the file name field may
228 * contain `.' or `:'. */
d143e9c3 229 char *delim = mbsrchr (loc_str, '.');
3fc65ead
JD
230 aver (delim);
231 *delim = '\0';
232 bound->column = atoi (delim+1);
d143e9c3 233 delim = mbsrchr (loc_str, ':');
3fc65ead
JD
234 aver (delim);
235 *delim = '\0';
236 bound->line = atoi (delim+1);
237 bound->file = uniqstr_new (loc_str);
238}