// This program records the number of occurances of
// all 95 printable ASCII characters
// Computer Science III
// Nick Cash -- August 22, 2006
// Input:
// The program will prompt for the file name of an input file to read from.
// Output:
// The program will then prompt for a file name of an output file to write to.
// Assumptions:
// The input file contains only printable characters from space to tilde
// and control characters marking the end of lines and the end of file.
// File names contain no more than 80 characters.
// includes
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <map>
using namespace std;
// for easier coding, make a typedef
typedef map<char, int> CharMap;
// function prototypes
void GetInput( ifstream& in, ofstream& out );
void ParseInput( ifstream& in, CharMap& map );
bool WriteData( ofstream& out, CharMap& map );
// Main function. Calls
int main(int argc, char *argv[])
{
CharMap char_occur; // store the occurances of each printable character
CharMap::iterator nl; // used to find the newline entry in the map
ifstream ifile; // input file handle
ofstream ofile; // output file handle
// Gather input and perform error checking
// When complete we have two open file handles
GetInput( ifile, ofile );
// Fill the map by reading the data
ParseInput( ifile, char_occur );
// display the number of lines in the input file, remove newlines from the map
nl = char_occur.find('\n');
if ( nl == char_occur.end() )
cout << "\n\nThe input was 1 line long.\n\n";
else
printf( "\n\nThe input was %d line%s long.\n\n", nl->second, (nl->second == 1 ? "" : "s" ));
// delete newline from map
char_occur.erase(nl);
// Write out the data. The function closes the file.
return WriteData(ofile, char_occur);
}
// GetInput: Gather and check file names supplied by the user.
// PreCondition: Supplied two closed file handles
// PostCondition: in/out are opened
void GetInput( ifstream& in, ofstream& out )
{
string input, output; // input/output filenames
// Validate references
if ( !in || !out )
{
cout << "\n\nGetInput: Critical error, exiting...\n\n";
exit(EXIT_FAILURE);
}
// When finished we will have an input file name stored in input
// of no more than 80 characters and an open file
// It prompts for input and checks the length each iteration.
while ( input.length() <= 0 )
{
cout << "\n\nInput file> ";
cin >> input;
if ( input.length() > 80 || input.length() <= 0 )
{
cout << "\n\nError: Bad filename. Try a shorter one.\n\n";
input = ""; // clear the string
continue;
}
// make sure input exists
in.open(input.c_str(), ios_base::in);
if ( !in.is_open())
{
cout << "\n\nError: Input file does not exist.\n\n";
input = "";
}
}
// When finished we will have an output file name stored in output
// of no more than 80 characters and an open output file
// It prompts for output and checks the length each iteration.
while ( output.length() <= 0 )
{
cout << "\n\nOutput file> ";
cin >> output;
if ( output.length() > 80 || output.length() <= 0 )
{
cout << "\n\nError: Bad filename. Try a shorter one.\n\n";
output = ""; // clear the string
continue;
}
// make sure file names are not the same
if ( input == output )
{
cout << "\n\nError: Input and Output file names match. Enter different file names.\n\n";
output = "";
continue;
}
// make sure the output name is valid
out.open(output.c_str(), ios_base::out);
if ( !out.is_open())
{
cout << "\n\nError: Bad output filename.\n\n";
out.close(); // close in-file
output = "";
}
}
}
// ParseInput: Read in each character and update counts.
// PreCondition: Supplied an open file stream to read from, and a map to insert into
// PostCondition: The data is in the map, the file stream is closed
void ParseInput( ifstream& in, CharMap& map )
{
char c; // temporary holder for characters
CharMap::iterator i; // iterator used in the loop
if ( !in.is_open() )
{
cout << "\n\nParseInput: Critical error, exiting...\n\n";
exit(EXIT_FAILURE);
}
// Grab a character and add it to the map. If it exists in the map, increase its count.
// Case-sensitive. Loop until end of file is reached.
// When complete the character map will be full of printable characters.
while ( !in.eof() )
{
c = in.get();
// end of file
if ( c == '\0' )
break;
// we don't want to record anything unprintable
if ( (c < ' ' || c > '~') && c != '\n' )
continue;
i = map.find(c);
// if it wasnt found in the map, add it, otherwise increment its occurance
if ( i == map.end() )
map[c] = 1;
else
i->second++;
}
in.close();
}
// WriteData: Write out data, close file
// PreCondition: Supplied the open file stream to write to and the CharMap data to write
// PostCondition: Returns EXIT_SUCESS or EXIT_FAILURE to complete the program
bool WriteData( ofstream& out, CharMap& map )
{
char buf[32]; // temporary buffer to hold string contents
// make sure ofstream is valid
if (!out.is_open())
{
cout << "\n\nWriteData: Critical error, exiting...\n\n";
return EXIT_FAILURE;
}
// Print out the number of occurances for each printable character
// in alphabetical order
// When complete, the program is finished
for ( CharMap::const_iterator i = map.begin(); i != map.end(); i++ )
{
sprintf( buf, "%c occurred %4d times\n", i->first, i->second );
out << buf;
buf[0] = '\0';
}
out.close();
return EXIT_SUCCESS;
}