xref: /freebsd/contrib/kyua/utils/stream.cpp (revision b0d29bc4)
1*b0d29bc4SBrooks Davis // Copyright 2011 The Kyua Authors.
2*b0d29bc4SBrooks Davis // All rights reserved.
3*b0d29bc4SBrooks Davis //
4*b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davis // met:
7*b0d29bc4SBrooks Davis //
8*b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davis //   documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davis //   may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davis //   without specific prior written permission.
16*b0d29bc4SBrooks Davis //
17*b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis 
29*b0d29bc4SBrooks Davis #include "utils/stream.hpp"
30*b0d29bc4SBrooks Davis 
31*b0d29bc4SBrooks Davis #include <fstream>
32*b0d29bc4SBrooks Davis #include <iostream>
33*b0d29bc4SBrooks Davis #include <sstream>
34*b0d29bc4SBrooks Davis #include <stdexcept>
35*b0d29bc4SBrooks Davis 
36*b0d29bc4SBrooks Davis #include "utils/format/macros.hpp"
37*b0d29bc4SBrooks Davis #include "utils/fs/path.hpp"
38*b0d29bc4SBrooks Davis #include "utils/sanity.hpp"
39*b0d29bc4SBrooks Davis 
40*b0d29bc4SBrooks Davis namespace fs = utils::fs;
41*b0d29bc4SBrooks Davis 
42*b0d29bc4SBrooks Davis 
43*b0d29bc4SBrooks Davis namespace {
44*b0d29bc4SBrooks Davis 
45*b0d29bc4SBrooks Davis 
46*b0d29bc4SBrooks Davis /// Constant that represents the path to stdout.
47*b0d29bc4SBrooks Davis static const fs::path stdout_path("/dev/stdout");
48*b0d29bc4SBrooks Davis 
49*b0d29bc4SBrooks Davis 
50*b0d29bc4SBrooks Davis /// Constant that represents the path to stderr.
51*b0d29bc4SBrooks Davis static const fs::path stderr_path("/dev/stderr");
52*b0d29bc4SBrooks Davis 
53*b0d29bc4SBrooks Davis 
54*b0d29bc4SBrooks Davis }  // anonymous namespace
55*b0d29bc4SBrooks Davis 
56*b0d29bc4SBrooks Davis 
57*b0d29bc4SBrooks Davis /// Opens a new file for output, respecting the stdout and stderr streams.
58*b0d29bc4SBrooks Davis ///
59*b0d29bc4SBrooks Davis /// \param path The path to the output file to be created.
60*b0d29bc4SBrooks Davis ///
61*b0d29bc4SBrooks Davis /// \return A pointer to a new output stream.
62*b0d29bc4SBrooks Davis std::auto_ptr< std::ostream >
open_ostream(const fs::path & path)63*b0d29bc4SBrooks Davis utils::open_ostream(const fs::path& path)
64*b0d29bc4SBrooks Davis {
65*b0d29bc4SBrooks Davis     std::auto_ptr< std::ostream > out;
66*b0d29bc4SBrooks Davis     if (path == stdout_path) {
67*b0d29bc4SBrooks Davis         out.reset(new std::ofstream());
68*b0d29bc4SBrooks Davis         out->copyfmt(std::cout);
69*b0d29bc4SBrooks Davis         out->clear(std::cout.rdstate());
70*b0d29bc4SBrooks Davis         out->rdbuf(std::cout.rdbuf());
71*b0d29bc4SBrooks Davis     } else if (path == stderr_path) {
72*b0d29bc4SBrooks Davis         out.reset(new std::ofstream());
73*b0d29bc4SBrooks Davis         out->copyfmt(std::cerr);
74*b0d29bc4SBrooks Davis         out->clear(std::cerr.rdstate());
75*b0d29bc4SBrooks Davis         out->rdbuf(std::cerr.rdbuf());
76*b0d29bc4SBrooks Davis     } else {
77*b0d29bc4SBrooks Davis         out.reset(new std::ofstream(path.c_str()));
78*b0d29bc4SBrooks Davis         if (!(*out)) {
79*b0d29bc4SBrooks Davis             throw std::runtime_error(F("Cannot open output file %s") % path);
80*b0d29bc4SBrooks Davis         }
81*b0d29bc4SBrooks Davis     }
82*b0d29bc4SBrooks Davis     INV(out.get() != NULL);
83*b0d29bc4SBrooks Davis     return out;
84*b0d29bc4SBrooks Davis }
85*b0d29bc4SBrooks Davis 
86*b0d29bc4SBrooks Davis 
87*b0d29bc4SBrooks Davis /// Gets the length of a stream.
88*b0d29bc4SBrooks Davis ///
89*b0d29bc4SBrooks Davis /// \param is The input stream for which to calculate its length.
90*b0d29bc4SBrooks Davis ///
91*b0d29bc4SBrooks Davis /// \return The length of the stream.  This is of size_t type instead of
92*b0d29bc4SBrooks Davis /// directly std::streampos to simplify the caller.  Some systems do not
93*b0d29bc4SBrooks Davis /// support comparing a std::streampos directly to an integer (see
94*b0d29bc4SBrooks Davis /// NetBSD 1.5.x), which is what we often want to do.
95*b0d29bc4SBrooks Davis ///
96*b0d29bc4SBrooks Davis /// \throw std::exception If calculating the length fails due to a stream error.
97*b0d29bc4SBrooks Davis std::size_t
stream_length(std::istream & is)98*b0d29bc4SBrooks Davis utils::stream_length(std::istream& is)
99*b0d29bc4SBrooks Davis {
100*b0d29bc4SBrooks Davis     const std::streampos current_pos = is.tellg();
101*b0d29bc4SBrooks Davis     try {
102*b0d29bc4SBrooks Davis         is.seekg(0, std::ios::end);
103*b0d29bc4SBrooks Davis         const std::streampos length = is.tellg();
104*b0d29bc4SBrooks Davis         is.seekg(current_pos, std::ios::beg);
105*b0d29bc4SBrooks Davis         return static_cast< std::size_t >(length);
106*b0d29bc4SBrooks Davis     } catch (...) {
107*b0d29bc4SBrooks Davis         is.seekg(current_pos, std::ios::beg);
108*b0d29bc4SBrooks Davis         throw;
109*b0d29bc4SBrooks Davis     }
110*b0d29bc4SBrooks Davis }
111*b0d29bc4SBrooks Davis 
112*b0d29bc4SBrooks Davis 
113*b0d29bc4SBrooks Davis /// Reads a whole file into memory.
114*b0d29bc4SBrooks Davis ///
115*b0d29bc4SBrooks Davis /// \param path The file to read.
116*b0d29bc4SBrooks Davis ///
117*b0d29bc4SBrooks Davis /// \return A plain string containing the raw contents of the file.
118*b0d29bc4SBrooks Davis ///
119*b0d29bc4SBrooks Davis /// \throw std::runtime_error If the file cannot be opened.
120*b0d29bc4SBrooks Davis std::string
read_file(const fs::path & path)121*b0d29bc4SBrooks Davis utils::read_file(const fs::path& path)
122*b0d29bc4SBrooks Davis {
123*b0d29bc4SBrooks Davis     std::ifstream input(path.c_str());
124*b0d29bc4SBrooks Davis     if (!input)
125*b0d29bc4SBrooks Davis         throw std::runtime_error(F("Failed to open '%s' for read") % path);
126*b0d29bc4SBrooks Davis     return read_stream(input);
127*b0d29bc4SBrooks Davis }
128*b0d29bc4SBrooks Davis 
129*b0d29bc4SBrooks Davis 
130*b0d29bc4SBrooks Davis /// Reads the whole contents of a stream into memory.
131*b0d29bc4SBrooks Davis ///
132*b0d29bc4SBrooks Davis /// \param input The input stream from which to read.
133*b0d29bc4SBrooks Davis ///
134*b0d29bc4SBrooks Davis /// \return A plain string containing the raw contents of the file.
135*b0d29bc4SBrooks Davis std::string
read_stream(std::istream & input)136*b0d29bc4SBrooks Davis utils::read_stream(std::istream& input)
137*b0d29bc4SBrooks Davis {
138*b0d29bc4SBrooks Davis     std::ostringstream buffer;
139*b0d29bc4SBrooks Davis 
140*b0d29bc4SBrooks Davis     char tmp[1024];
141*b0d29bc4SBrooks Davis     while (input.good()) {
142*b0d29bc4SBrooks Davis         input.read(tmp, sizeof(tmp));
143*b0d29bc4SBrooks Davis         if (input.good() || input.eof()) {
144*b0d29bc4SBrooks Davis             buffer.write(tmp, input.gcount());
145*b0d29bc4SBrooks Davis         }
146*b0d29bc4SBrooks Davis     }
147*b0d29bc4SBrooks Davis 
148*b0d29bc4SBrooks Davis     return buffer.str();
149*b0d29bc4SBrooks Davis }
150