Rheolef  7.2
an efficient C++ finite element environment
 
Loading...
Searching...
No Matches
rheostream.cc
Go to the documentation of this file.
1
21#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
49namespace rheolef {
50using namespace std;
51namespace ios = boost::iostreams;
52
53std::string
55 char* c_tmpdir = std::getenv ("TMPDIR");
56 return (c_tmpdir == 0) ? "/tmp" : c_tmpdir;
57}
58string
59ftos (const Float& x)
60{
61 std::ostringstream out;
62 out << x;
63 return out.str ();
64}
65// -----------------------------------------------------------------
66// output
67// -----------------------------------------------------------------
68orheostream::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}
79void
80orheostream::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}
100void
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}
114void
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}
142void
144{
146 _full_name = "";
147 _mode = io::out;
148}
149void
151{
152 // boost::iostreams are not yet flushable when using gzip:
153 // thus close and re-open... it is a clostly procedure
155 // then reopen: in append mode
157}
158// -----------------------------------------------------------------
159// input
160// -----------------------------------------------------------------
161void
162irheostream::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}
191void
193{
194 using namespace ios;
195 while (! filtering_stream<ios::input>::empty()) {
196 filtering_stream<ios::input>::pop();
197 }
198 _ifs.close();
199}
200irheostream::irheostream (const string& name, const string& suffix)
201 : ios::filtering_stream<ios::input>(), _ifs()
202{
203 open (name, suffix);
204}
209
210// has_suffix("toto.suffix", "suffix") -> true
211bool
212has_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"
225string
226delete_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
232bool
233has_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"
242string
243delete_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}
257string
258get_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}
266string
267get_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//
283static const char* rheo_path_name = "RHEOPATH";
284static const char* default_rheo_path = ".";
285static char* rheo_path = 0;
286
287static
288string
289get_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}
318static
319void
320init_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}
333void
334append_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}
342void
343prepend_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}
351static
352bool
353have_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}
448string
449get_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}
479bool
480is_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}
497Float
498to_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
see the Float page for the full documentation
std::ifstream _ifs
Definition rheostream.h:188
void open(const std::string &name, const std::string &suffix=std::string())
void _open_internal(io::mode_type mode)
io::mode_type _mode
Definition rheostream.h:210
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
static char * rheo_path
static const char * rheo_path_name
#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_dirname(const string &name)
get_dirname: see the rheostream page for the full documentation
string delete_suffix(const string &name, const string &suffix)
delete_suffix: see the rheostream page for the full documentation
void prepend_dir_to_rheo_path(const string &dir)
prepend_dir_to_rheo_path: see the rheostream page for the full documentation
Float to_float(const string &s)
to_float: see the rheostream page for the full documentation
string get_basename(const string &name)
get_basename: see the rheostream page for the full documentation
std::string get_tmpdir()
get_tmpdir: see the rheostream page for the full documentation
Definition rheostream.cc:54
bool has_suffix(const string &name, const string &suffix)
has_suffix: see the rheostream page for the full documentation
void append_dir_to_rheo_path(const string &dir)
append_dir_to_rheo_path: see the rheostream page for the full documentation
string delete_any_suffix(const string &name)
delete_any_suffix: see the rheostream page for the full documentation
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
bool is_float(const string &s)
is_float: see the rheostream page for the full documentation
string ftos(const Float &x)
itof: see the rheostream page for the full documentation
Definition rheostream.cc:59
bool file_exists(const std::string &filename)
file_exists: see the rheostream page for the full documentation
Definition scatch.icc:34
bool has_any_suffix(const string &name)
has_any_suffix: see the rheostream page for the full documentation
STL namespace.
#define PATH_MAX
Definition rheostream.cc:46