Rheolef  7.2
an efficient C++ finite element environment
rheostream.cc
Go to the documentation of this file.
1 #include "rheolef/rheostream.h"
22 #include "rheolef/iorheo.h"
23 
24 #include "scatch.icc" // compile this code here, but is reused in field2bb
25 
26 #include <climits> // PATH_MAX ?
27 
28 #pragma GCC diagnostic push
29 #pragma GCC diagnostic ignored "-Weffc++"
30 #include <boost/iostreams/filter/gzip.hpp>
31 #include <boost/iostreams/device/file.hpp>
32 #pragma GCC diagnostic pop
33 
34 #ifdef _RHEOLEF_HAVE_UNISTD_H
35 #include<unistd.h> // readink()
36 #endif
37 
38 #ifdef _RHEOLEF_HAVE_SYMLINK_H
39 #include<symlink.h> // readink() on hpux9*
40 #endif
41 
42 #include<dirent.h> // opendir()
43 #include<sys/stat.h> // stat()
44 
45 #ifndef PATH_MAX
46 #define PATH_MAX 1023 // TODO: find it !
47 #endif // PATH_MAX
48 
49 namespace rheolef {
50 using namespace std;
51 namespace ios = boost::iostreams;
52 
53 std::string
55  char* c_tmpdir = std::getenv ("TMPDIR");
56  return (c_tmpdir == 0) ? "/tmp" : c_tmpdir;
57 }
58 string
59 ftos (const Float& x)
60 {
61  std::ostringstream out;
62  out << x;
63  return out.str ();
64 }
65 // -----------------------------------------------------------------
66 // output
67 // -----------------------------------------------------------------
68 orheostream::orheostream (const string& name, const string& suffix, io::mode_type mode)
69  : ios::filtering_stream<ios::output>(),
70  _mode(mode),
71  _full_name()
72 {
73  open (name, suffix, mode);
74 }
76 {
78 }
79 void
80 orheostream::open (const string& name, const string& suffix, io::mode_type mode)
81 {
82  _mode = mode;
83  // append the '.gz' suffix:
84  if (suffix.length() == 0) {
85  _full_name = delete_suffix(name, "gz");
86  } else {
87  _full_name = delete_suffix(delete_suffix(name, "gz"), suffix)
88  + "." + suffix;
89  }
90  if (!(mode & io::nogz)) {
91  _full_name = _full_name + ".gz";
92  }
94  bool verbose = iorheo::getverbose(clog);
95  if (verbose) {
96  std::string action = (mode & io::app) ? "appended" : "created";
97  clog << "! file \"" << _full_name << "\" " << action << endl;
98  }
99 }
100 void
102 {
103  using namespace ios;
104  // create the output pipe with the optional gzip filter:
105  if (!(mode & io::nogz)) {
106  filtering_stream<output>::push (gzip_compressor());
107  }
108  // open the file.gz:
109  std::ios_base::openmode om = std::ios_base::out | std::ios_base::binary;
110  if (mode & io::app) { om |= std::ios_base::app; }
111  file_sink ofs (_full_name.c_str(), om);
112  filtering_stream<output>::push (ofs);
113 }
114 void
116 {
117  using namespace ios;
118  if (filtering_stream<ios::output>::empty()) {
119  return;
120  }
121 #define _RHEOLEF_HAVE_BOOST_IOSTREAMS_GZIP_EMPTY_FILE_BUG
122 #ifdef _RHEOLEF_HAVE_BOOST_IOSTREAMS_GZIP_EMPTY_FILE_BUG
123  if (! (_mode & io::nogz)) {
124  *this << endl;
125  }
126 #endif // _RHEOLEF_HAVE_BOOST_IOSTREAMS_GZIP_EMPTY_FILE_BUG
127 #ifdef _RHEOLEF_HAVE_BOOST_IOSTREAMS_GZIP_EMPTY_FILE_BUG_OLD
128  if (! (_mode & io::nogz)) {
129  // bug with empty gziped boost::io: workaround by writting an empty thing !
130  // https://svn.boost.org/trac/boost/ticket/5237
131  // the previous fix is buggy: requires a non-empty thing: a newline that does not change rheolef semantic
132  trace_macro ("_close_internal: _full_name="<<_full_name<<": gziped => add a carriage return before closing...");
133  static char dummy = '\n'; // in rheolef, does not change the file format
134  static size_t length = 1; // instead of zero
135  filtering_stream<ios::output>::component<gzip_compressor>(0)->write(*filtering_stream<ios::output>::component<file_sink>(1), &dummy, length);
136  }
137 #endif // _RHEOLEF_HAVE_BOOST_IOSTREAMS_GZIP_EMPTY_FILE_BUG_OLD
138  while (! filtering_stream<ios::output>::empty()) {
139  filtering_stream<ios::output>::pop();
140  }
141 }
142 void
144 {
145  _close_internal();
146  _full_name = "";
147  _mode = io::out;
148 }
149 void
151 {
152  // boost::iostreams are not yet flushable when using gzip:
153  // thus close and re-open... it is a clostly procedure
154  _close_internal();
155  // then reopen: in append mode
157 }
158 // -----------------------------------------------------------------
159 // input
160 // -----------------------------------------------------------------
161 void
162 irheostream::open (const string& name, const string& suffix)
163 {
164  using namespace ios;
165 
166  // get full file path with the optional '.gz' suffix:
167  string full_name = get_full_name_from_rheo_path (name, suffix);
168  if (full_name.length() == 0) {
169  if (suffix.length() != 0) {
170  error_macro ("file \"" << name << "[." << suffix << "[.gz]]\" not found");
171  } else {
172  error_macro ("file \"" << name << "[.gz]\" not found");
173  }
174  }
175  // open the file[.gz]:
176  bool has_gz = has_suffix (full_name, "gz");
177  if (!has_gz) {
178  _ifs.open (full_name.c_str(), ios_base::in);
179  } else {
180  _ifs.open (full_name.c_str(), ios_base::in | ios_base::binary);
181  }
182  bool verbose = iorheo::getverbose(clog);
183  if (verbose) clog << "! load \"" << full_name << "\"\n";
184 
185  // create the input pipe with the optional gzip filter:
186  if (has_gz) {
187  filtering_stream<input>::push (gzip_decompressor());
188  }
189  filtering_stream<input>::push (_ifs);
190 }
191 void
193 {
194  using namespace ios;
195  while (! filtering_stream<ios::input>::empty()) {
196  filtering_stream<ios::input>::pop();
197  }
198  _ifs.close();
199 }
200 irheostream::irheostream (const string& name, const string& suffix)
201  : ios::filtering_stream<ios::input>(), _ifs()
202 {
203  open (name, suffix);
204 }
206 {
208 }
209 
210 // has_suffix("toto.suffix", "suffix") -> true
211 bool
212 has_suffix (const string& name, const string& suffix)
213 {
214  size_t ln = name.length();
215  size_t ls = suffix.length();
216  if (ln <= ls+1) return false;
217 
218  if (name[ln-ls-1] != '.') return false;
219  for (size_t i = ln-ls, j = 0; i < ln; i++, j++)
220  if (name [i] != suffix [j]) return false;
221 
222  return true;
223 }
224 // delete_suffix("toto.suffix", "suffix") --> "toto"
225 string
226 delete_suffix (const string& name, const string& suffix)
227 {
228  if (!has_suffix(name, suffix)) return name;
229  return string(name, 0, name.length() - suffix.length() - 1);
230 }
231 // has_any_suffix("toto.any_suffix") -> true
232 bool
233 has_any_suffix (const string& name)
234 {
235  size_t ln = name.length();
236  if (ln == 0) return false;
237  for (size_t i = ln-1; i > 0 && name[i] != '/'; --i)
238  if (name [i] == '.') return true;
239  return false;
240 }
241 // delete_any_suffix("toto.any_suffix") --> "toto"
242 string
243 delete_any_suffix (const string& name)
244 {
245  size_t ln = name.length();
246  if (ln == 0) return name;
247  size_t i_dot = 0;
248  for (size_t i = ln-1; i > 0 && name[i] != '/'; --i) {
249  if (name [i] == '.') {
250  i_dot = i;
251  break;
252  }
253  }
254  if (i_dot == 0) return name;
255  return string(name, 0, i_dot);
256 }
257 string
258 get_basename (const string& name)
259 {
260  string::size_type l = name.length();
261  string::size_type i = name.find_last_of ('/');
262  if (i >= l) return name;
263  string b = string(name, i+1, l-i-1);
264  return b;
265 }
266 string
267 get_dirname (const string& name)
268 {
269  string::size_type l = name.length();
270  string::size_type i = name.find_last_of ('/');
271  if (i >= l) return ".";
272  string d = string(name, 0, i);
273  return d;
274 }
275 //
276 // NOTE: path could have an iterator that points to
277 // a directory name...
278 //
279 // NOTE 2: global cstors in shared libraries are not
280 // handled by g++ and most compilers
281 // => need char* instead of string here
282 //
283 static const char* rheo_path_name = "RHEOPATH";
284 static const char* default_rheo_path = ".";
285 static char* rheo_path = 0;
286 
287 static
288 string
289 get_dir_from_path (const string& path, unsigned int& i_pos)
290 {
291  // is search path finished ?
292  unsigned int last = path.length();
293  if (i_pos >= last) {
294  return string();
295  }
296  // skip ':' separators
297  while (i_pos < last && path [i_pos] == ':')
298  i_pos++;
299 
300  // test end of path
301  if (i_pos == last) {
302  return string();
303  }
304  // path [i_pos] != ':' and i_pos < last, so we have a dir
305  unsigned int i_last = i_pos;
306  for (i_last = i_pos; i_last < last && path [i_last] != ':'; i_last++);
307  string current_dir;
308  if (i_last == last)
309  current_dir = string(path, i_pos, i_last-i_pos+1);
310  else
311  current_dir = string(path, i_pos, i_last-i_pos);
312 
313  // i_last == last || path[i_last] == ':'
314  i_pos = i_last;
315 
316  return current_dir;
317 }
318 static
319 void
320 init_rheo_path ()
321 {
322  // get directory path from environ
323  if (rheo_path) {
324  return;
325  }
326  const char *s1 = getenv (rheo_path_name);
327  if (!s1) {
328  s1 = default_rheo_path;
329  }
330  rheo_path = new_tab_macro(char, strlen(s1)+1);
331  strcpy (rheo_path, s1);
332 }
333 void
334 append_dir_to_rheo_path (const string& dir)
335 {
336  init_rheo_path();
337  string tmp = string(rheo_path) + ":" + dir;
338  delete_tab_macro(rheo_path);
339  rheo_path = new_tab_macro(char, strlen(tmp.c_str())+1);
340  strcpy (rheo_path, tmp.c_str());
341 }
342 void
343 prepend_dir_to_rheo_path (const string& dir)
344 {
345  init_rheo_path();
346  string tmp = dir + ":" + string(rheo_path);
347  delete_tab_macro(rheo_path);
348  rheo_path = new_tab_macro(char, strlen(tmp.c_str())+1);
349  strcpy (rheo_path, tmp.c_str());
350 }
351 static
352 bool
353 have_name_in_dir (const string& dir, const string& name, string& full_path)
354 {
355  string prefix;
356  if (dir != "") {
357  // trace_macro ("scanning in \"" << dir.c_str() << "\"");
358  prefix = dir + "/";
359  }
360  // try to open file like dir/rootname.suffix.gz
361  string zip_full_name = prefix + name + ".gz";
362  bool zip_status = file_exists (zip_full_name);
363 
364  // try to open file like dir/rootname.suffix
365  string unzip_full_name = prefix + name;
366  bool unzip_status = file_exists (unzip_full_name);
367 
368  if (unzip_status && zip_status) {
369  warning_macro ("both compressed and uncompressed files exists:");
370  warning_macro (" \"" << zip_full_name << "\"");
371  warning_macro ("and \"" << unzip_full_name << "\"");
372  error_macro ("unrecoverable ambiguous situation (HINT: rename one of these files)");
373  }
374  // prefer ziped than unziped version
375  if (zip_status) {
376  full_path = zip_full_name;
377  return true;
378  }
379  if (unzip_status) {
380  full_path = unzip_full_name;
381  return true;
382  }
383  // 15 oct 2000: check that "dir" is a valid directory
384  struct stat sd;
385  if (stat(dir.c_str(), &sd) != 0) {
386  warning_macro ("cannot not stat \"" << dir << "\"");
387  warning_macro ("hint: check "<< rheo_path_name << " or -I options");
388  return false;
389  }
390  if ((sd.st_mode & S_IFDIR) == 0) {
391  warning_macro ("invalid directory \"" << dir << "\"");
392  warning_macro ("hint: check "<< rheo_path_name << " or -I options");
393  return false;
394  }
395  // scan subdirs
396  DIR* d = opendir(dir.c_str());
397  if (!d) {
398  warning_macro ("cannot open directory \"" << dir << "\"");
399  warning_macro ("hint: check "<< rheo_path_name << " or -I options");
400  return false;
401  }
402  struct dirent* dp;
403  while ((dp = readdir(d)) != 0) {
404 
405  string subdir = dir + "/" + (dp -> d_name);
406 
407  if (strcmp(dp -> d_name, ".") == 0 ||
408  strcmp(dp -> d_name, "..") == 0) continue;
409 
410  struct stat s;
411  if (stat(subdir.c_str(), &s) != 0) {
412  warning_macro ("can not stat() for \"" << subdir << "\"");
413  continue;
414  }
415  if ((s.st_mode & S_IFLNK) == 0) {
416  // 16 january 1999: skip also symbolic links to "." and ".."
417  char linkname [PATH_MAX + 2];
418  // extern "C" int readlink(const char *, char *, int);
419  char* subdir_cstr = (char*)(subdir.c_str());
420  int linksize = readlink (subdir_cstr, linkname, PATH_MAX + 1);
421  // PATH_MAX = max number of characters in a pathname
422  // (not including terminating null)
423  //
424  // from fileutils-3.14/src/ls.c (line 1724):
425  // "Some automounters give incorrect st_size for mount points.
426  // I can't think of a good workaround for it, though."
427  //
428  if (linksize < 0) {
429  // perhaps not a symklink ?
430  // trace_macro ("can not read link name \"" << subdir << "\"");
431  } else {
432  linkname [linksize] = '\0';
433  if (strcmp(linkname, ".") == 0 ||
434  strcmp(linkname, "..") == 0) {
435  continue;
436  }
437  }
438  }
439  if ((s.st_mode & S_IFDIR) != 0) {
440  // recurse in subdir
441  if (have_name_in_dir (subdir, name, full_path)) {
442  return true;
443  }
444  }
445  }
446  return false;
447 }
448 string
449 get_full_name_from_rheo_path (const string& rootname, const string& suffix)
450 {
451  if (rootname == "") {
452  return rootname;
453  }
454  string name = delete_suffix(delete_suffix(rootname, "gz"), suffix);
455  if (suffix != "") name += "." + suffix;
456  string full_path;
457 
458  if (rootname [0] == '.' || rootname[0] == '/') {
459  if (have_name_in_dir ("", name, full_path)) {
460  return full_path;
461  }
462  return string();
463  }
464  //
465  // rootname has no explicit reference: use search path
466  //
467  init_rheo_path();
468  unsigned int i_dir = 0;
469  string dir = get_dir_from_path (rheo_path, i_dir);
470  while (dir.length() != 0) {
471 
472  if (have_name_in_dir (dir, name, full_path)) {
473  return full_path;
474  }
475  dir = get_dir_from_path (rheo_path, i_dir);
476  }
477  return string();
478 }
479 bool
480 is_float (const string& s)
481 {
482  // simple check for float argument
483  // EXP ([fFeEdD]([\-+])?([0-9]+))
484  // ([\-])?[0-9]+ |
485  // ([\-])?[0-9]+"."[0-9]*{EXP}?
486  // ([\-])?[0-9]*"."[0-9]+{EXP}?
487  // ([\-])?[0-9]+{EXP}
488  unsigned int l = s.length();
489  if (l < 1) return false;
490  if (!isdigit(s[0]) && s[0] != '-' && s[0] != '.') return false;
491  if (s[0] == '-') {
492  if (l < 2) return false;
493  if (!isdigit(s[1]) && s[1] != '.') return false;
494  }
495  return true;
496 }
497 Float
498 to_float (const string& s) {
499  // more robust than atof when Float=float128
500  stringstream ss(s);
501  Float x;
502  ss >> x;
503  return x;
504 }
505 
506 }// namespace rheolef
field::size_type size_type
Definition: branch.cc:430
see the Float page for the full documentation
virtual ~irheostream()
Definition: rheostream.cc:205
void open(const std::string &name, const std::string &suffix=std::string())
Definition: rheostream.cc:162
void _open_internal(io::mode_type mode)
Definition: rheostream.cc:101
io::mode_type _mode
Definition: rheostream.h:210
virtual ~orheostream()
Definition: rheostream.cc:75
std::string _full_name
Definition: rheostream.h:211
void open(const std::string &name, const std::string &suffix=std::string(), io::mode_type mode=io::out)
Definition: rheostream.cc:80
static const char * default_rheo_path
Definition: rheostream.cc:284
static char * rheo_path
Definition: rheostream.cc:285
static const char * rheo_path_name
Definition: rheostream.cc:283
static iorheo::force_initialization dummy
Definition: iorheo.cc:147
#define trace_macro(message)
Definition: dis_macros.h:111
#define error_macro(message)
Definition: dis_macros.h:49
#define warning_macro(message)
Definition: dis_macros.h:53
This file is part of Rheolef.
string get_full_name_from_rheo_path(const string &rootname, const string &suffix)
get_full_name_from_rheo_path: see the rheostream page for the full documentation
Definition: rheostream.cc:449
string delete_any_suffix(const string &name)
delete_any_suffix: see the rheostream page for the full documentation
Definition: rheostream.cc:243
string delete_suffix(const string &name, const string &suffix)
delete_suffix: see the rheostream page for the full documentation
Definition: rheostream.cc:226
bool has_any_suffix(const string &name)
has_any_suffix: see the rheostream page for the full documentation
Definition: rheostream.cc:233
void prepend_dir_to_rheo_path(const string &dir)
prepend_dir_to_rheo_path: see the rheostream page for the full documentation
Definition: rheostream.cc:343
string get_basename(const string &name)
get_basename: see the rheostream page for the full documentation
Definition: rheostream.cc:258
bool is_float(const string &s)
is_float: see the rheostream page for the full documentation
Definition: rheostream.cc:480
void append_dir_to_rheo_path(const string &dir)
append_dir_to_rheo_path: see the rheostream page for the full documentation
Definition: rheostream.cc:334
string ftos(const Float &x)
itof: see the rheostream page for the full documentation
Definition: rheostream.cc:59
string get_dirname(const string &name)
get_dirname: see the rheostream page for the full documentation
Definition: rheostream.cc:267
std::string get_tmpdir()
get_tmpdir: see the rheostream page for the full documentation
Definition: rheostream.cc:54
bool file_exists(const std::string &filename)
file_exists: see the rheostream page for the full documentation
Definition: scatch.icc:34
bool has_suffix(const string &name, const string &suffix)
has_suffix: see the rheostream page for the full documentation
Definition: rheostream.cc:212
Float to_float(const string &s)
to_float: see the rheostream page for the full documentation
Definition: rheostream.cc:498
#define PATH_MAX
Definition: rheostream.cc:46