/****** * fileio.cc * Tom Prince and John Bowman 2004/08/10 * * Handle input/output ******/ #include "fileio.h" #include "settings.h" #if !defined(_WIN32) #define _fdopen fdopen #endif namespace camp { FILE *pipeout=NULL; string tab="\t"; string newline="\n"; ofile Stdout(""); file nullfile("",false,NOMODE,false,true); void openpipeout() { int fd=intcast(settings::getSetting("outpipe")); if(!pipeout && fd >= 0) pipeout=_fdopen(fd,"w"); if(!pipeout) { cerr << "Cannot open outpipe " << fd << endl; exit(-1); } } string locatefile(string name) { string s=settings::locateFile(name,false,""); return s.empty() ? name : s; } #pragma region "class file" bool file::Standard() { return standard; } void file::standardEOF() { #if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES) cout << endl; #endif } void file::purgeStandard(string&) { if(cin.eof()) standardEOF(); } void file::dimension(Int Nx, Int Ny, Int Nz) { if(Nx < -2 || Ny < -2 || Nz < -2) { ostringstream buf; buf << "Invalid array dimensions: " << Nx << ", " << Ny << ", " << Nz; reportError(buf); } nx=Nx; ny=Ny; nz=Nz; } file::file( string const& name, bool check, Mode type, bool binary, bool closed ) : name(name), check(check), type(type), linemode(false), csvmode(false), wordmode(false), singlereal(false), singleint(true), signedint(true), closed(closed), standard(name.empty()), binary(binary), nullfield(false), whitespace("") { dimension(); } void file::Check() { if(error()) { ostringstream buf; buf << "Cannot open file \"" << name << "\""; reportError(buf); } } file::~file() { } bool file::isOpen() { if(closed) { ostringstream buf; buf << "I/O operation attempted on "; if(name != "") buf << "closed file \'" << name << "\'"; else buf << "null file"; reportError(buf); } return true; } void file::unsupported(char const* rw, char const* type) { ostringstream buf; buf << rw << " of type " << type << " not supported in " << FileMode() << " mode"; reportError(buf); } #pragma endregion #pragma region "class ifile" void ifile::open() { if(standard) { if(mode & std::ios::binary) reportError("Cannot open standard input in binary mode"); stream=&cin; } else { if(mode & std::ios::out) name=outpath(name); if(mode & std::ios::in) { #ifdef HAVE_LIBCURL if(parser::isURL(name)) { parser::readURL(buf,name); stream=&buf; } else #endif { name=locatefile(inpath(name)); stream=fstream=new std::fstream(name.c_str(),mode); } } if(mode & std::ios::out) { if(error()) { delete fstream; std::ofstream f(name.c_str()); f.close(); stream=fstream=new std::fstream(name.c_str(),mode); } } index=processData().ifile.add(fstream); if(check) Check(); } } void ifile::ignoreComment() { if(comment == 0) return; int c=stream->peek(); bool eol=c == '\n'; if(csvmode && eol) {nullfield=true; return;} if(csvmode && c == ',') nullfield=true; for(;;) { while(isspace(c=stream->peek())) { stream->ignore(); whitespace += (char) c; } if(c == comment) { whitespace=""; while((c=stream->peek()) != '\n' && c != EOF) stream->ignore(); if(c == '\n') stream->ignore(); } else {if(c != EOF && eol) stream->unget(); return;} } } void ifile::Read(double& val) { char c; std::string str; bool neg; while(isspace(c=stream->peek())) stream->ignore(); neg=stream->peek() == '-'; // Try parsing the input as a number. if(*stream >> val) return; clear(); switch(stream->peek()) { case 'I': case 'i': // inf case 'N': case 'n': // NaN for(Int i=0; i < 3 && stream->good(); i++) str += stream->get(); break; default: stream->setstate(std::ios_base::failbit); return; } if(strcasecmp(str.c_str(),"inf") == 0) val=std::numeric_limits < double > ::infinity(); else if(strcasecmp(str.c_str(),"nan") == 0) val=std::numeric_limits < double > ::quiet_NaN(); else { for(auto it=str.rbegin(); it != str.rend(); ++it) stream->putback(*it); stream->setstate(std::ios_base::failbit); return; } if(neg) val=-val; } bool ifile::eol() { int c; while(isspace(c=stream->peek())) { if(c == '\n') return true; else { stream->ignore(); whitespace += (char) c; } } return false; } bool ifile::nexteol() { int c; if(nullfield) { nullfield=false; return true; } while(isspace(c=stream->peek())) { if(c == '\n' && comma) { nullfield=true; return false; } stream->ignore(); if(c == '\n') { while(isspace(c=stream->peek())) { if(c == '\n') {nullfield=true; return true;} else { stream->ignore(); whitespace += (char) c; } } return true; } else whitespace += (char) c; } return false; } void ifile::csv() { comma=false; nullfield=false; if(!csvmode || stream->eof()) return; std::ios::iostate rdstate=stream->rdstate(); if(stream->fail()) stream->clear(); int c=stream->peek(); if(c == ',') stream->ignore(); else if(c == '\n') { stream->ignore(); if(linemode && stream->peek() != EOF) stream->unget(); } else stream->clear(rdstate); if(c == ',') comma=true; } void ifile::Read(string& val) { string s; if(wordmode) { whitespace=""; while(isspace(stream->peek())) stream->ignore(); } if(csvmode || wordmode) { bool quote=false; while(stream->good()) { int c=stream->peek(); if(c == '"') {quote=!quote; stream->ignore(); continue;} if(!quote) { if(comment && c == comment) { while((c=stream->peek()) != '\n' && c != EOF) stream->ignore(); if(wordmode && !linemode) while(isspace(stream->peek())) stream->ignore(); if(stream->peek() == '"') {quote=!quote; stream->ignore(); continue;} if(s.empty() && c == '\n') { stream->ignore(); continue; } } if(csvmode && (c == ',' || c == '\n')) break; if(wordmode && isspace(c)) { if(!linemode) while(isspace(stream->peek())) stream->ignore(); break; } } s += (char) stream->get(); } } else getline(*stream,s); if(comment) { size_t p=0; while((p=s.find(comment,p)) < string::npos) { if(p+1 < s.length() && s[p+1] == comment) { s.erase(p,1); ++p; } else { s.erase(p); break; } } } size_t n=s.length(); if(n > 0) { size_t pos=n-1; if(s[pos] == '\r') s.erase(pos,1); } val=whitespace+s; } #pragma endregion void ofile::writeline() { if(standard && interact::query && !vm::indebugger) { Int scroll=settings::getScroll(); if(scroll && interact::lines > 0 && interact::lines % scroll == 0) { for(;;) { if(!cin.good()) { *stream << newline; cin.clear(); break; } int c=cin.get(); if(c == '\n') break; // Discard any additional characters while(cin.good() && cin.get() != '\n'); if(c == 's') {interact::query=false; break;} if(c == 'q') {interact::query=false; interact::lines=0; throw quit();} } } else *stream << newline; ++interact::lines; } else *stream << newline; if(errorstream::interrupt) {interact::lines=0; throw interrupted();} } void ofile::open() { if(standard) { if(mode & std::ios::binary) reportError("Cannot open standard output in binary mode"); stream=&cout; } else { name=outpath(name); stream=fstream=new std::ofstream(name.c_str(),mode | std::ios::trunc); stream->precision(settings::getSetting("digits")); index=processData().ofile.add(fstream); Check(); } } void ofile::close() { if(!standard && fstream) { fstream->close(); closed=true; delete fstream; fstream=NULL; processData().ofile.remove(index); } } Int ofile::precision(Int p) { return p == 0 ? stream->precision(settings::getSetting("digits")) : stream->precision(p); } void ofile::seek(Int pos, bool begin) { if(!standard && fstream) { clear(); fstream->seekp(pos,begin ? std::ios::beg : std::ios::end); } } size_t ofile::tell() { if(fstream) return fstream->tellp(); else return 0; } bool ofile::enabled() { return !standard || settings::verbose > 1 || interact::interactive || !settings::getSetting("quiet"); } #pragma region opipe void opipe::write(const string& val) { if (fprintf(pipeout,"%s",val.c_str()) < 0) { reportError("Write failed to pipe"); } } void opipe::flush() { if(pipeout) { if (fflush(pipeout) == EOF) { reportError("Flushing pipe failed"); } } } #pragma endregion void iofile::writeline() { *fstream << newline; if(errorstream::interrupt) throw interrupted(); } void igzxfile::open() { name=locatefile(inpath(name)); gzfile=gzopen(name.c_str(),"rb"); Check(); while(!gzeof(gzfile)) { std::vector tmpBuf(readSize); auto filSz = gzread(gzfile,tmpBuf.data(),readSize); std::copy(tmpBuf.begin(),tmpBuf.begin()+filSz,std::back_inserter(readData)); } gzclose(gzfile); fstream=new xdr::memixstream(readData); index=processData().ixfile.add(fstream); } void igzxfile::closeFile() { if(fstream) { fstream->close(); closed=true; delete fstream; processData().ixfile.remove(index); } } } // namespace camp