All the code in this book is designed to compile as shown
without errors. Lines of code that should generate a compile-time error may be
commented out with the special comment sequence //! . The following program
will remove these special comments and append a numbered comment to the line.
When you run your compiler, it should generate error messages, and you will see
all the numbers appear when you compile all the files. This program also
appends the modified line to a special file so that you can easily locate any
lines that don t generate errors.
//: C04:Showerr.cpp {RunByHand}
// Un-comment error generators.
#include <cstddef>
#include <cstdlib>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include "../require.h"
using namespace std;
const string USAGE =
"usage: showerr filename chapnum\n"
"where filename is a C++ source file\n"
"and chapnum is the chapter name it's
in.\n"
"Finds lines commented with //! and
removes\n"
"the comment, appending //(#) where # is
unique\n"
"across all files, so you can determine\n"
"if your compiler finds the error.\n"
"showerr /r\n"
"resets the unique counter.";
class Showerr {
const int CHAP;
const string MARKER, FNAME;
// File containing error number counter:
const string ERRNUM;
// File containing error lines:
const string ERRFILE;
stringstream edited; // Edited file
int counter;
public:
Showerr(const string& f, const string& en,
const string& ef, int c)
: CHAP(c), MARKER("//!"), FNAME(f),
ERRNUM(en),
ERRFILE(ef), counter(0) {}
void replaceErrors() {
ifstream infile(FNAME.c_str());
assure(infile, FNAME.c_str());
ifstream count(ERRNUM.c_str());
if(count) count >> counter;
int linecount = 1;
string buf;
ofstream errlines(ERRFILE.c_str(), ios::app);
assure(errlines, ERRFILE.c_str());
while(getline(infile, buf)) {
// Find marker at start of line:
size_t pos = buf.find(MARKER);
if(pos != string::npos) {
// Erase marker:
buf.erase(pos, MARKER.size() + 1);
// Append counter & error info:
ostringstream out;
out << buf << " // ("
<< ++counter << ") "
<< "Chapter " << CHAP
<< " File: " << FNAME
<< " Line " <<
linecount << endl;
edited << out.str();
errlines << out.str(); // Append error
file
}
else
edited << buf << "\n"; //
Just copy
++linecount;
}
}
void saveFiles() {
ofstream outfile(FNAME.c_str()); // Overwrites
assure(outfile, FNAME.c_str());
outfile << edited.rdbuf();
ofstream count(ERRNUM.c_str()); // Overwrites
assure(count, ERRNUM.c_str());
count << counter; // Save new counter
}
};
int main(int argc, char* argv[]) {
const string ERRCOUNT("../errnum.txt"),
ERRFILE("../errlines.txt");
requireMinArgs(argc, 1, USAGE.c_str());
if(argv[1][0] == '/' || argv[1][0] == '-') {
// Allow for other switches:
switch(argv[1][1]) {
case 'r': case 'R':
cout << "reset counter"
<< endl;
remove(ERRCOUNT.c_str()); // Delete files
remove(ERRFILE.c_str());
return EXIT_SUCCESS;
default:
cerr << USAGE << endl;
return EXIT_FAILURE;
}
}
if(argc == 3) {
Showerr s(argv[1], ERRCOUNT, ERRFILE, atoi(argv[2]));
s.replaceErrors();
s.saveFiles();
}
} ///:~
You can replace the marker with one of your choice.
Each file is read a line at a time, and each line is
searched for the marker appearing at the head of the line; the line is modified
and put into the error line list and into the string stream, edited.
When the whole file is processed, it is closed (by reaching the end of a
scope), it is reopened as an output file, and edited is poured into the
file. Also notice the counter is saved in an external file. The next time this
program is invoked, it continues to increment the counter.