revlines.cpp
 
/*************************************************************************
 * Quickly written utility to reverse the order of lines in a text file  *
 *                                                                       *
 * When compiling this program with Microsoft C++ specify the -GX switch *
 *************************************************************************/
static char RCSID[] =
    "$Id: revlines.cpp,v 1.1 2010/03/02 03:04:26 david Exp david $";

// TO DO: write a cpp version of parseopt to parse command line options
//        convert string constants to string objects
//        replace getine with <<, if possible

#include <iostream>
#include <fstream>
#include <string>
#include <stack>
using namespace std;

// if BREAK_OR_CONTINUE is defined, terminate loop when file open fails
#ifdef BREAK_OR_CONTINUE
#  undef BREAK_OR_CONTINUE
#  define BREAK_OR_CONTINUE break;      // stop loop on error
#else
#  define BREAK_OR_CONTINUE continue    // skip file on error
#endif

#define EQS(str1,str2) (strcmp((str1),(str2))==0)

static int ManyFiles = false;

static int reverse(char *fileName);     // reverse order of lines in one file

static int cppfilter(                   // generic routine to transform files
    int argc, char *argv[],             // files are specified on command line
    int (*process)(char *file),         // function to process each file
    bool filtbin=false          // open input files in binary mode (Windows) ?
);

static void showHelp(char *pgm);

static char *HelpText[] = {
"Reverse order of lines in a file",
"",
"Options:",
"  --version display version information and terminate",
"  -h        display this message (and version information)",
"  --help",
NULL
};

int main(int argc, char *argv[])
{
    if (argc > 1) {
        if (EQS(argv[1], "-h") || EQS(argv[1], "--help")) {
            showHelp(argv[0]);
            return 0;  // indicates success
        }
        else if (EQS(argv[1], "--version")) {
            cout << RCSID << endl;
            return 0;  // indicates success
        }
    }

    return cppfilter(argc, argv, reverse);
}

static int reverse(char *fileName)
{
    stack<string> lineStack;
    string line;

    if (fileName == NULL)
        fileName = "stdin";

    if(ManyFiles)
        cout << "======>" << fileName << endl;

    // Push lines from the file onto a stack
    for (getline(cin, line); !cin.eof(); getline(cin, line))
        lineStack.push(line);

    // final line may not end with end-of line character
    if (line.length() > 0)
        lineStack.push(line);

    // Pop lines (now in reverse order) and display them
    for (; !lineStack.empty(); lineStack.pop())
        cout << lineStack.top() << endl;

    return 0;   // indicates success
}

/****************************************************************************
 * Loop through files specified on the command line.                        *
 * Call a user-supplied function to process (i.e. filter) each file.        *
 * Before calling the function standard input (stdin) is reset              *
 * to point to the specified file.                                          *
 * Filename "-" represents the original standard input (stdin).             *
 *                                                                          *
 * The user-supplied function is expected to return zero on success,        *
 * non-zero otherwise.                                                      *
 * If a non-zero value is returned this routine terminates and returns that *
 * non-zero value to its caller.                                            *
 *                                                                          *
 * This routine returns zero if all files are successfully filtered.        *
 *                                                                          *
 * If no files were specified on the command line                           *
 * the original stdin is filtered.                                          *
 ****************************************************************************/

static int
cppfilter(
    int argc, char *argv[],     // files are specified on command line
    int (*process)(char *file), // function to process each file
    bool filtbin        // open input files in binary mode (Windows) ?

)
{
    filebuf cin_filebuf;
    streambuf* original_cin;
    char *fileName;     // pointer to filename argument
    int retVal = 0;     // return value, default is success
    int argCtr;
#ifdef _WIN32
    int iosFlags = ios_base::in;
#else
    _Ios_Openmode iosFlags = ios_base::in;
#endif

    ManyFiles = ((argc) > 2);

    if (filtbin)                // open files in binary mode (Windows)
        iosFlags |= ios_base::binary;

    // arguments are filenames to filter, "-" means original standard input
    if (argc == 1)                      // true if no files specified
        retVal = (*process)(NULL);     // use original stdin
    else for (argCtr = 1; argCtr < argc; ++argCtr) {    // cmd line args
        fileName = argv[argCtr];
        if (EQS(fileName,"-")) {       // use original stdin ?
            original_cin = NULL;
            fileName = NULL;
        } else { // redirect cin:
            if (! cin_filebuf.open(fileName, iosFlags)) {
                cerr << "Unable to open file "
                    << fileName << endl;
                BREAK_OR_CONTINUE;
            }
            original_cin = cin.rdbuf(&cin_filebuf);
            if (original_cin == NULL) {
                cerr << "Error redirecting input" << endl;
                BREAK_OR_CONTINUE;
            }
        }

        // process this file
        retVal = (*process)(fileName);

        if (original_cin != NULL) {    // reset cin stream if necessary
            cin_filebuf.close();
            cin.rdbuf(original_cin);
        }

        if (retVal != 0)
            break;     // failure processing file

    }   // end of else clause

    return retVal;
}

static void showHelp(char *pgm)
{
    char **cp;

    cout << "Usage: " << pgm;
    cout << " [-h] [--help] [--version] [files ...]" << endl;

    for (cp = HelpText; *cp != NULL; ++cp)
        cout << *cp << endl;

    cout << endl << RCSID << endl;
}
/************************************************************************
 *                   Copyright 2010 by David M. Elins                   *
 *                                                                      *
 * This program is free software: you can redistribute it and/or modify *
 * it under the terms of the GNU General Public License as published by *
 * the  Free  Software  Foundation, either version 3 of the License, or *
 * (at your option) any later version.                                  *
 *                                                                      *
 * This program is distributed in the hope that it will be useful,  but *
 * WITHOUT   ANY   WARRANTY;  without  even  the  implied  warranty  of *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR  PURPOSE.  See  the  GNU *
 * General Public License for more details.                             *
 *                                                                      *
 * A  copy  of  the  GNU  General  Public  License  (GPL)  be  found at *
 * <http://www.gnu.org/licenses/gpl-3.0-standalone.html>.               *
 *                                                                      *
 * One  is  supposed  to be included here but doing so would bloat this *
 * source code too much.                                                *
 ************************************************************************/
// vim:tabstop=8:shiftwidth=4:noexpandtab
Comments, flames, broken links?
Please send email to maintainer@intricate-simplicity.com