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