rheostream.cc
Go to the documentation of this file.
#include "rheolef/rheostream.h"
#include "rheolef/iorheo.h"
#include "scatch.icc" // compile this code here, but is reused in field2bb
#include <climits> // PATH_MAX ?
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/device/file.hpp>
#ifdef _RHEOLEF_HAVE_UNISTD_H
#include<unistd.h> // readink()
#endif
#ifdef _RHEOLEF_HAVE_SYMLINK_H
#include<symlink.h> // readink() on hpux9*
#endif
#include<dirent.h> // opendir()
#include<sys/stat.h> // stat()
#ifndef PATH_MAX
#define PATH_MAX 1023 // TODO: find it !
#endif // PATH_MAX
namespace rheolef {
using namespace std;
namespace ios = boost::iostreams;
std::string
get_tmpdir() {
char* c_tmpdir = std::getenv ("TMPDIR");
return (c_tmpdir == 0) ? "/tmp" : c_tmpdir;
}
string
ftos (const Float& x)
{
std::ostringstream out;
out << x;
return out.str ();
}
// -----------------------------------------------------------------
// output
// -----------------------------------------------------------------
orheostream::orheostream (const string& name, const string& suffix, io::mode_type mode)
: ios::filtering_stream<ios::output>(),
_mode(mode),
_full_name()
{
open (name, suffix, mode);
}
orheostream::~orheostream ()
{
orheostream::close();
}
void
orheostream::open (const string& name, const string& suffix, io::mode_type mode)
{
_mode = mode;
// append the '.gz' suffix:
if (suffix.length() == 0) {
_full_name = delete_suffix(name, "gz");
} else {
_full_name = delete_suffix(delete_suffix(name, "gz"), suffix)
+ "." + suffix;
}
if (!(mode & io::nogz)) {
_full_name = _full_name + ".gz";
}
_open_internal (_mode);
bool verbose = iorheo::getverbose(clog);
if (verbose) {
std::string action = (mode & io::app) ? "appended" : "created";
clog << "! file \"" << _full_name << "\" " << action << endl;
}
}
void
orheostream::_open_internal (io::mode_type mode)
{
using namespace ios;
// create the output pipe with the optional gzip filter:
if (!(mode & io::nogz)) {
filtering_stream<output>::push (gzip_compressor());
}
// open the file.gz:
std::ios_base::openmode om = std::ios_base::out | std::ios_base::binary;
if (mode & io::app) { om |= std::ios_base::app; }
file_sink ofs (_full_name.c_str(), om);
filtering_stream<output>::push (ofs);
}
void
orheostream::_close_internal ()
{
using namespace ios;
if (filtering_stream<ios::output>::empty()) {
return;
}
#define _RHEOLEF_HAVE_BOOST_IOSTREAMS_GZIP_EMPTY_FILE_BUG
#ifdef _RHEOLEF_HAVE_BOOST_IOSTREAMS_GZIP_EMPTY_FILE_BUG
if (! (_mode & io::nogz)) {
*this << endl;
}
#endif // _RHEOLEF_HAVE_BOOST_IOSTREAMS_GZIP_EMPTY_FILE_BUG
#ifdef _RHEOLEF_HAVE_BOOST_IOSTREAMS_GZIP_EMPTY_FILE_BUG_OLD
if (! (_mode & io::nogz)) {
// bug with empty gziped boost::io: workaround by writting an empty thing !
// https://svn.boost.org/trac/boost/ticket/5237
// the previous fix is buggy: requires a non-empty thing: a newline that does not change rheolef semantic
trace_macro ("_close_internal: _full_name="<<_full_name<<": gziped => add a carriage return before closing...");
static char dummy = '\n'; // in rheolef, does not change the file format
static size_t length = 1; // instead of zero
filtering_stream<ios::output>::component<gzip_compressor>(0)->write(*filtering_stream<ios::output>::component<file_sink>(1), &dummy, length);
}
#endif // _RHEOLEF_HAVE_BOOST_IOSTREAMS_GZIP_EMPTY_FILE_BUG_OLD
while (! filtering_stream<ios::output>::empty()) {
filtering_stream<ios::output>::pop();
}
}
void
orheostream::close ()
{
_close_internal();
_full_name = "";
_mode = io::out;
}
void
orheostream::flush ()
{
// boost::iostreams are not yet flushable when using gzip:
// thus close and re-open... it is a clostly procedure
_close_internal();
// then reopen: in append mode
_open_internal (io::mode_type(_mode | io::app));
}
// -----------------------------------------------------------------
// input
// -----------------------------------------------------------------
void
irheostream::open (const string& name, const string& suffix)
{
using namespace ios;
// get full file path with the optional '.gz' suffix:
string full_name = get_full_name_from_rheo_path (name, suffix);
if (full_name.length() == 0) {
if (suffix.length() != 0) {
error_macro ("file \"" << name << "[." << suffix << "[.gz]]\" not found");
} else {
error_macro ("file \"" << name << "[.gz]\" not found");
}
}
// open the file[.gz]:
bool has_gz = has_suffix (full_name, "gz");
if (!has_gz) {
_ifs.open (full_name.c_str(), ios_base::in);
} else {
_ifs.open (full_name.c_str(), ios_base::in | ios_base::binary);
}
bool verbose = iorheo::getverbose(clog);
if (verbose) clog << "! load \"" << full_name << "\"\n";
// create the input pipe with the optional gzip filter:
if (has_gz) {
filtering_stream<input>::push (gzip_decompressor());
}
filtering_stream<input>::push (_ifs);
}
void
irheostream::close ()
{
using namespace ios;
while (! filtering_stream<ios::input>::empty()) {
filtering_stream<ios::input>::pop();
}
_ifs.close();
}
irheostream::irheostream (const string& name, const string& suffix)
: ios::filtering_stream<ios::input>(), _ifs()
{
open (name, suffix);
}
irheostream::~irheostream ()
{
irheostream::close();
}
// has_suffix("toto.suffix", "suffix") -> true
bool
has_suffix (const string& name, const string& suffix)
{
size_t ln = name.length();
size_t ls = suffix.length();
if (ln <= ls+1) return false;
if (name[ln-ls-1] != '.') return false;
for (size_t i = ln-ls, j = 0; i < ln; i++, j++)
if (name [i] != suffix [j]) return false;
return true;
}
// delete_suffix("toto.suffix", "suffix") --> "toto"
string
delete_suffix (const string& name, const string& suffix)
{
if (!has_suffix(name, suffix)) return name;
return string(name, 0, name.length() - suffix.length() - 1);
}
// has_any_suffix("toto.any_suffix") -> true
bool
has_any_suffix (const string& name)
{
size_t ln = name.length();
if (ln == 0) return false;
for (size_t i = ln-1; i > 0 && name[i] != '/'; --i)
if (name [i] == '.') return true;
return false;
}
// delete_any_suffix("toto.any_suffix") --> "toto"
string
delete_any_suffix (const string& name)
{
size_t ln = name.length();
if (ln == 0) return name;
size_t i_dot = 0;
for (size_t i = ln-1; i > 0 && name[i] != '/'; --i) {
if (name [i] == '.') {
i_dot = i;
break;
}
}
if (i_dot == 0) return name;
return string(name, 0, i_dot);
}
string
get_basename (const string& name)
{
string::size_type l = name.length();
string::size_type i = name.find_last_of ('/');
if (i >= l) return name;
string b = string(name, i+1, l-i-1);
return b;
}
string
get_dirname (const string& name)
{
string::size_type l = name.length();
string::size_type i = name.find_last_of ('/');
if (i >= l) return ".";
string d = string(name, 0, i);
return d;
}
//
// NOTE: path could have an iterator that points to
// a directory name...
//
// NOTE 2: global cstors in shared libraries are not
// handled by g++ and most compilers
// => need char* instead of string here
//
static const char* rheo_path_name = "RHEOPATH";
static const char* default_rheo_path = ".";
static char* rheo_path = 0;
static
string
get_dir_from_path (const string& path, unsigned int& i_pos)
{
// is search path finished ?
unsigned int last = path.length();
if (i_pos >= last) {
return string();
}
// skip ':' separators
while (i_pos < last && path [i_pos] == ':')
i_pos++;
// test end of path
if (i_pos == last) {
return string();
}
// path [i_pos] != ':' and i_pos < last, so we have a dir
unsigned int i_last = i_pos;
for (i_last = i_pos; i_last < last && path [i_last] != ':'; i_last++);
string current_dir;
if (i_last == last)
current_dir = string(path, i_pos, i_last-i_pos+1);
else
current_dir = string(path, i_pos, i_last-i_pos);
// i_last == last || path[i_last] == ':'
i_pos = i_last;
return current_dir;
}
static
void
init_rheo_path ()
{
// get directory path from environ
if (rheo_path) {
return;
}
const char *s1 = getenv (rheo_path_name);
if (!s1) {
s1 = default_rheo_path;
}
rheo_path = new_tab_macro(char, strlen(s1)+1);
strcpy (rheo_path, s1);
}
void
append_dir_to_rheo_path (const string& dir)
{
init_rheo_path();
string tmp = string(rheo_path) + ":" + dir;
delete_tab_macro(rheo_path);
rheo_path = new_tab_macro(char, strlen(tmp.c_str())+1);
strcpy (rheo_path, tmp.c_str());
}
void
prepend_dir_to_rheo_path (const string& dir)
{
init_rheo_path();
string tmp = dir + ":" + string(rheo_path);
delete_tab_macro(rheo_path);
rheo_path = new_tab_macro(char, strlen(tmp.c_str())+1);
strcpy (rheo_path, tmp.c_str());
}
static
bool
have_name_in_dir (const string& dir, const string& name, string& full_path)
{
string prefix;
if (dir != "") {
// trace_macro ("scanning in \"" << dir.c_str() << "\"");
prefix = dir + "/";
}
// try to open file like dir/rootname.suffix.gz
string zip_full_name = prefix + name + ".gz";
bool zip_status = file_exists (zip_full_name);
// try to open file like dir/rootname.suffix
string unzip_full_name = prefix + name;
bool unzip_status = file_exists (unzip_full_name);
if (unzip_status && zip_status) {
warning_macro ("both compressed and uncompressed files exists:");
warning_macro (" \"" << zip_full_name << "\"");
warning_macro ("and \"" << unzip_full_name << "\"");
error_macro ("unrecoverable ambiguous situation (HINT: rename one of these files)");
}
// prefer ziped than unziped version
if (zip_status) {
full_path = zip_full_name;
return true;
}
if (unzip_status) {
full_path = unzip_full_name;
return true;
}
// 15 oct 2000: check that "dir" is a valid directory
struct stat sd;
if (stat(dir.c_str(), &sd) != 0) {
warning_macro ("cannot not stat \"" << dir << "\"");
warning_macro ("hint: check "<< rheo_path_name << " or -I options");
return false;
}
if ((sd.st_mode & S_IFDIR) == 0) {
warning_macro ("invalid directory \"" << dir << "\"");
warning_macro ("hint: check "<< rheo_path_name << " or -I options");
return false;
}
// scan subdirs
DIR* d = opendir(dir.c_str());
if (!d) {
warning_macro ("cannot open directory \"" << dir << "\"");
warning_macro ("hint: check "<< rheo_path_name << " or -I options");
return false;
}
struct dirent* dp;
while ((dp = readdir(d)) != 0) {
string subdir = dir + "/" + (dp -> d_name);
if (strcmp(dp -> d_name, ".") == 0 ||
strcmp(dp -> d_name, "..") == 0) continue;
struct stat s;
if (stat(subdir.c_str(), &s) != 0) {
warning_macro ("can not stat() for \"" << subdir << "\"");
continue;
}
if ((s.st_mode & S_IFLNK) == 0) {
// 16 january 1999: skip also symbolic links to "." and ".."
char linkname [PATH_MAX + 2];
// extern "C" int readlink(const char *, char *, int);
char* subdir_cstr = (char*)(subdir.c_str());
int linksize = readlink (subdir_cstr, linkname, PATH_MAX + 1);
// PATH_MAX = max number of characters in a pathname
// (not including terminating null)
//
// from fileutils-3.14/src/ls.c (line 1724):
// "Some automounters give incorrect st_size for mount points.
// I can't think of a good workaround for it, though."
//
if (linksize < 0) {
// perhaps not a symklink ?
// trace_macro ("can not read link name \"" << subdir << "\"");
} else {
linkname [linksize] = '\0';
if (strcmp(linkname, ".") == 0 ||
strcmp(linkname, "..") == 0) {
continue;
}
}
}
if ((s.st_mode & S_IFDIR) != 0) {
// recurse in subdir
if (have_name_in_dir (subdir, name, full_path)) {
return true;
}
}
}
return false;
}
string
get_full_name_from_rheo_path (const string& rootname, const string& suffix)
{
if (rootname == "") {
return rootname;
}
string name = delete_suffix(delete_suffix(rootname, "gz"), suffix);
if (suffix != "") name += "." + suffix;
string full_path;
if (rootname [0] == '.' || rootname[0] == '/') {
if (have_name_in_dir ("", name, full_path)) {
return full_path;
}
return string();
}
//
// rootname has no explicit reference: use search path
//
init_rheo_path();
unsigned int i_dir = 0;
string dir = get_dir_from_path (rheo_path, i_dir);
while (dir.length() != 0) {
if (have_name_in_dir (dir, name, full_path)) {
return full_path;
}
dir = get_dir_from_path (rheo_path, i_dir);
}
return string();
}
bool
is_float (const string& s)
{
// simple check for float argument
// EXP ([fFeEdD]([\-+])?([0-9]+))
// ([\-])?[0-9]+ |
// ([\-])?[0-9]+"."[0-9]*{EXP}?
// ([\-])?[0-9]*"."[0-9]+{EXP}?
// ([\-])?[0-9]+{EXP}
unsigned int l = s.length();
if (l < 1) return false;
if (!isdigit(s[0]) && s[0] != '-' && s[0] != '.') return false;
if (s[0] == '-') {
if (l < 2) return false;
if (!isdigit(s[1]) && s[1] != '.') return false;
}
return true;
}
Float
to_float (const string& s) {
// more robust than atof when Float=float128
stringstream ss(s);
Float x;
ss >> x;
return x;
}
}// 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
@ 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
@ 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
@ 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