#include "config.hh"
+#if HAVE_UTF8_WCHAR_H
+#include <utf8/wchar.h> /* mbrtowc */
+#else
+#include <wchar.h> /* mbrtowc */
+#endif
+
#include <cstdio>
+
#if HAVE_SSTREAM
#include <sstream>
#else
int
Source_file::tell () const
{
- return pos_str0_ - contents_str0_;
+ return pos_str0_ - contents_str0_;
}
std::istream*
if (!to_str0 ())
return " (" + _ ("position unknown") + ")";
else
- return name_string () + ":" + to_string (get_line (context_str0))
- + ":" + to_string (get_char (context_str0));
+ {
+ int l, ch, col;
+ get_counts (context_str0, &l, &ch, &col);
+
+ return name_string () + ":" + to_string (l)
+ + ":" + to_string (col);
+ }
+}
+
+
+
+String
+Source_file::quote_input (char const* pos_str0) const
+{
+ if (!contains (pos_str0))
+ return " (" + _ ("position unknown") + ")";
+
+ int l, ch, col;
+ get_counts (pos_str0, &l, &ch, &col);
+ String line = line_string (pos_str0);
+ String context = line.left_string (ch)
+ + to_string ('\n')
+ + to_string (' ', col)
+ + line.cut_string (ch, INT_MAX);
+ return context;
}
String
return String ((Byte const *)data_str0 + line[LEFT], line.length ());
}
-int
-Source_file::get_char (char const *pos_str0) const
-{
- if (!contains (pos_str0))
- return 0;
- char const *data_str0 = to_str0 ();
- return pos_str0 - (line_slice (pos_str0)[SMALLER] + data_str0);
-}
-
-int
-Source_file::get_column (char const *pos_str0) const
+void
+Source_file::get_counts (char const *pos_str0,
+ int *line_number,
+ int *line_char,
+ int *column) const
{
if (!contains (pos_str0))
- return 0;
+ return;
- int ch_i = get_char (pos_str0);
- String line = line_string (pos_str0);
+ *line_number = get_line (pos_str0);
+
+ Slice line = line_slice (pos_str0);
+ char const *data = to_str0 ();
+ Byte const *line_start = (Byte const *)data + line[LEFT];
- int col_i = 0;
- for (int i = 0; i < ch_i; i++)
- if (line[i] == '\t')
- col_i = (col_i / 8 + 1) * 8;
- else
- col_i++;
+ int left = (Byte const*) pos_str0 - line_start;
+ String line_begin (line_start, left);
+ char const *line_chars = line_begin.to_str0();
+
+ *column = 0;
+ *line_char = 0;
+
+ mbstate_t state;
- return col_i;
-}
+ /* Initialize the state. */
+ memset (&state, '\0', sizeof (state));
-String
-Source_file::error_string (char const* pos_str0) const
-{
- if (!contains (pos_str0))
- return " (" + _ ("position unknown") + ")";
+ while (left > 0)
+ {
+ wchar_t multibyte[2];
+
+ /*
+ FIXME, this is apparently locale dependent.
+ */
+ size_t thislen = mbrtowc (multibyte, line_chars, left, &state);
+
+ /* Stop converting at invalid character;
+ this can mean we have read just the first part
+ of a valid character. */
+ if (thislen == (size_t) -1)
+ break;
+
+ /* We want to handle embedded NUL bytes
+ but the return value is 0. Correct this. */
+ if (thislen == 0)
+ thislen = 1;
+
+ if (thislen == 1 && line_chars[0] == '\t')
+ (*column) = (*column / 8 + 1) * 8;
+ else
+ (*column) ++;
- int ch_i = get_char (pos_str0);
- String line = line_string (pos_str0);
- String context = line.left_string (ch_i)
- + to_string ('\n')
- + to_string (' ', get_column (pos_str0))
- + line.cut_string (ch_i, INT_MAX);
+ (*line_char) ++;
+ /* Advance past this character. */
+ line_chars += thislen;
+ left -= thislen;
+ }
- return context;
-}
+}
bool
Source_file::contains (char const* pos_str0) const
{
if (contains (pos_str0))
pos_str0_ = pos_str0;
else
- error (error_string (pos_str0) + "invalid pos");
+ error (quote_input (pos_str0) + "invalid pos");
}
char const *
if (contains (new_str0))
pos_str0_ = new_str0;
else
- error (error_string (new_str0) + "seek past eof");
+ error (quote_input (new_str0) + "seek past eof");
return pos_str0_;
}
if (contains (new_str0))
pos_str0_ = new_str0;
else
- error (error_string (new_str0) + "forward past eof");
+ error (quote_input (new_str0) + "forward past eof");
return old_pos;
}