161 lines
5.3 KiB
C
161 lines
5.3 KiB
C
|
|
||
|
#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);
|
||
|
}
|