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