0

How would I go about modifying this code to accept input from the user rather than using a predetermined string? Specifically, I need the program to require exactly two command line arguments. The first will either be the code "-e" or "-d" to indicate encoding or decoding of a message (this determines adding or subtracting you shift values) and the second parameter will be a single word that will be the keyword that you use for the encryption or decryption.

#include <iostream>
#include <cstring>
#include <algorithm>

// Vigenere Cipher Methods:
// Note: assumes that both strings as arguments have length > 0, and that
//       the key only contains letters of the alphabet from [A-Z]

void vigenere_encrypt(std::string& s, std::string key)
{
    std::transform(s.begin(), s.end(), s.begin(), ::toupper);
    std::transform(key.begin(), key.end(), key.begin(), ::toupper);
    unsigned int j = 0;
    for (int i = 0; i < s.length(); i++)
    {
        if (isalpha(s[i]))
        {
            s[i] += key[j] - 'A';
            if (s[i] > 'Z') s[i] += -'Z' + 'A' - 1;
        }
        j = j + 1 == key.length() ? 0 : j + 1;
    }
}

void vigenere_decrypt(std::string& s, std::string key)
{
    std::transform(s.begin(), s.end(), s.begin(), ::toupper);
    std::transform(key.begin(), key.end(), key.begin(), ::toupper);
    unsigned int j = 0;
    for (int i = 0; i < s.length(); i++)
    {
        if (isalpha(s[i]))
        {
            s[i] = s[i] >= key[j] ?
                s[i] - key[j] + 'A' :
                'A' + ('Z' - key[j] + s[i] - 'A') + 1;
        }
        j = j + 1 == key.length() ? 0 : j + 1;
    }
}

int main(void)
{
    std::string s("AceInfinity's Example");
    std::string key("Passkey");
    vigenere_encrypt(s, key);
    std::cout << "Encrypted: " << s << std::endl;
    vigenere_decrypt(s, key);
    std::cout << "Decrypted: " << s << std::endl;
    return 0;
}

Update

Thanks to your input and a few other sources I have re-developed my main code as is shown below. I am having trouble getting the program to decrypt and encrypt strings properly and I am not sure if the error is somewhere in the code itself, or operator error. Does anything look out of the ordinary here and how could I get this code functional to where it can encrypt or decrypt given user input?

#include <iostream>
#include <string>

int usage( const char* exe_name )
{
    std::cerr << "Usage: " << exe_name << " -e <text to encrypt>\n"
              << "       " << exe_name << " -d <text to decrypt>\n" ;
    return 1 ;
}

int main( int argc, char* argv[] )
{
    if (argc < 3 ) return usage( argv[0] ) ;

    const std::string option = argv[1];

    std::string text = argv[2];
    // cat the remaining cmd line args
    for( int i = 3 ; i < argc ; ++i ) { text += ' ' ; text += argv[i] ; }

    const std::string key("Passkey");

    if ( option== "-e" )
        std::cout << "Encrypt: '" << text << "'\n" ;

    else if ( option == "-d" )
        std::cout << "Decrypt: '" << text << "'\n" ;

    else
    {
        std::cout << "Unrecognised command line option '" << option << "'\n";
        return usage( argv[0] ) ;
    }
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
kdg926
  • 13
  • 1
  • 3
  • 4
  • 2
    What exactly have you tried? what happened then? and how was it different from what you expected? – Mats Petersson Nov 18 '14 at 08:34
  • This current code simply contains one fixed string to decode. I need the code to accept input, indicated for either encryption or decryption. The problem is I am brand new to C++ and have very limited knowledge. I am going to implement parsing as suggested below, but am unsure how to send the parsed input to either encryption or decryption status based on a flag (-e for encryption or -d for decryption). Could you offer any advice on how to proceed? – kdg926 Nov 19 '14 at 03:44
  • Your problem with the amended code is that you don't ever call your `vigenere_encrypt()` or `vigenere_decrypt()` functions. You also no longer need `key` as your `text` contains the key. Or maybe you just need to rename the variable `text` as `key`. – Jonathan Leffler Nov 19 '14 at 07:08
  • This is starting to drift in the direction of code review, as you don't seem to have any specific issues at this point. – Rook Nov 19 '14 at 09:00

2 Answers2

1

If you want command line arguments, you'll need to change the prototype of your main function a little bit and use the standard argv array:

int main(int argc, const char** argv)
{
    std::string s("AceInfinity's Example");

    if (argc != 3)
    {
        std::cout << "Usage: -e text\n" << "       -d text\n";
        return 0;
    }

    std::string arg1 = argv[1];
    std::string arg2 = argv[2];

    if (arg1 == "-e")
    {
        vigenere_encrypt(s, arg2);
        std::cout << "Encrypted: " << s << std::endl;
    }
    else if (arg1 == "-d")
    {
        vigenere_decrypt(s, arg2);
        std::cout << "Decrypted: " << s << std::endl;
    }
    else
        std::cout << "Unrecognised command line option " << arg1 << "\n";

    return 0;
}

Minimal effort made for a quick example, code probably works, e&oe, caveat emptor, etc.

Of course, you'd really be best off using a proper command line argument parser, like getopt, and you'll still need some way to supply the plaintext for encryption or ciphertext for decription, but that's left as an exercise for the reader. Reading from stdin by using std::cin is one way of doing so, for example.

Rook
  • 5,734
  • 3
  • 34
  • 43
  • Parsing makes perfect sense here, didnt think of it before because I simply did not know about that function (I am brand new to C++). As far as supplying the text for encryption or decryption, would I send the parsed terms from main to either function depending on the flag? Whats the best way to go about this? This is at the brink of my programming knowledge – kdg926 Nov 19 '14 at 03:41
  • 1
    @kdg926: this is starting to drift off topic. But a short answer of where to look next: you could read text from stdin as I suggested, you could read text from a file by parsing the arguments for `-f` or whatever, and you coudl combine the two easily enough by rewriting your encryption/decryption routines to use streams (see http://stackoverflow.com/questions/23050273/reading-from-text-file-or-stdin to get you started). But should really be trying stuff and opening new questions as you encounter specific difficulties. – Rook Nov 19 '14 at 09:01
0

Use cin to accept input from the user and input it into a string. Parse the string to obtain the -e/-d flags and the keyword. If the input is not what you want, prompt the user to try again.

Ali Haroon
  • 198
  • 1
  • 1
  • 11