Task: Vigenère cipher

C: #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include <getopt.h>

#define NUMLETTERS 26
#define BUFSIZE 4096

char *get_input(void);

int main(int argc, char *argv[])
{
    char const usage[] = "Usage: vinigere [-d] key";
    char sign = 1; 
    char const plainmsg[] = "Plain text:  ";
    char const cryptmsg[] = "Cipher text: ";
    bool encrypt = true;
    int opt;

    while ((opt = getopt(argc, argv, "d")) != -1) {
        switch (opt) {
        case 'd': 
            sign = -1;
            encrypt = false;
            break;
        default: 
            fprintf(stderr, "Unrecogized command line argument:'-%i'\n", opt);
            fprintf(stderr, "\n%s\n", usage);
            return 1;
        }
    }

    if (argc - optind != 1) {
        fprintf(stderr, "%s requires one argument and one only\n", argv[0]);
        fprintf(stderr, "\n%s\n", usage);
        return 1;
    }


    
    char const *const restrict key = argv[optind];
    size_t const keylen = strlen(key);
    char shifts[keylen];

    char const *restrict plaintext = NULL; 
    for (size_t i = 0; i < keylen; i++) {
        if (!(isalpha(key[i]))) {
            fprintf(stderr, "Invalid key\n");
            return 2;
        }
        char const charcase = (isupper(key[i])) ? 'A' : 'a';
        
        
        shifts[i] = (key[i] - charcase) * sign;
    }

    do {
        fflush(stdout);
        
        
        printf("%s", (encrypt) ? plainmsg : cryptmsg);
        plaintext = get_input();
        if (plaintext == NULL) {
            fprintf(stderr, "Error getting input\n");
            return 4;
        }
    } while (strcmp(plaintext, "") == 0); 

    size_t const plainlen = strlen(plaintext);

    char* const restrict ciphertext = calloc(plainlen + 1, sizeof *ciphertext);
    if (ciphertext == NULL) {
        fprintf(stderr, "Memory error\n");
        return 5;
    }

    for (size_t i = 0, j = 0; i < plainlen; i++) {
        
        if (!(isalpha(plaintext[i]))) {
            ciphertext[i] = plaintext[i];
            continue;
        }
        
        char const charcase = (isupper(plaintext[i])) ? 'A' : 'a';
        
        ciphertext[i] = ((plaintext[i] + shifts[j] - charcase + NUMLETTERS) % NUMLETTERS) + charcase;
        j = (j+1) % keylen;
    }
    ciphertext[plainlen] = '\0';
    printf("%s%s\n", (encrypt) ? cryptmsg : plainmsg, ciphertext);

    free(ciphertext);
    
    free((char*) plaintext);
    return 0;
}
char *get_input(void) {

    char *const restrict buf = malloc(BUFSIZE * sizeof (char));
    if (buf == NULL) {
        return NULL;
    }

    fgets(buf, BUFSIZE, stdin);

    
    size_t const len = strlen(buf);
    if (buf[len - 1] == '\n') buf[len - 1] = '\0';

    return buf;
}








VB: Option Explicit

Sub test()
Dim Encryp As String
   Encryp = Vigenere("Beware the Jabberwock, my son! The jaws that bite, the claws that catch!", "vigenerecipher", True)
   Debug.Print "Encrypt:= """ & Encryp & """"
   Debug.Print "Decrypt:= """ & Vigenere(Encryp, "vigenerecipher", False) & """"
End Sub

Private Function Vigenere(sWord As String, sKey As String, Enc As Boolean) As String
Dim bw() As Byte, bk() As Byte, i As Long, c As Long
Const sW As String = "ÁÂÃÄÅÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ"
Const sWo As String = "AAAAACEEEEIIIINOOOOOUUUUY"
Const A As Long = 65
Const N As Long = 26

   c = Len(sKey)
   i = Len(sWord)
   sKey = Left(IIf(c < i, StrRept(sKey, (i / c) + 1), sKey), i)
   sKey = StrConv(sKey, vbUpperCase)         
   sWord = StrConv(sWord, vbUpperCase)
   sKey = StrReplace(sKey, sW, sWo)          
   sWord = StrReplace(sWord, sW, sWo)
   sKey = RemoveChars(sKey)                  
   sWord = RemoveChars(sWord)
   bk = CharToAscii(sKey)                     
   bw = CharToAscii(sWord)
   For i = LBound(bw) To UBound(bw)
      Vigenere = Vigenere & Chr((IIf(Enc, ((bw(i) - A) + (bk(i) - A)), ((bw(i) - A) - (bk(i) - A)) + N) Mod N) + A)
   Next i
End Function

Private Function StrRept(s As String, N As Long) As String
Dim j As Long, c As String
   For j = 1 To N
      c = c & s
   Next
   StrRept = c
End Function

Private Function StrReplace(s As String, What As String, By As String) As String
Dim t() As String, u() As String, i As Long
   t = SplitString(What)
   u = SplitString(By)
   StrReplace = s
   For i = LBound(t) To UBound(t)
      StrReplace = Replace(StrReplace, t(i), u(i))
   Next i
End Function

Private Function SplitString(s As String) As String()
   SplitString = Split(StrConv(s, vbUnicode), Chr(0))
End Function

Private Function RemoveChars(str As String) As String
Dim b() As Byte, i As Long
   b = CharToAscii(str)
   For i = LBound(b) To UBound(b)
      If b(i) >= 65 And b(i) <= 90 Then RemoveChars = RemoveChars & Chr(b(i))
   Next i
End Function

Private Function CharToAscii(s As String) As Byte()
   CharToAscii = StrConv(s, vbFromUnicode)
End Function