Vigenère Cipher code

Good evening everyone, 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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#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;
}
Last edited on
Last edited on
Ok so I am reworking my main function and I am going to implement parsing as suggested, but I 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? Here is my reworked main function so far:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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];

    std::string key("Passkey");

    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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <string>

void vigenere_encrypt(std::string& s, std::string key) ;
void vigenere_decrypt(std::string& s, std::string key) ;

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

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

    const std::string option /*arg1*/ = argv[1];
    std::string text /*arg2*/ = argv[2];

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

    if ( option /*arg1*/ == "-e")
    {
        // vigenere_decrypt(s, arg2);
        vigenere_encrypt( text, key );
        std::cout << "Encrypted: " << text /*s*/ << '\n' ; // std::endl;
    }
    else if ( option /*arg1*/ == "-d")
    {
        // vigenere_decrypt(s, arg2);
        vigenere_decrypt( text, key );
        std::cout << "Decrypted: " << text /*s*/ << '\n' ; // std::endl;
    }


    else
        std::cout << "Unrecognised command line option " << option /*arg1*/ << "\n";

    // return 0; // implicit

}
Wow this looks great! When I run program for some reason it will just print out:

Usage: -e text
-d text

Do I need to create and input command and send the input somewhere?
> Do I need to create and input command and send the input somewhere?

Yes. For instance, from the command prompt:
> ./my_program -e text to be encrypted

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#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] ) ;
        }
}

clang++ -std=c++14 -stdlib=libc++ -O3 -Wall -Wextra -pedantic-errors main.cpp -lsupc++ 
echo ------ && ./a.out
echo ------ && ./a.out -e one two buckle my shoe
echo ------ && ./a.out -d three four open the door
echo ------ && ./a.out -x five six pick up sticks
------
Usage: ./a.out -e <text to encrypt>
       ./a.out -d <text to decrypt>
------
Encrypt: 'one two buckle my shoe'
------
Decrypt: 'three four open the door'
------
Unrecognised command line option '-x'
Usage: ./a.out -e <text to encrypt>
       ./a.out -d <text to decrypt>


If you want to run it from within an IDE, check the documentation for the IDE on how to specify the program's command line arguments.
All I am using is the Cygwin terminal and Notepad++ so it's pretty bare bones here. I've played around with the command line and inputs a bit and all I get as output is the same phrase as input; there is no actual decryption or encryption in action. What is it that I am missing here?
You need to actually call the encrypt/decrypt functions that you have written.

1
2
3
4
5
6
7
8
9
10
11
   if( option == "-e" )
   {
          vigenere_encrypt( text, key );
          // ...
   }

   else if( option == "-d" )
   {
          vigenere_decrypt( text, key );
          // ...
   }



> All I am using is the Cygwin terminal and Notepad++

Good; keep it that way for a while.

Next, learn to use the command line debugger (gdb in your case) and explore make files.

After that, if you fancy it, try out a few IDEs.
Ok so I just had a wrench thrown in my gears, as of 10 minutes ago this code must now follow a class structure. Now I know even less about classes than parsing and other topics discussed here so this greatly concerns me. Is there any way I can salvage this code or will I have to scrap it and start from scratch?? Very frustrating...
> Is there any way I can salvage this code or will I have to scrap it and start from scratch??

You will be able to reuse almost all of this code; only the packaging would be different.

Read up on classes, make a first attempt at the class definition(s) (don't implement anything yet) and post it here. It is a good idea to present the first (several) classes that you write for review and subsequent revision.
I was only able to read on classes a little before I had to leave for work this morning, but below is my modifications so far. What would I need to continue from here. Also, I noticed the code is likely only showing those outputs because I never actually call the encrypt and decrypt functions, does this appear to be accurate. Thanks again for everything.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <iostream>
#include <cstring>
#include <algorithm>

// Keith Gilmore
// Blackboard login: kegilm7654
// Program #8

// 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]

using namespace std;

class vigenere{
	public:
		vigenere(int main); // specify shift amount
		void vigenere_encrypt(string);
		void vigenere_decrypt(string);
	private:
		int usage
};

if ( option == "-e" )
{
	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;
		}
	}
}

else if ( option == "-d" )

	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 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] ) ;
        }
}
Forget about parsing command line arguments for the moment.
Implement the vigenère class; test it (with hard coded strings) and make sure that it works correctly.

(The vigenère class is only concerned about encrypting and decrypting; it has no business worrying about usage, command line arguments etc.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <string>

struct vigenere
{
    // explicit: disable implicit conversion from std::string to vigenere
    // http://en.cppreference.com/w/cpp/language/explicit
    explicit vigenere( std::string key ) ; // initialise with the key phrase
    
    // encrypt plain_text, return cipher_text
    // const: does not modify the vigenere object
    //  http://www.parashift.com/c++-faq-lite/const-member-fns.html
    std::string encrypt( std::string plain_yext ) const ;
    
    // decrypt cipher_text, return plain_text
    std::string decrypt( std::string plain_yext ) const ;

    private: 
        const std::string key_phrase ; // immutable; the same key phrase has to 
                                       // be used for both encrypt and decrypt
};
Topic archived. No new replies allowed.