Tuesday, July 4, 2017

Programming Challenge 12.9 - File Encryption Filter

Example Files: long.txt
                          encrypted.txt


/* File Encryption Filter - File encryption is the science of writing the
    contents of a file in secret code. This encryption program works like
    a filter, reading the contents of one file, modifying the data into a
    code, and then writing the coded contents out to a second file. The
    second file is a version of the first file, but written in secret code. */

#include "Utility.h"

int  readFile(fstream &, string &);
string encryptText(string);
int writeFile(fstream &, const string);

int main()
{
    fstream textFile;
    fstream textCrypt;

    int    fOpen = 0;
    string clearText = "";
    string encrypted = "";

    cout << "File Encryption Filter\n\n";

    fOpen = readFile(textFile, clearText);

    if (fOpen != -1)
    {
        cout << "\nYour file will be encrypted now ...\n";
        encrypted = encryptText(clearText);

        cout << "File encrypted. Writing encrypted text to file ...\n";
        writeFile(textCrypt, encrypted);

        if (fOpen != -1)
        {
            cout << "\nFile successfully created. You can now close this program.\n"
                  << "Have a nice day!";
        }
    }

   pauseSystem();
   return 0;
}

/* **********************************************************
    Definition: readFile

    This function uses a reference parameter to an fstream
    object and a reference to a string object as parameters.
    Upon success, the contents of the file is read-in and
    stored in a string object.
   ********************************************************** */

int readFile(fstream &textFile, string &clearText)
{
    string fileName = "";
    string tmpText = " ";

    cout << "Enter name of file you wish to open: ";
    cin >> fileName;

    textFile.open(fileName, ios::in);

    if (!textFile.fail())
    {
        while (getline(textFile, tmpText))
        {
            clearText += tmpText + " ";
        }
    }
    else
    {
        cout << "\nFile Read Error. Could not read " << fileName;
        return -1;
    }
    textFile.close();

    return 0;
}

/* **********************************************************
    Definition: encryptText

    This function uses a string object as parameters. The
    contents in the string object is encrypted, and the string
    returned.
   ********************************************************** */

string encryptText(string encrypted)
{
    int basEnc = 0;
    int locEnc = 0;
    int locFin = 0;
    int locTxt = 0;

    basEnc = 32 / 3;
    locEnc = (5 + (basEnc + 5) * (basEnc + basEnc / 8));
    locFin = ((3 * basEnc) + (locEnc - 6));
    locTxt = ((1 - (basEnc + locEnc) * (basEnc + locEnc)) + locFin);

    for (int i = 0; i < encrypted.size(); i++)
    {
        encrypted[i] += locTxt + locFin / locEnc;       
    }

    return encrypted;
}

/* **********************************************************
    Definition: writeFile

    This uses a reference to an fstream object and a constant
    string object variable as parameters. Upon success, the
    file is opened, and the encrypted text contained in the
    string object is written to it.
   ********************************************************** */

int writeFile(fstream &cryptText, const string encrypted)
{
    string fileName = "";

    cout << "\nEnter name of file you wish to write to: ";
    cin >> fileName;

    cryptText.open(fileName, ios::out);
   
    if (!cryptText.fail())
    {   
        cryptText << encrypted;
    }
    else
    {
        cout << "File Write Error. Could not write data to " << fileName;
        return -1;
    }
    cryptText.close();

    return 0;
}

Example Output:




Monday, July 3, 2017

Programming Challenge 12.8 - Array/File Functions

/* Array/File Functions - This program contains a function named arrayToFile.
    It accepts three arguments:
   
        * The name of a file
        * A pointer to an int array
        * The size of the array

    The function opens the specified file in binary mode, writes the contents
    of the array to the file, and the closes the file.

    It also contains another function named fileToArray. This functions accepts
    three arguments:

        * The name of a file
        * A pointer to an int array
        * The size of the array

    The function opens the specified file in binary mode, reads its contents
    into the array, and then closes the file.

    The functions are demonstrated in this program, by using the arrayToFile
    function to write an array to a file, and then using the fileToArray function
    to read the data from the same file. After the data are read from the file
    into the array, the array's contents are displayed on the screen. */

#include "Utility.h"

void rNumGenerator(int *, const int);
int  arrayToFile(const string fileName, int *, const int);
int  fileToArray(const string fileName, int *, const int);
void displayArray(const int *, const int);

int main()
{
    const int NUMELS = 6;

    int     lotteryNumbers[NUMELS] = { 0 };
    int     fOpenErr = 0;
    string fileName = "";

    cout << "ARRAY/FILE FUNCTIONS.\n\n"
          << "This program demonstrates two functions. One writes an array\n"
          << "containing RNG-numbers to a file in binary mode, the other reads\n"
          << "the contents of the file into an array. If both operations are\n"
          << "successful, the contents of the array is displayed.\n\n";

    cout << "Enter the name of a file to write to: ";
    cin >> fileName;

    fOpenErr = arrayToFile(fileName, lotteryNumbers, NUMELS);

    if (fOpenErr != -1)
    {
        cout << "Enter the name of a file to read from: ";
        cin >> fileName;

        fileToArray(fileName, lotteryNumbers, NUMELS);
    }

   pauseSystem();
   return 0;
}

/* **********************************************************
   Definition: rNumGenerator

    This function accepts a pointer to an array and its size
    as parameters. It fills the array with 6 random numbers.
   ********************************************************** */

void rNumGenerator(int *lotteryNums, const int NUMELS)
{
    const int HIGHEST_NUM = 45,
               LOWEST_NUM = 1;

    int lastNum = 0;
    int count = 0;
   
    srand((unsigned int)time(0));

    while (count < NUMELS)
    {
        lastNum = (rand() % (HIGHEST_NUM - LOWEST_NUM + 1) + LOWEST_NUM);
       
        if (lastNum != 0)
        {
            *(lotteryNums + count) = lastNum;
        }

        count++;
    }
}

/* **********************************************************
   Definition: arrayToFile

    This functions accepts the name of a file, a pointer to an
    integer array, and the size of the array as parameters. It
    opens the file in binary mode, writes the contents of the
    array to the file, and the closes the file.
   ********************************************************** */

int arrayToFile(const string fileName, int *lotteryNums, const int NUMELS)
{
    char *arrPtr = nullptr;

    rNumGenerator(lotteryNums, NUMELS);

    fstream toFile(fileName, ios::out | ios::binary);

    if (!toFile.fail())
    {

        cout << "\nWriting array data to file ...\n";
        toFile.write(reinterpret_cast<char *>(lotteryNums), sizeof(lotteryNums));
        cout << "Array contents successfully written to file.\n"
              << "Now closing " << fileName << "\n\n";
    }
    else
    {
        cout << "\nFile Writing Error. Array contents could not be written to file ...\n"
              << "Press enter to close this program.";
        return -1;
    }
    toFile.close();

    return 0;
}

/* **********************************************************
   Definition: fileToArray

    This functions accepts the name of a file, a pointer to an
    integer array, and the size of the array as parameters. It
    opens the file in binary mode, reads its contents into the
    array, and then closes the file.
   ********************************************************** */

int fileToArray(const string fileName, int *lotteryNums, const int NUMELS)
{
    char *arrPtr = nullptr;

    fstream fromFile(fileName, ios::binary | ios::in);
   
    if (!fromFile.fail())
    {
        cout << "\nReading in file-contents ...\n";
        fromFile.read(reinterpret_cast<char *>(lotteryNums), sizeof(lotteryNums));
        cout << "File contents successfully read into array.\n"
              << "Now closing " << fileName << "\n\n";

        cout << "\nThis is the array's contents: ";
        displayArray(lotteryNums, NUMELS);
    }
    else
    {
        cout << "File Reading Error. Could not read " << fileName << " ...";
        return -1;
    }
    fromFile.close();

    return 0;
}

/* **********************************************************
   Definition: displayArray

    This functions accepts a constant pointer to an integer
    array, and the size of the array as parameters. It outputs
    the contents of the array to screen.
   ********************************************************** */

void displayArray(const int *lotteryNums, const int NUMELS)
{
    for (int i = 0; i < NUMELS; i++)
    {
        cout << *(lotteryNums + i) << " ";
    }
}

Example Output:






Programming Challenge 12.7 - Sentence Filter

Example Files: capitalizer.txt
                         capitalized.txt


/* Sentence Filter - This program asks the user for two file names. The
    first is opened for input and the second file is opened for output.
    (It is assumed that the first file contains sentences that end with
    a period.) The program reads the contents of the first file and changes
    all the letters to lowercase except the first letter of each sentence,
    which is made uppercase. The revised contents is stored in the second
    file. */

#include "Utility.h"

int  fileIO();
void senDecapitalizer(string &);
void wordCapitalizer(string &);


int main()
{
    cout << "SENTENCE FILTER\n\n";

    fileIO();

   pauseSystem();
   return 0;
}

/* **********************************************************
   Definition: fileIO

    This function first attempts to open and read-in text from
    a file. Upon success, the text is processed, and the file
    is closed. Another file is opened for output. If the file
    is created successfully, the processed text is output to
    the file. If one or both file operations fail, an error
    message is displayed, and the program exits.
   ********************************************************** */

int fileIO()
{
    string tmpText = "";
    string sentence = "";

    fstream readFrom;
    fstream writeTo;

    readFrom.open("capitalizer.txt", ios::in);

    if (!readFrom.fail())
    {
        cout << "Reading in contents of text file ...";

        while (getline(readFrom, tmpText))
        {       
            senDecapitalizer(tmpText);
            wordCapitalizer(sentence);

            sentence += tmpText + "\n";
        }
        cout << "\nFile successfully processed.\n\n";
    }
    else
    {
        cout << "File open error. Now exiting the program ...";
        return -1;
    }
    readFrom.close();
   
    cout << "Now closing the file ..\n";

    /* Write data to the file */
    writeTo.open("capitalized.txt", ios::out);

    if (!writeTo.fail())
    {
        cout << "\nWriting text to the file ...";
        writeTo << sentence << " ";

        cout << "\nText successfully written to file.\n";
    }
    else
    {
        cout << "\nFile Writing Error. Unable to create or process file ...\n"
              << "Press enter to exit this program.";
        return -1;
    }
    writeTo.close();

    cout << "\nPress enter to close this program ...";

    return 0;
}

/* **********************************************************
   Definition: senDecapitalizer

   This function accepts a reference to a string object as
    its parameter. It replaces all uppercase characters found
    in a sentence by their lowercase equivalent.
   ********************************************************** */

void senDecapitalizer(string &sentence)
{
    for (unsigned int index = 0; index < sentence.length(); index++)
    {
        if (isupper(sentence[index]))
        {
            sentence[index] = tolower(sentence[index]);
        }
    }
}

/* **********************************************************
   Definition: wordCapitalizer

    This function accepts a reference to a string object as
    its parameter. It turns all letters found at the beginning
    of a sentence to uppercase.
   ********************************************************** */

void wordCapitalizer(string &sentence)
{
    bool isDelim = false;

    for (unsigned int index = 0; index < sentence.length(); index++)
    {
        if (sentence.at(index) == '.' || sentence.at(index) == '!' ||
            sentence.at(index) == '?' || sentence.at(index) == ';')
        {
            isDelim = false;
        }

        if (isalpha(sentence.at(index)) && isDelim == false)
        {
            isDelim = true;
            sentence.at(index) = toupper(sentence.at(index));
        }
    }
}

Example Output:




Sunday, July 2, 2017

Programming Challenge 12.6 - String Search

Example-File: short.txt
Include-File: UtilityCls.h


/* String Search - This program asks the user for a file name and a string
    to search for. The program searches the file for every occurrence of a
    specified string. When the string is found, the line that contains it is
    displayed. After all the occurrences have been located, the program reports
    the number of times the string appeared in the file. */

#include "UtilityCls.h"

struct GetFile
{
    string fileName;        /* The file name    */
    fstream textFile;        /* fstream object */

    GetFile(string fName = "")
    {
        fileName = fName;
    }

    ~GetFile()
    {
    }
};

struct TextSearch
{
    int    timesFound;        /* Counts the occurrences of words found in the text        */
    string searchWord;        /* Holds the word to search for in the text                    */
    string delimList;            /* Holds a list of delimiting characters                        */
    string tmpText;            /* A temporary variable to hold text while it is read in */
    string getText;            /* Holds the text read in from the file                        */
    string searchResult;        /* Holds the search result                                            */

    TextSearch(int cnt = 0, string dlmLst = ".:)(!?\";,", string sw = " ",
                string gTxt = " ", string sRes = " ")
    {
        timesFound = cnt;
        searchWord = sw;
        delimList = dlmLst;
        getText = gTxt;
        searchResult = sRes;
    }

    ~TextSearch()
    {
    }
};

void menu(GetFile &, TextSearch &);
char tryAgain();
void getFileName(GetFile &);
int  openFile(GetFile &, TextSearch &);
void getSearchWord(TextSearch &);
void changeCase(TextSearch &);
void removePunct(TextSearch &);
void performTextSearch(TextSearch &, const string);
void getWordFreq(TextSearch &);
void displayResult(const TextSearch &);
void cleanUp(GetFile &, TextSearch &);

int main()
{
    GetFile fileData;
    TextSearch search;
   
    menu(fileData, search);

    pauseSystem();
    return 0;
}

/* **********************************************************
    Definition: menu

    This function uses a two structure reference parameters.
    It offers a basic menu and introduction to the program.
    ********************************************************** */

void menu(GetFile &fileData, TextSearch &search)
{
    int  fOpen = 0;
    char again = ' ';

    cout << "\n\tText Search\n\n"
          << "\tThis program allows you to search for a word\n"
          << "\tin any given text-file. It will only find whole\n"
          << "\twords. To give you an example, if you type in the\n"
          << "\tword 'is', it will only find and display this word\n"
          << "\tand sentences that contain it. If 'is' is part of\n"
          << "\tanother word, like 'this', it will not be found.\n\n";

    do
    {
        fOpen = openFile(fileData, search);

        if (fOpen != -1)
        {
            cout << "\n\n\tText Search - Search Result\n\n";
            displayResult(search);
        }

        again = tryAgain();

        if (again == 'N')
        {
            cout << "\n\tThank you for trying this program!";
        }
        else
        {
            clearScreen();
            cleanUp(fileData, search);
        }
    } while (again != 'N');
}

/* **********************************************************
    Definition: openFile

    This function uses a two structure reference parameters as
    its arguments. First, the user is asked to enter a file
    name. If the file exists and is opened successfully, the
    user is asked to enter a word to search for. Then the file
    contents is read in and processed by other functions,
    while the text is being read-in. In case of an error, an
    error message is displayed, and the function exits.
    ********************************************************** */

int openFile(GetFile &fileData, TextSearch &search)
{
    string tmpText = "";

    getFileName(fileData);

    while (fileData.fileName.empty())
    {
        cin >> fileData.fileName;
    }

    /* Open the file for reading */
    fileData.textFile.open(fileData.fileName, ios::in);

    if (!fileData.textFile.fail())
    {
        getSearchWord(search);

            while (getline(fileData.textFile, tmpText))
            {       
                search.getText = ' ' + tmpText + ' ';

                removePunct(search);
                changeCase(search);
                performTextSearch(search, tmpText);
                getWordFreq(search);
            }
    }
    else
    {
        cout << "\tFile open error: " << fileData.fileName
              << " could not be openend.";
        return -1;
    }
    fileData.textFile.close();

    return 0;
}

/* **********************************************************
    Definition: getSearchWord

    This function uses a structure reference parameter. The
    user is asked to enter a word to search for. If the word
    contains uppercase letters, they are changed to lowercase.
    This allows to search for 'Pac-man' as well as 'pAc-Man'
    or any other variation of casing letters.
    ********************************************************** */

void getSearchWord(TextSearch &search)
{
    cout << "\tPlease enter a word to search for: ";
    cin >> search.searchWord;

    while (search.searchWord.empty() || search.searchWord == "\0")
    {
        cout << "\tPlease enter a word to search for: ";
        cin >> search.searchWord;
    }

    for (size_t i = 0; i < search.searchWord.size(); i++)
    if (isupper(search.searchWord.at(i)))
    {
        search.searchWord.at(i) = tolower(search.searchWord.at(i));
    }
}

/* **********************************************************
    Definition: getFileName

    This function uses a structure reference as parameter. It
    asks the user for a filename. If the filename does not
    contain a file-extension, for example '.txt', it is added,
    and the filename stored in a struct member variable. If a
    file-extension has been entered, the filename is stored,
    and the function exits.
    ********************************************************** */

void getFileName(GetFile &getName)
{
    string fileExt = ".txt";

    cout << "\n\tPlease enter a file name: ";
    cin >> getName.fileName;

    if (getName.fileName.find(".") != string::npos)
    {
        getName.fileName;
    }
    else
    {
        getName.fileName.append(fileExt);
    }
}
/* **********************************************************
    Definition: changeCase

    This function uses a structure reference parameter. It
    turns all uppercase letters found in a text to lowercase.
    ********************************************************** */

void changeCase(TextSearch &search)
{
    for (int i = 0; i < search.getText.size(); i++)
    {
        search.getText[i] = tolower(search.getText[i]);
    }
}

/* **********************************************************
    Definition: removePunct

    This function uses a structure reference parameter. It
    finds and removes selected punctuation characters. Once
    done, the text stored in a structure member variable.
    ********************************************************** */

void removePunct(TextSearch &search)
{
    for (int i = 0; i < search.delimList.size(); i++)
    {
        search.getText.erase(remove(search.getText.begin(), search.getText.end(),
                                             search.delimList.at(i)), search.getText.end());
    }
}

/* **********************************************************
    Definition: performTextSearch

    This function uses a structure reference parameter and a
    string object holding the unprocessesed text. It searches
    for the occurence of the word. If a match is found, the
    sentence(s) containing it are stored in the appropriate
    structure member variable.
    ********************************************************** */

void performTextSearch(TextSearch &search, const string tmpText)
{
    if (search.getText.find(' ' + search.searchWord + ' ') != string::npos)
    {
        search.searchResult.append("\t" + tmpText + "\n");
    }
}

/* **********************************************************
    Definition: getWordFreq

    This function uses a structure reference variable as its
    argument. It contains a stringstream object, which, word
    by word, extracts the text from a struct member variable
    holding the full text. It searches for an occurence of the
    word input by the user. If a match is found, a counter,
    which is another struct member variable, increments.
    ********************************************************** */

void getWordFreq(TextSearch &search)
{
    stringstream ss(search.getText);

    while (ss >> search.getText)
    {
        if (search.getText == search.searchWord)
        {
            ++(search.timesFound);
        }
    }
}

/* **********************************************************
    Definition: displayResult

    This function uses a constant structure reference variable
    as its argument. If the word to be searched for has been
    found, the word, the sentence(s) contaninig this word, and
    the number of matches is displayed. If there is no match,
    the user is informed by a message about the fact.
    ********************************************************** */

void displayResult(const TextSearch &search)
{
    if (search.timesFound != 0)
    {
        cout << "\n\tYour search word: " << search.searchWord << " was found "
            << search.timesFound << " times.\n";

        cout << "\n\tThe following sentence(s) contain this word:\n\n"
            << search.searchResult;
    }
    else
    {
        cout << "\n\tNo match found for your search word: " << search.searchWord;
    }
}

/* **********************************************************
    Definition: tryAgain

    This function asks the user if he or she wishes to try
    again. This decision is returned.
    ********************************************************** */

char tryAgain()
{
    char again = ' ';

    cout << "\n\n\tDo you wish to perform another search? ";
    cin >> again;
    cin.ignore();

    /* Input validation */
    while (toupper(again) != 'Y' && toupper(again) != 'N')
    {
        cout << "\n\tDo you wish to perform another search? ";
        cin >> again;
        cin.ignore();
    }

    return toupper(again);
}

/* **********************************************************
    Definition: cleanUp

    This function uses two structure reference parameters. It
    clears any content present in the struct member variables.
    This is necessary to be able to perform another search
    without exiting the program.
    ********************************************************** */

void cleanUp(GetFile &clean, TextSearch &search)
{
    clean.fileName.clear();
    clean.textFile.clear();
    search.getText.clear();
    search.timesFound = 0;
    search.searchWord.clear();
    search.searchResult.clear();
}

Example Output:






Thursday, June 22, 2017

[Update] Programming Challenge 12.2

Without being aware of it, the code written for Programming Challenge 12.2 already contained, what was asked for in 12.5: It displayed the line numbers next to whatever text a file contains. That being the case I had to make a decision:

1.) I post a link and explain that, instead of actual code, this is the link to Programming Challenge 12.2 and here is why.
2.) I alter the Programming Challenge 12.2, remove the line that displays the line numbers, take screenshots, update the code, and explain the reason for doing so.

Although I hate to alter code once it is published, it was a good decision this time around. The reason being that there are two example files attached to both Programming Challenges. One contains a long one a short text. In case of the latter it is indeed shorter, yet still contains more than 24 lines of text. I don't even know why, upon testing my program, this went unnoticed. It makes absolutely no sense at all! I can only guess that, originally, it should contain less than 24 lines, to demonstrate that "Press Enter to continue" would not be triggered upon executing the program. Whatever the reason, an updated version of short.txt is online, which now contains less than 24 lines.

Now it is back to my IDE. I wish my visitors, occasional and regular, as well as my fellow learners, to you manage to be productive today, and you, unlike I, don't have to suffer to much under the remorseless heat of summer.

Programming Challenge 12.5 - Line Numbers

Example Files: long.txt
                          short.txt


/* Line Numbers - This is a modification of Programming Challenge 12.2
   The program asks the user for the name of a file. The program displays
    the contents of the file on the screen. Each line of screen output is
    preceded with a line number, followed by a colon. The line numbering
    starts at 1. If the file's contents won't fit on a single screen, the
    program displays 24 lines of output at a time, and then pauses. Each
    time the program pauses, it waits for the user to strike a key before
    the next 24 lines are displayed. */

#include "Utility.h"

void openFile();
bool isGood(fstream &, const string);
void displayText(const vector<string>);

int main()
{
    openFile();

   pauseSystem();
   return 0;
}

/* **********************************************************
   Definition: openFile

    This function reads in and stores the contents of a text
    file in a vector of string objects.
   ********************************************************** */

void openFile()
{
    string  fileName = " ";            /* To hold the file name */
    string  tmpText = " ";            /* To hold the text         */  
    fstream textFile;                    /* File stream object     */

    vector<string> gamesText;        /* Vector of string objects to hold
                                               the file contents */

    cout << "\n\tLINE NUMBERS\n\n"
         << "\tEnter the name of the file you wish to open: ";
    cin >> fileName;

    if (isGood(textFile, fileName))
    {
        while (getline(textFile, tmpText))
        {
            gamesText.push_back(tmpText);
        }
        textFile.close();

        displayText(gamesText);
    }
    else
    {
        cout << "\tERROR: Cannot open the file.\n"
              << "\tPress Enter or click [X] to exit ...\n";
    }
}

/* **********************************************************
   Definition: isGood

    This function accepts a reference to an fstream object as
    argument. The file is opened for input. The function
    returns true upon success, false upon failure.
   ********************************************************** */

bool isGood(fstream &textFile, const string fileName)
{
    textFile.open(fileName, ios::in);

    if (!textFile.fail())
    {
        return true;
    }
    else
    {
        return false;
    }
}

/* **********************************************************
   Definition: displayText

    This function accepts a vector of string objects as its
    argument. It displays the contents of the string object.
    After every 24 lines of text being output to screen, the
    user is asked to press Enter to continue. If the remaining
    number of lines is less then 24, they are displayed. Else
    the process repeats, until the end of text is reached.
   ********************************************************** */

void displayText(const vector<string> gamesText)
{
    int numLines = 0;

    cout << "\n";
    cin.ignore();

    while (numLines < gamesText.size())
    {
        numLines++;
      
        cout << "\t" << setw(3) << right << numLines << ": "
              << gamesText[numLines-1] << setw(6) << right << "\n";

        if (numLines % 24 == 0)
        {
            cout << "\n\tPress Enter to continue:";
            cin.get();
            cout << "\n";
        }
    }

    if (gamesText.size())
    {
        cout << "\n\tEnd of text.\n"
              << "\tPress Enter to exit this program.";
    }
}

Example Output:






Programming Challenge 12.4 - Tail Program

Example Files: tailLong.txt
                         tailShort.txt


/* Tail Program - This program asks the user for the name of a file.
    The program displays the last 10 lines of the file on the screen
    (the 'tail' of the file). If the file has fewer than 10 lines, the
    entire file is displayed, with a message indicating the entire file
    has been displayed. */

#include "Utility.h"

void menu();
void openFile();
bool isGood(fstream &tail, const string fileName);
void displayText(const vector<string>, const int numLines);

int main()
{
    menu();

   pauseSystem();
   return 0;
}

/* **********************************************************
   Definition: menu

    This function provides a basic menu. An introduction is
    displayed, and a function to open a file is called. If the
    user wishes, he or she can open another file, or exit the
    program.
   ********************************************************** */

void menu()
{
    char again = ' ';

    cout << "\n\tFILE TAIL PROGRAM\n\n"
          << "\tThis program displays the 'Tail of a file.' This means\n"
          << "\tthat, if a file contains more than 10 lines of text, only\n"
          << "\tthe last 10 lines will be displayed. If it contains fewer\n"
          << "\tthan 10 lines, the full text is displayed.\n\n";

    do
    {
        openFile();

        cout << "\n\tDo you wish to open another file [y/N]? ";
        cin >> again;

        while (toupper(again) != 'Y' && toupper(again) != 'N')
        {
            cout << "\tDo you wish to open another file [y/N]? ";
            cin >> again;
        }

        if (toupper(again) == 'N')
        {
            cout << "\n\tNow exiting the program ...";
        }
    } while (toupper(again) == 'Y');
}

/* **********************************************************
   Definition: openFile

    This function reads in and stores the contents of a text
    file. The contents of the file is stored in a vector of
    strings.
   ********************************************************** */

void openFile()
{
    int     numLines = 0;            /* To hold the number of lines of text */
    string  fileName = " ";           /* To hold the filename */
    string  tmpText = " ";            /* To hold text while it is read-in */
    fstream textFile;                    /* File stream object */

    vector<string> tail;                /* Vector of string objects to hold
                                                the file contents */

    cout << "\nEnter the name of the file you wish to open:\n";
    cin >> fileName;

    if (isGood(textFile, fileName))
    {
        while (getline(textFile, tmpText))
        {
            tail.push_back(tmpText);
            numLines++;       
        }
        textFile.close();

        displayText(tail, numLines);
    }
    else
    {
        cout << "\n\tERROR: Cannot open " << fileName << "\n";
    }
}

/* **********************************************************
   Definition: isGood

    This function accepts a reference to an fstream object as
    argument. The file is opened for input. The function
    returns true upon success, false upon failure.
   ********************************************************** */

bool isGood(fstream &textFile, const string fileName)
{
    textFile.open(fileName, ios::in);

    if (!textFile.fail())
    {
        return true;
    }
    else
    {
        return false;
    }
}

/* **********************************************************
   Definition: displayText

    This function accepts a vector of string objects as its
    argument. If the string object holds more than ten lines
    of text, only the last ten lines are displayed. Else the
    full text, and a message indicating the entire file has
    been displayed, is output to screen.
   ********************************************************** */

void displayText(const vector<string> tail, const int numLines)
{
    size_t index = 0;

    /* This ternary operator determines whether the number of lines
        is greater than 10. If it is, 'index' gets tail.size() - 10,
        or the index position of the 10th from the last line, else it
        gets 0. */
    numLines > 10 ? index = tail.size() -10 : index;

    cout << "\n\n\tFILE TAIL:\n\n";
    for (; index < tail.size(); index++)
    {
        cout << "\t" << tail[index] << "\n";
    }

    if (numLines < 10)
    {
        cout << "\n\tThe entire file has been displayed.\n";
    }
}

Example Output: