1cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project/* Locations for Bison
2cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Copyright (C) 2002, 2005-2012 Free Software Foundation, Inc.
4cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
5cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   This file is part of Bison, the GNU Compiler Compiler.
6cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is free software: you can redistribute it and/or modify
8cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   it under the terms of the GNU General Public License as published by
905436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the Free Software Foundation, either version 3 of the License, or
1005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   (at your option) any later version.
11cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
1205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is distributed in the hope that it will be useful,
13cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   but WITHOUT ANY WARRANTY; without even the implied warranty of
14cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   GNU General Public License for more details.
16cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
17cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   You should have received a copy of the GNU General Public License
1805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
20cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project#include <config.h>
21cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project#include "system.h"
22cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
2305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <mbswidth.h>
24cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project#include <quotearg.h>
25cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
2605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "complain.h"
27cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project#include "location.h"
28cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
2905436638acc7c010349a69c3395f1a57c642dc62Ying Wanglocation const empty_location = EMPTY_LOCATION_INIT;
3005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* If BUF is null, add BUFSIZE (which in this case must be less than
3205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   INT_MAX) to COLUMN; otherwise, add mbsnwidth (BUF, BUFSIZE, 0) to
3305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   COLUMN.  If an overflow occurs, or might occur but is undetectable,
3405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   return INT_MAX.  Assume COLUMN is nonnegative.  */
3505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3605436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic inline int
3705436638acc7c010349a69c3395f1a57c642dc62Ying Wangadd_column_width (int column, char const *buf, size_t bufsize)
3805436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
3905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  size_t width;
4005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  unsigned int remaining_columns = INT_MAX - column;
4105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (buf)
4305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
4405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (INT_MAX / 2 <= bufsize)
4505436638acc7c010349a69c3395f1a57c642dc62Ying Wang	return INT_MAX;
4605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      width = mbsnwidth (buf, bufsize, 0);
4705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
4805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
4905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    width = bufsize;
5005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return width <= remaining_columns ? column + width : INT_MAX;
5205436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
5305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5405436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Set *LOC and adjust scanner cursor to account for token TOKEN of
5505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   size SIZE.  */
5605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5705436638acc7c010349a69c3395f1a57c642dc62Ying Wangvoid
5805436638acc7c010349a69c3395f1a57c642dc62Ying Wanglocation_compute (location *loc, boundary *cur, char const *token, size_t size)
5905436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
6005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int line = cur->line;
6105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int column = cur->column;
6205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  char const *p0 = token;
6305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  char const *p = token;
6405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  char const *lim = token + size;
6505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  loc->start = *cur;
6705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  for (p = token; p < lim; p++)
6905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    switch (*p)
7005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
7105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      case '\n':
7205436638acc7c010349a69c3395f1a57c642dc62Ying Wang	line += line < INT_MAX;
7305436638acc7c010349a69c3395f1a57c642dc62Ying Wang	column = 1;
7405436638acc7c010349a69c3395f1a57c642dc62Ying Wang	p0 = p + 1;
7505436638acc7c010349a69c3395f1a57c642dc62Ying Wang	break;
7605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      case '\t':
7805436638acc7c010349a69c3395f1a57c642dc62Ying Wang	column = add_column_width (column, p0, p - p0);
7905436638acc7c010349a69c3395f1a57c642dc62Ying Wang	column = add_column_width (column, NULL, 8 - ((column - 1) & 7));
8005436638acc7c010349a69c3395f1a57c642dc62Ying Wang	p0 = p + 1;
8105436638acc7c010349a69c3395f1a57c642dc62Ying Wang	break;
8205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      default:
8405436638acc7c010349a69c3395f1a57c642dc62Ying Wang	break;
8505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }
8605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  cur->line = line;
8805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  cur->column = column = add_column_width (column, p0, p - p0);
8905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  loc->end = *cur;
9105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (line == INT_MAX && loc->start.line != INT_MAX)
9305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    warn_at (*loc, _("line number overflow"));
9405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (column == INT_MAX && loc->start.column != INT_MAX)
9505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    warn_at (*loc, _("column number overflow"));
9605436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
9705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
98cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project
99cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project/* Output to OUT the location LOC.
100cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project   Warning: it uses quotearg's slot 3.  */
10105436638acc7c010349a69c3395f1a57c642dc62Ying Wangunsigned
102cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Projectlocation_print (FILE *out, location loc)
103cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project{
10405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  unsigned res = 0;
10505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int end_col = 0 != loc.end.column ? loc.end.column - 1 : 0;
10605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  res += fprintf (out, "%s",
10705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  quotearg_n_style (3, escape_quoting_style, loc.start.file));
10805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (0 <= loc.start.line)
10905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
11005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      res += fprintf (out, ":%d", loc.start.line);
11105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (0 <= loc.start.column)
11205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        res += fprintf (out, ".%d", loc.start.column);
11305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
114cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project  if (loc.start.file != loc.end.file)
11505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
11605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      res += fprintf (out, "-%s",
11705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      quotearg_n_style (3, escape_quoting_style,
11805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                        loc.end.file));
11905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (0 <= loc.end.line)
12005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
12105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          res += fprintf (out, ":%d", loc.end.line);
12205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (0 <= end_col)
12305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            res += fprintf (out, ".%d", end_col);
12405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
12505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
12605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else if (0 <= loc.end.line)
12705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
12805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (loc.start.line < loc.end.line)
12905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
13005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          res += fprintf (out, "-%d", loc.end.line);
13105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (0 <= end_col)
13205436638acc7c010349a69c3395f1a57c642dc62Ying Wang            res += fprintf (out, ".%d", end_col);
13305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
13405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else if (0 <= end_col && loc.start.column < end_col)
13505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        res += fprintf (out, "-%d", end_col);
13605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
13705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return res;
13905436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
14005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
14105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
14205436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Persistant data used by location_caret to avoid reopening and rereading the
14305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   same file all over for each error.  */
14405436638acc7c010349a69c3395f1a57c642dc62Ying Wangstruct caret_info
14505436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
14605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  FILE *source;
14705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  size_t line;
14805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  size_t offset;
14905436638acc7c010349a69c3395f1a57c642dc62Ying Wang};
15005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15105436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic struct caret_info caret_info = { NULL, 1, 0 };
15205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15305436638acc7c010349a69c3395f1a57c642dc62Ying Wangvoid
15405436638acc7c010349a69c3395f1a57c642dc62Ying Wangcleanup_caret ()
15505436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
15605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (caret_info.source)
15705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    fclose (caret_info.source);
15805436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
15905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
16005436638acc7c010349a69c3395f1a57c642dc62Ying Wangvoid
16105436638acc7c010349a69c3395f1a57c642dc62Ying Wanglocation_caret (FILE *out, location loc)
16205436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
16305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* FIXME: find a way to support multifile locations, and only open once each
16405436638acc7c010349a69c3395f1a57c642dc62Ying Wang     file. That would make the procedure future-proof.  */
16505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (! (caret_info.source
16605436638acc7c010349a69c3395f1a57c642dc62Ying Wang         || (caret_info.source = fopen (loc.start.file, "r")))
16705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      || loc.start.column == -1 || loc.start.line == -1)
16805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    return;
16905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
17005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* If the line we want to quote is seekable (the same line as the previous
17105436638acc7c010349a69c3395f1a57c642dc62Ying Wang     location), just seek it. If it was before, we lost track of it, so
17205436638acc7c010349a69c3395f1a57c642dc62Ying Wang     return to the start of file.  */
17305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (caret_info.line <= loc.start.line)
17405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    fseek (caret_info.source, caret_info.offset, SEEK_SET);
17505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  else
17605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
17705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      caret_info.line = 1;
17805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      caret_info.offset = 0;
17905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      fseek (caret_info.source, caret_info.offset, SEEK_SET);
18005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
18105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
18205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Advance to the line's position, keeping track of the offset.  */
18305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  while (caret_info.line < loc.start.line)
18405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    caret_info.line += fgetc (caret_info.source) == '\n';
18505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  caret_info.offset = ftell (caret_info.source);
18605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
18705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Read the actual line.  Don't update the offset, so that we keep a pointer
18805436638acc7c010349a69c3395f1a57c642dc62Ying Wang     to the start of the line.  */
18905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  {
19005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    char *buf = NULL;
19105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    size_t size = 0;
19205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    ssize_t len = getline (&buf, &size, caret_info.source);
19305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (0 < len)
19405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
19505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* The caret of a multiline location ends with the first line.  */
19605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        int end = loc.start.line != loc.end.line ? len : loc.end.column;
19705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
19805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* Quote the file, indent by a single column.  */
19905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        fputc (' ', out);
20005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        fwrite (buf, 1, len, out);
20105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
20205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* Print the caret, with the same indent as above.  */
20305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        fprintf (out, " %*s", loc.start.column - 1, "");
20405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
20505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          int i = loc.start.column;
20605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          do
20705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            fputc ('^', out);
20805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          while (++i < end);
20905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
21005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        fputc ('\n', out);
21105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }
21205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    free (buf);
21305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  }
21405436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
21505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
21605436638acc7c010349a69c3395f1a57c642dc62Ying Wangvoid
21705436638acc7c010349a69c3395f1a57c642dc62Ying Wangboundary_set_from_string (boundary *bound, char *loc_str)
21805436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
21905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Must search in reverse since the file name field may
22005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   * contain `.' or `:'.  */
22105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  char *delim = mbsrchr (loc_str, '.');
22205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  aver (delim);
22305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  *delim = '\0';
22405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  bound->column = atoi (delim+1);
22505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  delim = mbsrchr (loc_str, ':');
22605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  aver (delim);
22705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  *delim = '\0';
22805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  bound->line = atoi (delim+1);
22905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  bound->file = uniqstr_new (loc_str);
230cea198a11f15a2eb071d98491ca9a8bc8cebfbc4The Android Open Source Project}
231