ACaesar/acaesar.c
2023-09-03 20:48:08 -04:00

161 lines
5.3 KiB
C
Executable file

#include "utf8hack.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int get_index_of_utf8_char(utf8_char *utf8_string, size_t string_length, utf8_char search_char);
void transcode(long offset, char *charset_str, char *message_str);
#define HELP_MESSAGE \
"ACaesar - Caesar Cipher transcoder version 0.1\n\
Usage: acaesar [options] message\n\
Options:\n\
--help Print this help message\n\
-o <offset> Set the integer offset used in transcoding\n\
-c <character set> Set the character set\n\
--xyz Set the character set to the lowercase alphabet (default)\n"
int main(int argc, char *argv[]) {
bool charset_set = false;
bool message_set = false;
bool offset_set = false;
bool alloc_charset = false;
long offset;
char *charset;
char *message;
// Argument parsing
for (int i = 1; i < argc; i++) {
char *current_arg = argv[i];
// Help flag
if (strcmp(current_arg, "--help") == 0) {
printf(HELP_MESSAGE);
return 0;
}
// Charset flag
if (strcmp(current_arg, "-c") == 0) {
if (i == argc - 1) {
fprintf(stderr, "Error, charset (-c) flag found without following charset.\n");
return 1;
}
if (charset_set) {
fprintf(stderr, "Error, character set specified twice.\n");
return 1;
}
char *next_arg = argv[i + 1];
size_t size = strlen(next_arg);
charset = malloc(size * sizeof(char) + 1);
strcpy(charset, next_arg);
charset_set = true;
i++;
continue;
}
// Offset flag
if (strcmp(current_arg, "-o") == 0) {
if (i == argc - 1) {
fprintf(stderr, "Error, offset (-o) flag found without following offset.\n");
return 1;
}
if (offset_set) {
fprintf(stderr, "Error, offset (-o) specified twice.\n");
return 1;
}
char *next_arg = argv[i + 1];
offset = strtol(next_arg, NULL, 10);
offset_set = true;
i++;
continue;
}
// alphabetical charset flag. (default anyways). Only exists for completeness.
if (strcmp(current_arg, "--xyz") == 0) {
if (charset_set) {
fprintf(stderr, "Error, character set specified twice.\n");
return 1;
}
charset = "abcdefghijklmnopqrstuvwxyz";
charset_set = true;
alloc_charset = true;
continue;
}
if (i != argc - 1) {
// Unrecognized flag
fprintf(stderr, "Error, unknown argument found: '%s'\n", current_arg);
return 1;
} else {
// Message to be transcoded.
// Last argument is assumed to be message.
size_t size = strlen(current_arg);
message = malloc(size * sizeof(char) + 1);
strcpy(message, current_arg);
message_set = true;
}
}
if (!charset_set) {
// Default to a...z when no charset is found.
charset = "abcdefghijklmnopqrstuvwxyz";
charset_set = true;
}
if (!offset_set) {
fprintf(stderr, "Error, no offset found. Use '-o' to set one.\n");
return 1;
}
if (!message_set) {
fprintf(stderr, "Error, no message found to transcode.\n");
return 1;
}
transcode(offset, charset, message);
// Clean up
free(message);
// In some cases, charset is malloc'd and in others it is set to be a string literal.
// String literals can not bee freed so `alloc_charset` is used to determine when charset should be freed
if (alloc_charset)
free(charset);
return 0;
}
int get_index_of_utf8_char(utf8_char *utf8_string, size_t string_length, utf8_char search_char) {
for (size_t i = 0; i < string_length; i++) {
if (utf8_char_eq(&utf8_string[i], &search_char)) {
return i;
}
}
return -1;
}
// Error handling would be nice for this function.
void transcode(long offset, char *charset_str, char *message_str) {
size_t charset_length;
utf8_char *charset;
parse_to_utf8(charset_str, &charset, &charset_length);
size_t message_length;
utf8_char *message;
parse_to_utf8(message_str, &message, &message_length);
utf8_char *transcoded_message = malloc(message_length * sizeof(utf8_char));
for (size_t i = 0; i < message_length; i++) {
// A hashmap would likely be more efficient for larger messages, but would introduce much complexity.
int a = get_index_of_utf8_char(charset, charset_length, message[i]);
if (a != -1) {
transcoded_message[i] = copy_utf8_char(&charset[(a + offset) % charset_length]);
} else {
// If character is not in character set, copy it over unchanged.
transcoded_message[i] = copy_utf8_char(&message[i]);
}
}
print_utf8_str(transcoded_message, message_length);
printf("\n");
free_utf8_str(charset, charset_length);
free_utf8_str(message, message_length);
free_utf8_str(transcoded_message, message_length);
}