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;
}
Comments