Vcsn  2.5.dev
Be Rational
stream.cc
Go to the documentation of this file.
1 #include <vcsn/misc/stream.hh>
2 
3 #include <cassert>
4 #include <cstring> // strerror
5 #include <istream>
6 #include <fstream>
7 
8 #include <vcsn/misc/raise.hh>
9 
10 namespace vcsn
11 {
12 
13  std::ostream cnull{nullptr};
14  std::wostream wcnull{nullptr};
15 
16  std::string
17  bracketed(std::istream& i, const char lbracket, const char rbracket)
18  {
19  assert(i.peek() == lbracket);
20  i.ignore();
21  size_t level = 1;
22  std::ostringstream o;
23  int c;
24  while ((c = i.get()) != -1)
25  {
26  if (c == lbracket)
27  ++level;
28  else if (c == rbracket
29  && !--level)
30  return o.str();
31  o << char(c);
32  }
33  raise("missing ", str_escape(rbracket), " after ",
34  str_escape(lbracket), o.str());
35  }
36 
37 
38  bool
39  equal_files(const std::string& fn1, const std::string& fn2)
40  {
41  std::ifstream f1(fn1, std::ifstream::binary|std::ifstream::ate);
42  std::ifstream f2(fn2, std::ifstream::binary|std::ifstream::ate);
43 
44  if (f1.fail() || f2.fail())
45  return false;
46 
47  if (f1.tellg() != f2.tellg())
48  return false;
49 
50  f1.seekg(0, std::ifstream::beg);
51  f2.seekg(0, std::ifstream::beg);
52  return std::equal(std::istreambuf_iterator<char>(f1.rdbuf()),
53  std::istreambuf_iterator<char>(),
54  std::istreambuf_iterator<char>(f2.rdbuf()));
55  }
56 
57 
58  std::string expand_tilda(const std::string& s)
59  {
60  auto res = s;
61  if (!res.empty() && res[0] == '~')
62  {
63  assert(res.size() == 1 || res[1] == '/');
64  auto home = xgetenv("HOME", xgetenv("USERPROFILE"));
65  char const *hdrive = getenv("HOMEDRIVE");
66  char const *hres = getenv("HOMERES");
67  if (!home.empty())
68  res.replace(0, 1, home);
69  else if (hdrive && hres)
70  res.replace(0, 1, std::string(hdrive) + hres);
71  else
72  res.replace(0, 1, xgetenv("VCSN_TMPDIR", "/tmp"));
73  }
74  return res;
75  }
76 
77  char get_char(std::istream& i)
78  {
79  int res = i.get();
80  if (res == '\\')
81  switch (int c = i.get())
82  {
83  // Usual escapes.
84 #define CASE(Key, Value) \
85  case Key: res = Value; i.ignore(); break
86  CASE('a', '\a');
87  CASE('b', '\b');
88  CASE('f', '\f');
89  CASE('n', '\n');
90  CASE('r', '\r');
91  CASE('t', '\t');
92  CASE('v', '\v');
93 #undef CASE
94 
95  // Hexadecimal escapes.
96  case 'x':
97  {
98  // Handle hexadecimal escape.
99  int c1 = i.get();
100  require(c1 != EOF,
101  "get_char: unexpected end-of-file"
102  " after: \\x");
103  require(isxdigit(c1),
104  "get_char: invalid escape: \\x", char(c1));
105  int c2 = i.get();
106  require(c2 != EOF,
107  "get_char: unexpected end-of-file"
108  " after: \\x", char(c1));
109  require(isxdigit(c2),
110  "get_char: invalid escape: \\x",
111  char(c1), char(c2));
112  res = std::stoi(std::string{char(c1), char(c2)}, nullptr, 16);
113  }
114  break;
115 
116  // Other escapes, e.g., \\, \", \', etc. \(, \) and \-
117  // are used in setalpha::make, e.g., char_letters(\(\-\)).
118  default:
119  require(!std::isalnum(c),
120  "get_char: invalid escape: \\", char(c), " in \\",
121  char(c), i);
122  res = c;
123  break;
124  }
125  require(res != EOF,
126  "get_char: unexpected end-of-file");
127  return res;
128  }
129 
130  char eat(std::istream& is, char c)
131  {
132  if (is.peek() == c)
133  {
134  is.ignore();
135  return c;
136  }
137  else
138  fail_reading(is, "expected ", str_escape(c), ", got");
139  }
140 
141  const std::string& eat(std::istream& is, const std::string& expect)
142  {
143  std::string s;
144  char c;
145  size_t cnt = expect.size();
146  while (cnt && is >> c)
147  {
148  s.append(1, c);
149  --cnt;
150  }
151  VCSN_REQUIRE(s == expect,
152  "unexpected: ", str_escape(s),
153  ": expected ", str_escape(expect));
154  return expect;
155  }
156 
157  // http://stackoverflow.com/questions/2602013.
158  std::string
159  get_file_contents(const std::string& file)
160  {
161  std::ifstream in(file.c_str(), std::ios::in | std::ios::binary);
162  VCSN_REQUIRE(in.good(), "cannot read file: ", file, ": ", strerror(errno));
163 
164  std::string res;
165  in.seekg(0, std::ios::end);
166  res.resize(in.tellg());
167  in.seekg(0, std::ios::beg);
168  in.read(&res[0], res.size());
169  in.close();
170  return res;
171  }
172 
173  std::shared_ptr<std::istream>
174  open_input_file(const std::string& file)
175  {
176  std::shared_ptr<std::istream> res;
177  if (file.empty() || file == "-")
178  res.reset(&std::cin, [](...){});
179  else
180  {
181  res.reset(new std::ifstream(file.c_str()));
182  VCSN_REQUIRE(res->good(),
183  "cannot open ", file, " for reading: ", strerror(errno));
184  }
185  return res;
186  }
187 
188  std::shared_ptr<std::ostream>
189  open_output_file(const std::string& file)
190  {
191  std::shared_ptr<std::ostream> res;
192  if (file.empty() || file == "-")
193  res.reset(&std::cout, [](...){});
194  else
195  {
196  res.reset(new std::ofstream(file.c_str()));
197  VCSN_REQUIRE(res->good(),
198  "cannot open ", file, " for writing: ", strerror(errno));
199  }
200  return res;
201  }
202 
203  void skip_space(std::istream& is)
204  {
205  while (isspace(is.peek()))
206  is.ignore();
207  }
208 
209  std::string
210  xgetenv(const std::string& var, const std::string& val)
211  {
212  const char* cp = getenv(var.c_str());
213  return cp ? cp : val;
214  }
215 }
std::wostream wcnull
An wide-char stream that discards the output.
Definition: stream.cc:14
std::shared_ptr< std::ostream > open_output_file(const std::string &file)
Open file for writing and return its autoclosing stream.
Definition: stream.cc:189
std::shared_ptr< std::istream > open_input_file(const std::string &file)
Open file for reading and return its autoclosing stream.
Definition: stream.cc:174
bool equal_files(const std::string &fn1, const std::string &fn2)
Whether two files have exactly equal contents.
Definition: stream.cc:39
char get_char(std::istream &i)
Read a single char, with possible -escape support.
Definition: stream.cc:77
#define VCSN_REQUIRE(Cond,...)
A macro similar to require.
Definition: raise.hh:102
auto in(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions arriving to state s.
Definition: automaton.hh:135
return res
Definition: multiply.hh:399
weightset_mixin< detail::f2_impl > f2
Definition: fwd.hh:49
char eat(std::istream &is, char c)
Check lookahead character and advance.
Definition: stream.cc:130
std::string expand_tilda(const std::string &res)
Expand initial "~" in res.
Definition: stream.cc:58
std::string xgetenv(const std::string &var, const std::string &val="")
getenv(var) if defined, otherwise val.
Definition: stream.cc:210
ATTRIBUTE_NORETURN void fail_reading(std::istream &is, Args &&... args)
Throw an exception after failing to read from is.
Definition: stream.hh:76
std::ostream cnull
An narrow-char stream that discards the output.
Definition: stream.cc:13
void require(Bool b, Args &&... args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:91
Definition: a-star.hh:8
#define CASE(Key, Value)
void skip_space(std::istream &is)
Ignore spaces.
Definition: stream.cc:203
std::string bracketed(std::istream &i, char lbracket, char rbracket)
Extract the string which is here between lbracket and rbracket.
Definition: stream.cc:17
std::string get_file_contents(const std::string &file)
Return the contents of file.
Definition: stream.cc:159
std::ostream & str_escape(std::ostream &os, const std::string &str, const char *special=nullptr)
Output a string, escaping special characters.
Definition: escape.cc:51