coan  6.0.1
A C/C++ Configuration Analyzer
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
io.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2004, 2006 Symbian Software Ltd. *
3  * All rights reserved. *
4  * Copyright (C) 2007-2013 Mike Kinghan, imk@burroingroingjoing.com *
5  * All rights reserved. *
6  * *
7  * Contributed originally by Mike Kinghan, imk@burroingroingjoing.com *
8  * *
9  * Redistribution and use in source and binary forms, with or without *
10  * modification, are permitted provided that the following conditions *
11  * are met: *
12  * *
13  * Redistributions of source code must retain the above copyright *
14  * notice, this list of conditions and the following disclaimer. *
15  * *
16  * Redistributions in binary form must reproduce the above copyright *
17  * notice, this list of conditions and the following disclaimer in the *
18  * documentation and/or other materials provided with the distribution. *
19  * *
20  * Neither the name of Symbian Software Ltd. nor the names of its *
21  * contributors may be used to endorse or promote products derived from *
22  * this software without specific prior written permission. *
23  * *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS *
31  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED *
32  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,*
33  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF *
34  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
35  * DAMAGE. *
36  * *
37  **************************************************************************/
38 #include "io.h"
39 #include "options.h"
40 #include "path.h"
41 #include "directive.h"
42 #include "diagnostic.h"
43 #include "symbol.h"
44 #include <fstream>
45 #include <iostream>
46 
51 using namespace std;
52 
53 string io::_in_filename_;
54 ostream * io::_output_(nullptr);
56 filebuf io::_outfile_;
57 istream * io::_input_(nullptr);
58 filebuf io::_infile_;
59 string io::_out_filename_;
60 string io::_bak_filename_;
61 char const * const io::_stdin_name_ = "[stdin]";
62 string io::_spin_dir_;
63 string io::_spin_prefix_;
64 
65 void io::top() {
67  _in_filename_.resize(0);
68 }
69 
71 {
72  if (remove(_in_filename_.c_str())) {
74  "Cannot remove file \"" << _in_filename_ << '\"' << emit();
75  }
76 }
77 
79 {
80  string filename;
81  int ch;
82  bool quoted;
83  ch = getchar();
84  /* Skip whitespace on stdin*/
85  for ( ; ch != EOF && isspace(ch); ch = getchar()) {};
86  if (ch == EOF) {
87  return filename;
88  }
89  quoted = ch == '\"';
90  if (quoted) {
91  for (ch = getchar() ; ch != EOF && ch != '\"'; ch = getchar()) {
92  if (isspace(ch) && ch != ' ') {
94  "Illegal whitespace in _input_ filename: \""
95  << filename << "..." << emit();
96  }
97  filename += ch;
98  }
99  if (ch == EOF) {
101  "A quoted _input_ filename is unterminated: \""
102  << filename << "..." << emit();
103  }
104  } else {
105  for ( ; ch != EOF && !isspace(ch); ch = getchar()) {
106  filename += ch;
107  }
108  }
109  return filename;
110 }
111 
113 {
114  path_t path(fs::real_path(_in_filename_));
115  path.pop_back();
116  path.push_back("coan_out_XXXXXX");
117  _out_filename_ = fs::tempname(path.str());
118  if (_out_filename_.empty()) {
119  abend_no_tempfile() << "Cannot create temporary file" << emit();
120  }
121 }
122 
124 {
125  if (rename(_out_filename_.c_str(),_in_filename_.c_str())) {
127  "Cannot rename file \"" << _out_filename_ << "\" as \""
128  << _in_filename_ << '\"' << emit();
129  } else if (_in_out_permissions_ != -1) {
130  _in_out_permissions_ =
131  fs::set_permissions(_in_filename_,_in_out_permissions_);
132  assert(_in_out_permissions_ != -1);
133  }
134 }
135 
136 void io::make_backup_name(string const & filename)
137 {
138  _bak_filename_ = filename;
139  do {
140  _bak_filename_ += options::backup_suffix();
141  } while(fs::obj_type(_bak_filename_) != fs::OBJ_NONE);
142 }
143 
145 {
146  make_backup_name(_in_filename_);
147  if (rename(_in_filename_.c_str(),
148  _bak_filename_.c_str())) {
150  "Cannot rename file \"" << _in_filename_ << "\" as \""
151  << _bak_filename_ << '\"' << emit();
152  }
153 }
154 
156 {
157  _outfile_.open(_out_filename_.c_str(),ios_base::out);
158  if (!_outfile_.is_open()) {
159  abend_cant_open_output() << "Can't open " <<
160  _out_filename_ << " for writing" << emit();
161  }
162  _output_ = new ostream(&_outfile_);
163 }
164 
166 {
167  delete _output_;
168  if (spin()) {
169  make_spinfile();
170  open_outfile();
171  } else if (options::replace()) {
172  make_tempfile();
173  open_outfile();
174  } else {
175  _output_ = new ostream(cout.rdbuf());
176  }
177 }
178 
179 void io::close(unsigned error)
180 {
181  delete _input_, _input_ = nullptr;
182  delete _output_, _output_ = nullptr;
183  _infile_.close();
184  _outfile_.close();
185  if (!error) {
186  if (options::replace() && !spin()) {
187  if (options::backup_suffix().length()) {
188  backup_infile();
189  } else {
190  delete_infile();
191  }
192  replace_infile();
193  }
194  } else {
195  if (!options::keep_going()) {
197  }
198  }
199  top();
200 }
201 
202 void io::open(string const & fname)
203 {
204  _in_filename_ = fname;
205  delete _input_;
206  if (fname != _stdin_name_) {
207  _in_out_permissions_ =
208  options::replace() ? fs::get_permissions(fname) : -1;
209  _infile_.open(fname.c_str(),ios_base::in);
210  if (!_infile_.is_open()) {
211  abend_cant_open_input() << "Can't open " <<
212  _in_filename_ << " for reading" << emit();
213  }
214  _input_ = new istream(&_infile_);
215  assert(_input_->good());
216  } else {
217  _input_ = new istream(cin.rdbuf());
218  }
219  open_output();
224  }
225 }
226 
227 void io::set_spin_dir(char const *optarg)
228 {
229  _spin_dir_ = fs::abs_path(optarg);
230 }
231 
232 void io::set_spin_prefix(char const *optarg)
233 {
234  _spin_prefix_ = fs::real_path(optarg);
235 }
236 
238 {
239  path_t spin_filename(_spin_dir_);
240  path_t in_filename(_in_filename_);
241  assert(fs::is_absolute(_in_filename_));
242  if (_spin_prefix_.empty()) {
243  spin_filename += in_filename.segment(1);
244  } else {
245  static path_t prefix(_spin_prefix_);
246  spin_filename += in_filename.segment(prefix.elements());
247  }
248  size_t parts = spin_filename.elements();
249  string dir = spin_filename.segment(0,parts - 1);
250  fs::make_dir(dir);
251  _out_filename_ = spin_filename.str();
252 }
253 
254 
255 /* EOF*/
abend_msg< 11 > abend_no_tempfile
Report cannot create a temporary file.
Definition: diagnostic.h:806
abend_msg< 8 > abend_illegal_filename
Report invalid filename input.
Definition: diagnostic.h:800
static char const *const _stdin_name_
Nominal filename for the standard input stream.
Definition: io.h:55
abend_msg< 3 > abend_eof_in_filename
Report end of input encountered while reading a quoted filename. a closing quotation was not found...
Definition: diagnostic.h:790
static void make_tempfile()
Create a temporary file to which output will be written.
Definition: io.cpp:112
permissions get_permissions(std::string const &filename)
void make_dir(std::string const &abs_path, bool recursive=true)
Create a directory given an absolute path name.
static fs::permissions _in_out_permissions_
File permissions mask of input file, in case file is replaced.
Definition: io.h:227
static void open_output()
Open an output stream for the current input file.
Definition: io.cpp:165
std::string segment(size_t start=0, size_t len=std::string::npos) const
Get a sub-sequence of the path's elements as a string.
Definition: path.h:165
static void top()
Reinitialize the module.
Definition: io.cpp:65
abend_msg< 1 > abend_cant_open_output
Report cannot open an output file.
Definition: diagnostic.h:784
bool is_absolute(std::string pathname)
Say whether a filename is absolute or relative.
std::string const & str() const
Get the path as a string.
Definition: path.h:106
static int exitcode()
Convert the internal exit status to an exit code for exit().
Definition: diagnostic.cpp:156
static void close(unsigned error)
Finalise the current pairing of source input and processed output, if any.
Definition: io.cpp:179
void pop_back()
Remove the last element of the path, if any.
Definition: path.h:187
static void make_backup_name(std::string const &filename)
Generate a filename for backing up an input file.
Definition: io.cpp:136
static std::istream * _input_
The input stream.
Definition: io.h:223
static std::string read_filename()
Read the name of a source file from stdin.
Definition: io.cpp:78
static std::string _spin_prefix_
Path prefix assumed to match the spin directory.
Definition: io.h:237
static void set_spin_prefix(char const *optarg)
Set a path prefix (of input files) that will be assumed to match the name of the spin directory...
Definition: io.cpp:232
static bool list_once_per_file()
Do we report the listed items just once per input file?
Definition: options.h:121
static std::ostream * _output_
The output stream.
Definition: io.h:221
static std::filebuf _outfile_
The output file.
Definition: io.h:233
static void top()
Reinitialize the class static state.
The tag class is inserted in a diagnostic_base to tell it to emit itself.
Definition: diagnostic.h:77
abend_msg< 2 > abend_cant_open_input
Report cannot open an input file.
Definition: diagnostic.h:786
static void make_spinfile()
Create an output file in the spin directory corresponding to an input file.
Definition: io.cpp:237
static std::string _out_filename_
Current output filename, if needed.
Definition: io.h:229
static void per_file_init()
Delete all transient symbols from the symbol table.
static void open_outfile()
Open the output file.
Definition: io.cpp:155
size_t elements() const
Get the number of elements in the path
Definition: path.h:101
static bool keep_going()
Shall we continue to process input files after errors?
Definition: options.h:191
An error diagnostic.
void push_back(std::string const &str)
Append a string to the path.
Definition: path.h:178
static void delete_infile()
Delete the current input source file.
Definition: io.cpp:70
static bool replace()
Do we replace input files with output files?
Definition: options.h:109
static std::string _spin_dir_
Name of directory in which to output a spin.
Definition: io.h:235
int set_permissions(std::string const &filename, permissions p)
static void set_spin_dir(char const *optarg)
Set the directory in which to output a spin.
Definition: io.cpp:227
static void erase_all()
Forget all directives table used by the operative command.
std::string abs_path(std::string const &filename)
Get the absolute pathname for a filename.
static std::string const & backup_suffix()
Get the file backup name suffix.
Definition: options.h:101
std::string real_path(std::string const &relname)
Get the absolute real pathname of a file or directory name.
static std::string _in_filename_
The name of the current source file.
Definition: io.h:219
static void replace_infile()
Replace the current input source file with the temporary output file.
Definition: io.cpp:123
obj_type_t obj_type(std::string const &name)
Get the type of the object putatively designated by a filename.
static void backup_infile()
Backup the current input source file.
Definition: io.cpp:144
std::string tempname(std::string const &format)
Create a tempory filename from a template.
static void open(std::string const &fname)
Open an input file and the appropriate output file.
Definition: io.cpp:202
abend_msg< 9 > abend_cant_delete_file
Report failure to delete a file.
Definition: diagnostic.h:802
char * optarg
Argument to an option parsed by getopt_long()
Definition: get_options.cpp:49
abend_msg< 10 > abend_cant_rename_file
Report failure to rename a file.
Definition: diagnostic.h:804
static std::filebuf _infile_
The input file.
Definition: io.h:225
static std::string _bak_filename_
Backup filename, if needed.
Definition: io.h:231
No such object.
Definition: filesys.h:51
int permissions
Type of file permissions mask.
Definition: filesys.h:147