#ifndef lreader_hpp__ #define lreader_hpp__ #include #include template< typename charT > class stream_line_reader { enum { STOCK_BUFFER_SIZE = 16, // 本当のストック用バッファサイズ .. 2 以上である事 STOCKABLE = STOCK_BUFFER_SIZE - 1 // 改行が 2 文字かも知れず,種類を簡単に判別するために 1 文字余裕を持たせる }; typedef char static_test[ STOCKABLE -1 ]; // ここでコンパイルエラーになれば,stock_buffer_size が小さすぎるという事 charT stock_[ STOCK_BUFFER_SIZE ]; unsigned int offset_; unsigned int stocked_; unsigned int breaker_; bool eof_; /* * ストリームは何を使うか? * 例えば Cスタイルの FILE* を使いたいなど,別のストリーム機構を使いたいなら * o input_ メンバの型 * o read_stream() の内部 * o コンストラクタ * を修正し,適切なファイルを #include する * read_stream() は input_ から buf に最大 size バイトを読み込み, * 実際に読み込んだサイズを返す */ std::basic_istream *input_; unsigned int read_stream( void *buf, unsigned int size ) { input_->read( (char*)buf, size ); return input_->gcount(); } public: //! 行末文字の種類 enum { end_of_stream = 0, lf = 1, // \n (unix) cr = 2, // \r (mac) crlf = 3, // \r\n (msdos) lfcr = 4 // \n\r (crazy ;-) }; /*! * ctor */ explicit stream_line_reader (std::basic_istream& in) : input_(&in) { offset_ = 0; stocked_ = 0; eof_ = false; breaker_ = end_of_stream; } /*! 一行を読む * 行末文字を返す */ unsigned int read_a_line (std::basic_string *pstr) { typedef std::basic_string str_type; typedef str_type::size_type size_type; unsigned int o, next_offset; breaker_ = end_of_stream; pstr->assign("", (size_type)0); for (;;) { if (offset_ == stocked_) { stocked_ = read_stream( stock_, STOCKABLE ); offset_ = 0; } if (stocked_ == 0) break; o = offset_; while (o < stocked_) { if (stock_[o] == '\r' || stock_[o] == '\n') goto breaker_found; ++o; } pstr->append( &stock_[offset_], o - offset_ ); offset_ = o; } eof_ = true; return breaker_; breaker_found: if (o == (stocked_ - 1)) // とりあえず次の 1 バイトもチェックしたい stocked_ += read_stream( &stock_[o+1], 1 ); // 改行の種類の判定 if ((o < (stocked_ - 1)) && stock_[o]=='\r' && stock_[o+1]=='\n') { breaker_ = crlf; next_offset = o + 2; } else if ((o < (stocked_ - 1)) && stock_[o]=='\n' && stock_[o+1]=='\r') { breaker_ = lfcr; next_offset = o + 2; } else if (stock_[o] == '\r') { breaker_ = cr; next_offset = o + 1; } else { breaker_ = lf; next_offset = o + 1; } pstr->append( &stock_[offset_], o - offset_ ); offset_ = next_offset; return breaker_; } /*! eof ? */ bool eof () const { return eof_; } }; #endif // lreader_hpp__