/** * Author: Nigel Brown * * Copyright (c) 2007 Des Higgins, Julie Thompson and Toby Gibson. */ /** * InFileStream subclasses std::ifstream, adding a check for the end-of-line * character convention in the input file. This is then used by the getline() * member as the line delimiter, unless the caller supplies an explicit * delimiter. * * Note: This is an ugly workaround; at present various operations repeatedly * construct/destruct an instance and open/close a sequence file up to 12 * times! A cleaner class will probably derive this class from something like * 'istream' aggregating a 'filebuf' under control of istream::seekg(). * * Created: 09-02-07,Nigel Brown(EMBL) * * Changes: * Mark Larkin 13-2-07: I removed the dynamic cast from the getline functions. ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "InFileStream.h" using namespace std; const char LF = 0x0a; //linefeed const char CR = 0x0d; //carriage return InFileStream::InFileStream() : ifstream() { delim = '\n'; // default //cout << "InFileStream() constructor 1" << endl; } InFileStream::InFileStream(const char *filename) : ifstream(filename, ios::in), filename(filename) { //cout << "InFileStream(f) constructor 2" << endl; delim = findDelimiter(); } //- copy-constructor: can't copy superclass private members //- InFileStream::InFileStream(const InFileStream ©) : //- ifstream(static_cast(copy)) //- { //- cout << "InFileStream() constructor 3" << endl; //- delim = copy.delim; //- } void InFileStream::open(const char *filename) { this->filename = filename; ifstream::open(filename, ios::in); if (ifstream::fail()) return; delim = findDelimiter(); } //not necessary, but for symmetry to open() void InFileStream::close() { ifstream::close(); } //getline with stored delimiter std::istream& InFileStream::getline(char *s, streamsize n) { return ifstream::getline(s, n, delim); } //getline with caller supplied delimiter std::istream& InFileStream::getline(char *s, streamsize n, char delim) { return ifstream::getline(s, n, delim); } /** * Mark 24-1-2007. I added the function findDelimiter to determine if '\r' or * '\n' will be used as the line delimiter when parsing the file. * * 25-01-07,Nigel Brown(EMBL): changed body of loop to check successive chars * in case of DOS/Windows * * 09-02-07,Nigel Brown(EMBL): moved member into new InFileStream subclassed * from std::ifstream, so this is called automatically for any file reader * that uses InFileStream in place of std::ifstream. Replaced if/then/else * with switch. */ char InFileStream::findDelimiter() { ifstream in; int type = 0; in.open(filename.c_str(), ios::in); if (in.fail()) return delim; in.seekg(0, ios::beg); //look for CR or LF or CRLF (or LFCR) if (in.is_open()) { char c; while (in.get(c)) { if (c == CR) type |= 1; else if (c == LF) type |= 2; else if (type) break; } } in.close(); switch (type) { case 1: //cout << "file is Mac System 9" << endl; delim = '\r'; break; case 2: //cout << "file is UNIX" << endl; delim = '\n'; break; case 3: //cout << "file is DOS" << endl; delim = '\n'; break; default: //short or empty file //cout << "file is UNIX (default)" << endl; delim = '\n'; } return delim; }