vigenere.c
Here is the reference solution for Problem Set 2, vigenere.c
// Encrypt a message using the Vigenère cypher, with a user-provided key.
// This is CS50x pset2 vigenere.c
//
// Author: david@newtongwc.org
//
// Usage: vigenere <secret>
//
// "secret" must be a non-empty, purely alphabetic string.
//
// Reads the (new-line-terminated) clear-text message from stdin, writes the
// crypt-text message to stdout.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <cs50.h>
#define true 1
#define false 0
string kSecretError = "the Vigenère secret must be a non-empty,"
" alpha-numeric string";
int ArgsAreValid(int argc, string argv[]) {
if (argc != 2) {
printf("Error: You must supply exactly 1 argument to %s\n", argv[0]);
return false;
}
string secret = argv[1];
if (strlen(secret) < 1) {
printf("Error: %s", kSecretError);
}
for (int i = 0; i < strlen(secret); i++) {
if (!isalpha(secret[i])) {
printf("Error: %s", kSecretError);
return false;
}
}
return true;
}
bool ShouldAlter(char clear) {
return isalpha(clear);
}
// Encrypt a single character by shifting it some number of places
// up the alphabet, wrapping around from 'z' to 'a'. Works for both upper- and
// lower-case letters, staying within the same case. Leaves non-alphabetic
// characters unchanged.
char EncryptChar(char clear, int shift) {
char crypt = 0;
if (isupper(clear)) {
crypt = (clear - 'A' + shift) % 26 + 'A';
} else if (islower(clear)) {
crypt = (clear - 'a' + shift) % 26 + 'a';
} else {
crypt = clear;
}
return crypt;
}
// Determines the shift that corresponds to a particular character under
// the Vigenère scheme. Treat both A and a as 0, B and b as 1, … , and Z and
// z as 25.
int ComputeVigenereShift(char c) {
return (tolower(c) - 'a');
}
// Encrypts a full message, one character at a time, using the provided
// encryption secret.
string Encrypt(string clear_text, string secret) {
string crypt_text = malloc(strlen(clear_text) * sizeof(char));
int message_length = strlen(clear_text);
int secret_length = strlen(secret);
int secret_pos = 0;
for (int i = 0; i < message_length; ++i) {
if (ShouldAlter(clear_text[i])) {
int shift = ComputeVigenereShift(secret[secret_pos]);
crypt_text[i] = EncryptChar(clear_text[i], shift);
secret_pos = (secret_pos + 1) % secret_length;
} else {
crypt_text[i] = clear_text[i];
}
}
return crypt_text;
}
int main(int argc, string argv[]) {
if (!ArgsAreValid(argc, argv)) {
return 1;
}
string secret = argv[1];
string clear_text = GetString();
string crypt_text = Encrypt(clear_text, secret);
printf("%s\n", crypt_text);
free(clear_text);
free(crypt_text);
return 0;
}