Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/Base/Reader.cpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.
7 : : All rights reserved. See the LICENSE file for details.
8 : : \brief Reader class definition
9 : : \details Reader base class declaration. Reader base servers as a base class
10 : : for various file readers. It does generic low-level I/O, e.g., opening and
11 : : closing a file, and associated error handling.
12 : : */
13 : : // *****************************************************************************
14 : :
15 : : #include <cstdio>
16 : : #include <exception>
17 : : #include <string>
18 : :
19 : : #include "Reader.hpp"
20 : : #include "Exception.hpp"
21 : :
22 : : using tk::Reader;
23 : :
24 : 845 : Reader::Reader( const std::string& filename, std::ios_base::openmode mode ) :
25 [ + - ]: 851 : m_filename( filename ), m_inFile()
26 : : // *****************************************************************************
27 : : // Constructor: Acquire file handle
28 : : //! \param[in] filename Name of file to open for reading
29 : : //! \param[in] mode Open mode, see
30 : : //! http://en.cppreference.com/w/cpp/io/ios_base/openmode
31 : : // *****************************************************************************
32 : : {
33 : : // Make sure there is a filename
34 [ + + ][ + - ]: 845 : Assert( !filename.empty(), "No filename specified" );
[ + - ][ + - ]
35 : :
36 : : // Check if file exists, throw exception if it does not
37 [ + - ]: 844 : m_inFile.open( filename, mode );
38 [ + - ][ + + ]: 844 : ErrChk( m_inFile.good(), "Failed to open file: " + filename );
[ + - ][ + - ]
[ + - ]
39 : :
40 : : // Attempt to read a character, throw if it fails
41 : : // It is curious that on some systems opening a directory instead of a file
42 : : // with the above ifstream::open() call does not set the failbit. Thus we get
43 : : // here fine, so we try to read a character from it. If it is a directory or
44 : : // an empty file the read will fail, so we throw. Read more at: http://
45 : : // stackoverflow.com/questions/9591036/
46 : : // ifstream-open-doesnt-set-error-bits-when-argument-is-a-directory.
47 [ + - ]: 843 : m_inFile.get();
48 [ + - ][ + + ]: 843 : ErrChk( m_inFile.good(), "Failed to read from file: " + filename );
[ + - ][ + - ]
[ + - ]
49 : :
50 : : // Close it
51 [ + - ]: 842 : m_inFile.close();
52 [ + - ][ - + ]: 842 : ErrChk( !m_inFile.fail(), "Failed to close file: " + filename );
[ - - ][ - - ]
[ - - ]
53 : :
54 : : // Re-open
55 [ + - ]: 842 : m_inFile.open( filename, std::ifstream::in );
56 [ + - ][ - + ]: 842 : ErrChk( m_inFile.good(), "Failed to open file: " + filename );
[ - - ][ - - ]
[ - - ]
57 : 842 : }
58 : :
59 : 842 : Reader::~Reader() noexcept
60 : : // *****************************************************************************
61 : : // Destructor: Release file handle
62 : : //! \details Exception safety: no-throw guarantee: never throws exceptions.
63 : : //! Error handling, while done by throwing and catching exceptions, results in
64 : : //! warnings to terminal. We use C-style printf, since that will not throw
65 : : //! exceptions.
66 : : // *****************************************************************************
67 : : {
68 : : // Clear failbit triggered by eof, so close() won't throw a false FAILED_CLOSE
69 : 842 : m_inFile.clear();
70 : :
71 : : try {
72 : :
73 [ + - ]: 842 : m_inFile.close();
74 [ + - ][ - + ]: 842 : ErrChk( !m_inFile.fail(), "Failed to close file: " + m_filename );
[ - - ][ - - ]
[ - - ]
75 : :
76 : : } // emit only a warning on error
77 : 0 : catch (Exception& e) {
78 : 0 : e.handleException();
79 : : }
80 : 0 : catch (std::exception& e) {
81 : 0 : printf( ">>> WARNING: std::exception in MeshReader destructor: %s\n",
82 : 0 : e.what() );
83 : : }
84 : 0 : catch (...) {
85 : 0 : printf( ">>> WARNING: UNKNOWN EXCEPTION in MeshReader destructor\n" );
86 : : }
87 : 842 : }
88 : :
89 : : std::string
90 : 822 : Reader::firstline()
91 : : // *****************************************************************************
92 : : // Return first line (for detection of file type based on header)
93 : : //! \return First line read from file. This can be used for detection of file
94 : : //! type based on header.
95 : : // *****************************************************************************
96 : : {
97 : 822 : std::string s;
98 [ + - ]: 822 : std::getline( m_inFile, s ); // read the first line
99 [ + - ]: 822 : m_inFile.seekg( 0, std::ios::beg ); // seek back to the beginning of file
100 : 822 : return s;
101 : : }
102 : :
103 : : std::vector< std::string >
104 : 2 : Reader::lines()
105 : : // *****************************************************************************
106 : : // Read file and return a string for each line
107 : : //! \return A std::vector< std::string >, a string for each line of a file.
108 : : // *****************************************************************************
109 : : {
110 : 4 : std::string s;
111 : 2 : std::vector< std::string > ls;
112 [ + - ][ + - ]: 2940 : while ( std::getline( m_inFile, s ) ) ls.push_back( s );
[ + + ][ + - ]
113 : 4 : return ls;
114 : : }
115 : :
116 : : std::string
117 : 0 : Reader::line( std::size_t lineNum )
118 : : // *****************************************************************************
119 : : // Read a given line from file
120 : : //! \param[in] lineNum Line number to read from file
121 : : //! \return Line read from file at line given
122 : : // *****************************************************************************
123 : : {
124 : 0 : std::string s;
125 : 0 : std::size_t num = 0;
126 [ - - ][ - - ]: 0 : while ( std::getline( m_inFile, s ) && ++num < lineNum ) {}
[ - - ][ - - ]
[ - - ]
127 [ - - ]: 0 : m_inFile.seekg( 0, std::ios::beg ); // seek back to the beginning of file
128 : 0 : return s;
129 : : }
|