EvilZone

Programming and Scripting => C - C++ => : Recon January 11, 2014, 12:35:02 AM

: Need Help Processing Command Line Arguments for Program
: Recon January 11, 2014, 12:35:02 AM
Dear all,

I have a bunch of perfectly functional pieces of a program that work great when I call them from main and do exactly what I want, but I can't seem to get the program to determine which to call based on command line arguments. According to this (http://www.cplusplus.com/forum/articles/13355/) the method I'm trying to use ought to work. Am I missing something?

NOTE: Realized I forgot to comment in the code what the arguments should be. If there is just one argument, the program parses it as the path of a text file to reverse or as a flag, and if there are two, the program parses the first as a flag and the second as the path of the text file. The single-argument version with the path only is working fine, but neither "flag" version is working correctly.

:
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>

using namespace std;

string readIn(string filename);
string reverseStringByLine(string input);
string reverseManualInput();
string reverseString(string input);
void displayUsage();
void displayUsagePossibleError();
void reverseTextFile(string filename);
void reverseTextFileByLine(string filename);
void writeOut(string filename, string buffer);

int main(int argc, char* argv[]) {
    switch (argc) {
    case 2:
        if (argv[1] == "-m" || argv[1] == "/m" || argv[1] == "-M" || argv[1] == "/M") {
            reverseManualInput();
            cin.get();
        } else {
            reverseTextFile(argv[1]);
        }
        break;
    case 3:
        if (argv[1] == "-l" || argv[1] == "/l" || argv[1] == "-L" || argv[1] == "/L") {
            reverseTextFileByLine(argv[2]);
        } else displayUsage();
        break;
    default:
        displayUsage();
        break;
    }
}

string readIn(string filename) {
    ifstream in (filename);
    string buffer;
    if (in.is_open()) {
        in.seekg(0, std::ios::end);
        buffer.resize(in.tellg());
        in.seekg(0, std::ios::beg);
        in.read(&buffer[0], buffer.size());
        in.close();
        return buffer;
    } else {
        displayUsagePossibleError();
    }
}

string reverseManualInput() {
    string input;
    string output;
    getline(cin, input);
    output = reverseString(input);
    return output;
}

string reverseStringByLine(string input) {
    string buffer1;
    string buffer2;
    string output;
    int newLineCounter = 0;
    for(int i = 0; i < input.length(); i++) {
        if (input[i] == '\n') {
            buffer1 = input.substr(0, i);
            buffer2 = reverseString(buffer1) + '\n';
            output.append(buffer2);
            input.erase(0, i + 1);
            i = 0;
            newLineCounter++;
        }
    }
    string lastLine = input.substr(0, input.length() - newLineCounter);
    output.append(reverseString(lastLine));
    return output;
}

string reverseString(string input) {
    string output;
    for (int i = input.length() - 1; i >= 0; i--) {
        output.push_back(input.at(i));
    }
    return output;
}

void displayUsage() {
    cout << "\nProper Usage: Reverse-Text.exe [-m] [-l] fullpath.txt\n\n"
        << "Only one of the flags may be used at once, and either /m and /l or -m and -l will work. "
        << "-m allows the program to accept a single line of manual input, while -l tells the program "
        << "to reverse each line of the text file individually, preserving the order of the lines.";
    return;
}

void displayUsagePossibleError() {
    cout << "\nAn error was encountered. Please double-check the proper usage.\n";
    displayUsage();
}

void reverseTextFile(string filename) {
    string buffer1 = readIn(filename);
    string buffer2 = reverseString(buffer1);
    for(int i = 0; i < buffer2.length(); i++) {
        if (buffer2[i] == '\n') {
            buffer2.erase(0, 1);
        }
    }
    writeOut(filename, buffer2);
}

void reverseTextFileByLine(string filename) {
    string buffer1 = readIn(filename);
    string buffer2 = reverseStringByLine(buffer1);
    writeOut(filename, buffer2);
}

void writeOut(string filename, string buffer) {
    ofstream out(filename);
    if (out.is_open()) {
        out << buffer;
        out.close();
    } else {
        displayUsagePossibleError();
    }
}
: Re: Need Help Processing Command Line Arguments for Program
: Matriplex January 11, 2014, 01:21:26 AM
According that article you can embed Python. I would use Python's OptionParser, but that's just me and I am strange and do things terribly inefficiently. Have you tried just printing out argv to make sure you're getting the positioning in the array correct? I know that in Python the first arg is actually the .py file but that is somewhat different from other languages.
: Re: Need Help Processing Command Line Arguments for Program
: vezzy January 11, 2014, 01:46:21 AM
According that article you can embed Python. I would use Python's OptionParser, but that's just me and I am strange and do things terribly inefficiently. Have you tried just printing out argv to make sure you're getting the positioning in the array correct? I know that in Python the first arg is actually the .py file but that is somewhat different from other languages.

You're seriously suggesting he use Python's C API to process fucking command line arguments?

What the fuck?

Anyway, OP, I'd recommend looking into getopt (honestly) or boost::program_options. Your code doesn't seem to compile on GNU/Linux.

You should look into refactoring your event loop though, something like this, perhaps?...

: (C)
int main(int argc, char *argv[]) {
      switch(argc) {
      case "-m":
             reverseManualInput();
             cin.get();
             // so on and so forth...

Having all these redundant command line styles is an antipattern, anyway. You should only stick to one well defined style (usually the typical hyphen), so as to maintain consistency and clarity.

getopt is still the standard for C/++, you can also try more basic if-else if blocks as documented here. (http://www.cplusplus.com/articles/DEN36Up4/)
: Re: Need Help Processing Command Line Arguments for Program
: Matriplex January 11, 2014, 04:39:29 AM
I'm not suggesting it, I am simply stating that I would do it that way, because as I said, I am terribly inefficient and make silly decisions. No need to flip out man, just responding to a post.
: Re: Need Help Processing Command Line Arguments for Program
: bluechill January 11, 2014, 06:25:24 AM
You're seriously suggesting he use Python's C API to process fucking command line arguments?

What the fuck?

Anyway, OP, I'd recommend looking into getopt (honestly) or boost::program_options. Your code doesn't seem to compile on GNU/Linux.

You should look into refactoring your event loop though, something like this, perhaps?...

: (C)
int main(int argc, char *argv[]) {
      switch(argc) {
      case "-m":
             reverseManualInput();
             cin.get();
             // so on and so forth...

Having all these redundant command line styles is an antipattern, anyway. You should only stick to one well defined style (usually the typical hyphen), so as to maintain consistency and clarity.

getopt is still the standard for C/++, you can also try more basic if-else if blocks as documented here. (http://www.cplusplus.com/articles/DEN36Up4/)

*rolls his eyes*

You realize argc is the argument *count* not the arguments?

argc should not be equal to a string period and your code should NOT compile.  Furthermore, switch statements can ONLY use things which can be converted to numbers and a string "-m" cannot be.  This is why you never see double quotes, only single quotes in switch statements because single quotes specify a character which is an integer value.  If you want to use a switch statement you first have to parse out the '-' then you can compare the short hand but if you also want long hand (--example) then you need to use if statements or some combination.  Also if you're using C, don't fucking use python.  If you want to use python, use python but don't use a slow, interpreted, scripting language in something as fast as C.

argv[0] is the program name w/ execution path
argv[1] is the first argument etc.

argc == 1 means no arguments
argc == 2 means one argument, etc.

:
int main(int argc, char** argv)
{
    int i;
    for (i = 0;i < argc;i++)
    {
        if (strncmp(argv[i], "-m", 2) == 0)
            // has -m option
        // etc.
    }
}
: Re: Need Help Processing Command Line Arguments for Program
: Stackprotector January 11, 2014, 12:21:57 PM
What a terrible advices here :P Bluechill's advice is correct use strNcmp not strcmp to check if a string equals another. I can advise you to have a set of boolean values, maybe in a struct called 'options' or commandlinearguments and set the flags when you find the corresponding flags "-c". Be creative but when you write C keep it to C, if you can't handle C and revert to python libs, well go back to Python and get your basics straight:D
: Re: Need Help Processing Command Line Arguments for Program
: vezzy January 11, 2014, 02:42:44 PM
Fuck. I just made a total fool of myself by responding to posts while in an inebriated state last night.

Thank you for being the voice of reason.
: Re: Need Help Processing Command Line Arguments for Program
: Recon January 12, 2014, 03:29:44 AM
What a terrible advices here :P Bluechill's advice is correct use strNcmp not strcmp to check if a string equals another. I can advise you to have a set of boolean values, maybe in a struct called 'options' or commandlinearguments and set the flags when you find the corresponding flags "-c". Be creative but when you write C keep it to C, if you can't handle C and revert to python libs, well go back to Python and get your basics straight:D

Advice taken.

:
int main(int argc, char** argv)
{
    int i;
    for (i = 0;i < argc;i++)
    {
        if (strncmp(argv[i], "-m", 2) == 0)
            // has -m option
        // etc.
    }
}

Thanks mightily. I've recoded to use strncmp and an iterator.