aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2021-11-02 11:23:53 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2021-11-02 11:23:53 -0400
commitce48be18ff6d36326521cfb28eea203c562f391c (patch)
tree2afb3520980b50921abf9ae1b24e8e733c2b3ffa
parentdc1303d5d1e04ec63b4a5776909cf007fb8fdfe6 (diff)
downloadjdtalkc-ce48be18ff6d36326521cfb28eea203c562f391c.tar.gz
Break down project into smaller chunks
-rw-r--r--CMakeLists.txt2
-rw-r--r--dictionary.c140
-rw-r--r--jdtalk.h54
-rw-r--r--main.c401
-rw-r--r--strings.c143
-rw-r--r--talk.c110
6 files changed, 481 insertions, 369 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c6f5d02..249ea85 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,4 +3,4 @@ project(jdtalkc C)
set(CMAKE_C_STANDARD 99)
-add_executable(jdtalkc main.c)
+add_executable(jdtalkc dictionary.c strings.c talk.c main.c jdtalk.h)
diff --git a/dictionary.c b/dictionary.c
new file mode 100644
index 0000000..7d9523b
--- /dev/null
+++ b/dictionary.c
@@ -0,0 +1,140 @@
+#include "jdtalk.h"
+
+struct Dictionary *dictionary_new() {
+ struct Dictionary *dict;
+ dict = calloc(1, sizeof(*dict));
+ dict->words = calloc(DICT_INITIAL_SIZE, sizeof(**dict->words));
+ dict->nelem_alloc = DICT_INITIAL_SIZE;
+ dict->nelem_inuse = 0;
+ return dict;
+}
+
+void dictionary_append(struct Dictionary **dict, char *s, unsigned type) {
+ if ((*dict)->nelem_inuse + 1 > (*dict)->nelem_alloc) {
+ struct Word **tmp;
+ (*dict)->nelem_alloc += DICT_INITIAL_SIZE;
+ tmp = realloc((*dict)->words, (*dict)->nelem_alloc * sizeof((*dict)->words));
+ if (!tmp) {
+ perror("Unable to extend word list");
+ exit(1);
+ }
+ (*dict)->words = tmp;
+ }
+ (*dict)->words[(*dict)->nelem_inuse] = calloc(1, sizeof(**(*dict)->words));
+ (*dict)->words[(*dict)->nelem_inuse]->word = strdup(s);
+ (*dict)->words[(*dict)->nelem_inuse]->nchar = strlen(s) - 1;
+ *((*dict)->words[(*dict)->nelem_inuse]->word + ((*dict)->words[(*dict)->nelem_inuse]->nchar)) = '\0';
+ (*dict)->words[(*dict)->nelem_inuse]->type = type;
+ (*dict)->nelem_inuse++;
+}
+
+int dictionary_read(FILE *fp, struct Dictionary **dict, unsigned type) {
+ //char buf[DICT_WORD_SIZE_MAX];
+ char *bufp = calloc(DICT_WORD_SIZE_MAX, sizeof(char));
+ //bufp = buf;
+ while ((fgets(bufp, DICT_WORD_SIZE_MAX - 1, fp) != NULL)) {
+ if (errno) {
+ return errno;
+ }
+ if (*bufp == '\0' || *bufp == '\n')
+ continue;
+ dictionary_append(&(*dict), bufp, type);
+ }
+ free(bufp);
+ return 0;
+}
+
+struct Dictionary *dictionary_populate() {
+ FILE *fp;
+ struct Dictionary *dict;
+ const char *files[] = {
+ "nouns.txt",
+ "adjectives.txt",
+ "adverbs.txt",
+ "verbs.txt",
+ NULL,
+ };
+
+ const unsigned files_type[] = {
+ WT_NOUN,
+ WT_ADJECTIVE,
+ WT_ADVERB,
+ WT_VERB,
+ };
+
+ dict = dictionary_new();
+ for (size_t i = 0; files[i] != NULL; i++) {
+ char *datadir;
+ char filename[PATH_MAX];
+ filename[0] = '\0';
+ datadir = getenv("JDTALK_DATA");
+
+ if (!datadir) {
+ fprintf(stderr, "JDTALK_DATA environment variable is not set\n");
+ exit(1);
+ }
+
+ sprintf(filename, "%s/%s", datadir, files[i]);
+ fp = fopen(filename, "r");
+ if (!fp) {
+ fprintf(stderr, "Unable to open dictionary: %s", filename);
+ exit(1);
+ }
+ dictionary_read(fp, &dict, files_type[i]);
+ fclose(fp);
+ }
+ return dict;
+}
+
+int dictionary_contains(struct Dictionary *dict, const char *s, unsigned type) {
+ int result;
+ unsigned icase;
+
+ icase = type & WT_ICASE;
+ type &= 0x7f;
+ result = 0;
+
+ for (size_t i = 0; i < dict->nelem_inuse; i++) {
+ if (*s != *dict->words[i]->word) {
+ // Didn't start with first character in s
+ continue;
+ }
+
+ if (type != WT_ANY && dict->words[i]->type != type) {
+ // Incorrect type of word
+ continue;
+ }
+
+ if (icase) {
+ result = strcasecmp(dict->words[i]->word, s) == 0;
+ } else {
+ result = strcmp(dict->words[i]->word, s) == 0;
+ }
+
+ if (result) {
+ break;
+ }
+ }
+ return result;
+}
+
+char *dictionary_word(struct Dictionary *dict, unsigned type) {
+ struct Word *word;
+ while (1) {
+ size_t index = rand() % dict->nelem_inuse;
+ word = dict->words[index];
+ if (word->type == type || type == WT_ANY) {
+ return word->word;
+ }
+ }
+}
+
+void dictionary_free(struct Dictionary *dict) {
+ for (size_t i = 0; i < dict->nelem_inuse; i++) {
+ free(dict->words[i]->word);
+ free(dict->words[i]);
+ }
+ free(dict->words);
+ free(dict);
+}
+
diff --git a/jdtalk.h b/jdtalk.h
new file mode 100644
index 0000000..ce3554b
--- /dev/null
+++ b/jdtalk.h
@@ -0,0 +1,54 @@
+#ifndef JDTALKC_JDTALK_H
+#define JDTALKC_JDTALK_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+
+#define DICT_INITIAL_SIZE 65535
+#define DICT_WORD_SIZE_MAX 255
+#define INPUT_SIZE_MAX 255
+#define OUTPUT_PART_MAX 255
+#define OUTPUT_SIZE_MAX 1024
+
+#define WT_ICASE 0x80
+#define WT_ANY 0
+#define WT_NOUN 1
+#define WT_ADJECTIVE 2
+#define WT_ADVERB 3
+#define WT_VERB 4
+
+struct Word {
+ char *word;
+ unsigned type;
+ size_t nchar;
+};
+
+struct Dictionary {
+ struct Word **words;
+ size_t nelem_alloc;
+ size_t nelem_inuse;
+};
+
+struct Dictionary *dictionary_new();
+void dictionary_append(struct Dictionary **dict, char *s, unsigned type);
+int dictionary_read(FILE *fp, struct Dictionary **dict, unsigned type);
+struct Dictionary *dictionary_populate();
+int dictionary_contains(struct Dictionary *dict, const char *s, unsigned type);
+char *dictionary_word(struct Dictionary *dict, unsigned type);
+void dictionary_free(struct Dictionary *dict);
+
+char *str_random_case(char *s);
+char *str_hill_case(char *s);
+char *str_leet(char *s);
+
+char *talkf(struct Dictionary *dict, const char *fmt, char **parts);
+char *talk_salad(struct Dictionary *dict, size_t limit, char **parts);
+char *talk_acronym(struct Dictionary *dict, const char *fmt, char *s, char **parts);
+int acronym_safe(const char *acronym, const char *pattern);
+
+#endif //JDTALKC_JDTALK_H
diff --git a/main.c b/main.c
index bea5c56..87952d0 100644
--- a/main.c
+++ b/main.c
@@ -1,396 +1,45 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <errno.h>
-#include <ctype.h>
-#include <limits.h>
-
-#define DICT_INITIAL_SIZE 1024
-#define DICT_WORD_SIZE_MAX 255
-#define INPUT_SIZE_MAX DICT_WORD_SIZE_MAX
-#define OUTPUT_PART_MAX 255
-#define OUTPUT_SIZE_MAX 1024
-
-#define WT_ICASE 0x80
-#define WT_ANY 0
-#define WT_NOUN 1
-#define WT_ADJECTIVE 2
-#define WT_ADVERB 3
-#define WT_VERB 4
-
-
-int seed;
-
-struct Word {
- char *word;
- unsigned type;
- size_t nchar;
-};
-
-struct Dictionary {
- struct Word **words;
- size_t nelem_alloc;
- size_t nelem_inuse;
-};
-
-struct Dictionary *dictionary_new() {
- struct Dictionary *dict;
- dict = calloc(1, sizeof(*dict));
- dict->words = calloc(DICT_INITIAL_SIZE, sizeof(**dict->words));
- dict->nelem_alloc = DICT_INITIAL_SIZE;
- dict->nelem_inuse = 0;
- return dict;
-}
-
-void dictionary_append(struct Dictionary **dict, char *s, unsigned type) {
- if ((*dict)->nelem_inuse + 1 > (*dict)->nelem_alloc) {
- struct Word **tmp;
- (*dict)->nelem_alloc++;
- tmp = realloc((*dict)->words, (*dict)->nelem_alloc * sizeof(**(*dict)->words));
- if (!tmp) {
- perror("Unable to extend word list");
- exit(1);
- }
- (*dict)->words = tmp;
- }
- (*dict)->words[(*dict)->nelem_inuse] = calloc(1, sizeof(*(*dict)->words[0]));
- (*dict)->words[(*dict)->nelem_inuse]->word = strdup(s);
- (*dict)->words[(*dict)->nelem_inuse]->nchar = strlen(s) - 1;
- *((*dict)->words[(*dict)->nelem_inuse]->word + ((*dict)->words[(*dict)->nelem_inuse]->nchar)) = '\0';
- (*dict)->words[(*dict)->nelem_inuse]->type = type;
- (*dict)->nelem_inuse++;
-}
-
-int dictionary_read(FILE *fp, struct Dictionary **dict, unsigned type) {
- char buf[DICT_WORD_SIZE_MAX];
- char *bufp;
- bufp = buf;
- while ((fgets(bufp, sizeof(buf), fp) != NULL)) {
- if (errno) {
- return errno;
- }
- if (*bufp == '\0' || *bufp == '\n')
- continue;
- dictionary_append(&(*dict), bufp, type);
- }
- return 0;
-}
-
-struct Dictionary *dictionary_populate() {
- FILE *fp;
- struct Dictionary *dict;
- const char *files[] = {
- "nouns.txt",
- "adjectives.txt",
- "adverbs.txt",
- "verbs.txt",
- NULL,
- };
-
- const unsigned files_type[] = {
- WT_NOUN,
- WT_ADJECTIVE,
- WT_ADVERB,
- WT_VERB,
- };
-
- dict = dictionary_new();
- for (size_t i = 0; files[i] != NULL; i++) {
- char *datadir;
- char filename[PATH_MAX];
- filename[0] = '\0';
- datadir = getenv("JDTALK_DATA");
-
- if (!datadir) {
- fprintf(stderr, "JDTALK_DATA environment variable is not set\n");
- exit(1);
- }
-
- sprintf(filename, "%s/%s", datadir, files[i]);
- fp = fopen(filename, "r");
- if (!fp) {
- fprintf(stderr, "Unable to open dictionary: %s", filename);
- exit(1);
- }
- dictionary_read(fp, &dict, files_type[i]);
- fclose(fp);
- }
- return dict;
-}
-
-int dictionary_contains(struct Dictionary *dict, const char *s, unsigned type) {
- int result;
- unsigned icase;
-
- icase = type & 0x80;
- type &= 0x7f;
- result = 0;
-
- for (size_t i = 0; i < dict->nelem_inuse; i++) {
- if (*s != *dict->words[i]->word) {
- // Didn't start with first character in s
- continue;
- }
-
- if (type != WT_ANY && dict->words[i]->type != type) {
- // Incorrect type of word
- continue;
- }
-
- if (icase) {
- result = strcasecmp(dict->words[i]->word, s) == 0;
- } else {
- result = strcmp(dict->words[i]->word, s) == 0;
- }
-
- if (result) {
- break;
- }
- }
- return result;
-}
-
-char *dictionary_word(struct Dictionary *dict, unsigned type) {
- struct Word *word;
- while (1) {
- size_t index = rand() % dict->nelem_inuse;
- word = dict->words[index];
- if (word->type == type || type == WT_ANY) {
- return word->word;
- }
- }
-}
-
-void dictionary_free(struct Dictionary *dict) {
- for (size_t i = 0; i < dict->nelem_alloc; i++) {
- free(dict->words[i]);
- }
- free(dict->words);
-}
-
-char *str_random_case(char *s) {
- for (size_t i = 0; i < strlen(s); i++) {
- if ((rand() % 100) >= 50) {
- s[i] = (char)toupper(s[i]);
- }
- }
- return s;
-}
-
-char *str_hill_case(char *s) {
- for (size_t i = 0; i < strlen(s); i++) {
- if (i % 2) {
- s[i] = (char)toupper(s[i]);
- }
- }
- return s;
-}
-
-char *str_leet(char *s) {
- static char buf[OUTPUT_SIZE_MAX];
- memset(buf, '\0', sizeof(buf));
- for (size_t i = 0; i < strlen(s); i++) {
- switch (s[i]) {
- case 'a':
- case 'A':
- strcat(buf, "4");
- break;
- case 'b':
- case 'B':
- strcat(buf, "8");
- break;
- case 'c':
- case 'C':
- strcat(buf, "(");
- break;
- case 'd':
- case 'D':
- strcat(buf, ")");
- break;
- case 'e':
- case 'E':
- strcat(buf, "3");
- break;
- case 'f':
- case 'F':
- strcat(buf, "ƒ");
- break;
- case 'g':
- case 'G':
- strcat(buf, "6");
- break;
- case 'h':
- case 'H':
- strcat(buf, "#");
- break;
- case 'i':
- case 'I':
- strcat(buf, "!");
- break;
- case 'j':
- case 'J':
- strcat(buf, "]");
- break;
- case 'k':
- case 'K':
- strcat(buf, "X");
- break;
- case 'l':
- case 'L':
- strcat(buf, "1");
- break;
- case 'm':
- case 'M':
- strcat(buf, "|\\/|");
- break;
- case 'n':
- case 'N':
- strcat(buf, "|\\|");
- break;
- case 'o':
- case 'O':
- strcat(buf, "0");
- break;
- case 'p':
- case 'P':
- strcat(buf, "|*");
- break;
- case 'q':
- case 'Q':
- strcat(buf, "9");
- break;
- case 'r':
- case 'R':
- strcat(buf, "|2");
- break;
- case 's':
- case 'S':
- strcat(buf, "$");
- break;
- case 't':
- case 'T':
- strcat(buf, "7");
- break;
- case 'u':
- case 'U':
- strcat(buf, "|_|");
- break;
- case 'v':
- case 'V':
- strcat(buf, "\\/");
- break;
- case 'w':
- case 'W':
- strcat(buf, "\\/\\/");
- break;
- case 'x':
- case 'X':
- strcat(buf, "><");
- break;
- case 'y':
- case 'Y':
- strcat(buf, "¥");
- break;
- case 'z':
- case 'Z':
- strcat(buf, "2");
- break;
- default:
- buf[strlen(buf)] = s[i];
- break;
- }
- }
- return buf;
-}
-
-char *talkf(struct Dictionary *dict, const char *fmt, char **parts) {
- static char buf[OUTPUT_SIZE_MAX];
- buf[0] = '\0';
-
- if (!fmt || !strlen(fmt)) {
- return NULL;
- }
-
- for (size_t i = 0; i < strlen(fmt); i++) {
- char *word = NULL;
- switch (fmt[i]) {
- case 'a':
- word = dictionary_word(dict, WT_ADJECTIVE);
- break;
- case 'd':
- word = dictionary_word(dict, WT_ADVERB);
- break;
- case 'n':
- word = dictionary_word(dict, WT_NOUN);
- break;
- case 'v':
- word = dictionary_word(dict, WT_VERB);
- break;
- default:
- break;
- }
- parts[i] = word;
- strncat(buf, word, OUTPUT_SIZE_MAX);
- if (i < strlen(fmt) - 1)
- strcat(buf, " ");
- }
- return buf;
-}
-
-char *talk_salad(struct Dictionary *dict, int limit, char **parts) {
- static char buf[OUTPUT_SIZE_MAX];
- buf[0] = '\0';
- for (size_t i = 0; i < limit; i++) {
- char *word = NULL;
- word = dictionary_word(dict, WT_ANY);
- parts[i] = word;
- strncat(buf, word, OUTPUT_SIZE_MAX);
- if (i < limit - 1) {
- strcat(buf, " ");
- }
- }
- return buf;
-}
-
-char *talk_acronym(struct Dictionary *dict, char *s) {
- for (size_t i = 0; i < strlen(s); i++) {
-
- }
-}
+#include "jdtalk.h"
int main(int argc, char *argv[]) {
- FILE *fp;
struct Dictionary *dict;
char buf[OUTPUT_SIZE_MAX];
char format[INPUT_SIZE_MAX];
char pattern[INPUT_SIZE_MAX];
+ char acronym[INPUT_SIZE_MAX];
char *part[OUTPUT_PART_MAX];
int found;
int do_pattern;
int do_exact;
+ int do_acronym;
int do_random_case;
int do_hill_case;
int do_leet;
int do_salad;
int do_benchmark;
int salad_limit;
- int limit;
+ size_t limit;
float start_time;
float end_time;
float time_elapsed;
- srand(time(NULL));
do_pattern = 0;
do_exact = 0;
+ do_acronym = 0;
do_random_case = 0;
do_hill_case = 0;
do_leet = 0;
do_salad = 0;
do_benchmark = 0;
- limit = 1;
+ limit = 0;
salad_limit = 10;
+
strcpy(format, "andv");
+ pattern[0] = '\0';
+ buf[0] = '\0';
+ acronym[0] = '\0';
+
+ srand(time(NULL));
+ setvbuf(stdout, NULL, _IONBF, 0);
for (size_t i = 0; argv[i] != NULL; i++) {
if (strcmp(argv[i], "-b") == 0) {
@@ -423,6 +72,10 @@ int main(int argc, char *argv[]) {
if (strcmp(argv[i], "-f") == 0) {
strcpy(format, argv[i + 1]);
}
+ if (strcmp(argv[i], "-a") == 0) {
+ do_acronym = 1;
+ strcpy(acronym, argv[i + 1]);
+ }
}
dict = dictionary_populate();
@@ -432,14 +85,22 @@ int main(int argc, char *argv[]) {
exit(1);
}
+ if ((do_pattern && do_acronym) && !acronym_safe(acronym, pattern)) {
+ fprintf(stderr, "Word will never appear in acronym, '%s': %s\n", acronym, pattern);
+ exit(1);
+ }
+
if (do_benchmark)
- start_time = (float)clock()/CLOCKS_PER_SEC;
+ start_time = (float)clock() / CLOCKS_PER_SEC;
- for (size_t i = 0; i < limit; i++) {
+ for (size_t i = 1; ; i++) {
LABEL_TRY_AGAIN:
- memset(part, 0, sizeof(part) / sizeof(*part));
+ memset(part, 0, sizeof(part) / sizeof(*part) * sizeof(char *));
+
if (do_salad) {
strcpy(buf, talk_salad(dict, salad_limit, part));
+ } else if (do_acronym) {
+ strcpy(buf, talk_acronym(dict, format, acronym, part));
} else {
strcpy(buf, talkf(dict, format, part));
}
@@ -472,10 +133,14 @@ int main(int argc, char *argv[]) {
strcpy(buf, str_leet(buf));
}
puts(buf);
+
+ if (limit && i == limit) {
+ break;
+ }
}
if (do_benchmark) {
- end_time = (float)clock()/CLOCKS_PER_SEC;
+ end_time = (float) clock() / CLOCKS_PER_SEC;
time_elapsed = end_time - start_time;
fprintf(stderr, "benchmark: %fs\n", time_elapsed);
}
diff --git a/strings.c b/strings.c
new file mode 100644
index 0000000..a7a6dda
--- /dev/null
+++ b/strings.c
@@ -0,0 +1,143 @@
+#include "jdtalk.h"
+
+char *str_random_case(char *s) {
+ size_t len;
+ len = strlen(s);
+ for (size_t i = 0; i < len; i++) {
+ if ((rand() % 100) >= 50) {
+ s[i] = (char)toupper(s[i]);
+ }
+ }
+ return s;
+}
+
+char *str_hill_case(char *s) {
+ size_t len;
+ len = strlen(s);
+ for (size_t i = 0; i < len; i++) {
+ if (i % 2) {
+ s[i] = (char)toupper(s[i]);
+ }
+ }
+ return s;
+}
+
+char *str_leet(char *s) {
+ size_t len;
+ static char buf[OUTPUT_SIZE_MAX];
+ memset(buf, '\0', sizeof(buf));
+ len = strlen(s);
+ for (size_t i = 0; i < len; i++) {
+ switch (s[i]) {
+ case 'a':
+ case 'A':
+ strcat(buf, "4");
+ break;
+ case 'b':
+ case 'B':
+ strcat(buf, "8");
+ break;
+ case 'c':
+ case 'C':
+ strcat(buf, "(");
+ break;
+ case 'd':
+ case 'D':
+ strcat(buf, ")");
+ break;
+ case 'e':
+ case 'E':
+ strcat(buf, "3");
+ break;
+ case 'f':
+ case 'F':
+ strcat(buf, "ƒ");
+ break;
+ case 'g':
+ case 'G':
+ strcat(buf, "6");
+ break;
+ case 'h':
+ case 'H':
+ strcat(buf, "#");
+ break;
+ case 'i':
+ case 'I':
+ strcat(buf, "!");
+ break;
+ case 'j':
+ case 'J':
+ strcat(buf, "]");
+ break;
+ case 'k':
+ case 'K':
+ strcat(buf, "X");
+ break;
+ case 'l':
+ case 'L':
+ strcat(buf, "1");
+ break;
+ case 'm':
+ case 'M':
+ strcat(buf, "|\\/|");
+ break;
+ case 'n':
+ case 'N':
+ strcat(buf, "|\\|");
+ break;
+ case 'o':
+ case 'O':
+ strcat(buf, "0");
+ break;
+ case 'p':
+ case 'P':
+ strcat(buf, "|*");
+ break;
+ case 'q':
+ case 'Q':
+ strcat(buf, "9");
+ break;
+ case 'r':
+ case 'R':
+ strcat(buf, "|2");
+ break;
+ case 's':
+ case 'S':
+ strcat(buf, "$");
+ break;
+ case 't':
+ case 'T':
+ strcat(buf, "7");
+ break;
+ case 'u':
+ case 'U':
+ strcat(buf, "|_|");
+ break;
+ case 'v':
+ case 'V':
+ strcat(buf, "\\/");
+ break;
+ case 'w':
+ case 'W':
+ strcat(buf, "\\/\\/");
+ break;
+ case 'x':
+ case 'X':
+ strcat(buf, "><");
+ break;
+ case 'y':
+ case 'Y':
+ strcat(buf, "¥");
+ break;
+ case 'z':
+ case 'Z':
+ strcat(buf, "2");
+ break;
+ default:
+ buf[strlen(buf)] = s[i];
+ break;
+ }
+ }
+ return buf;
+}
+
diff --git a/talk.c b/talk.c
new file mode 100644
index 0000000..c4dfff8
--- /dev/null
+++ b/talk.c
@@ -0,0 +1,110 @@
+#include "jdtalk.h"
+
+char *talkf(struct Dictionary *dict, const char *fmt, char **parts) {
+ static char buf[OUTPUT_SIZE_MAX];
+ buf[0] = '\0';
+
+ if (!fmt || !strlen(fmt)) {
+ return NULL;
+ }
+
+ size_t len;
+ len = strlen(fmt);
+ for (size_t i = 0; i < len; i++) {
+ char *word = NULL;
+ switch (fmt[i]) {
+ case 'a':
+ word = dictionary_word(dict, WT_ADJECTIVE);
+ break;
+ case 'd':
+ word = dictionary_word(dict, WT_ADVERB);
+ break;
+ case 'n':
+ word = dictionary_word(dict, WT_NOUN);
+ break;
+ case 'v':
+ word = dictionary_word(dict, WT_VERB);
+ break;
+ default:
+ break;
+ }
+
+ if (parts)
+ parts[i] = word;
+
+ strncat(buf, word, OUTPUT_SIZE_MAX);
+
+ if (i < len - 1)
+ strcat(buf, " ");
+ }
+ return buf;
+}
+
+char *talk_salad(struct Dictionary *dict, size_t limit, char **parts) {
+ static char buf[OUTPUT_SIZE_MAX];
+ buf[0] = '\0';
+ for (size_t i = 0; i < limit; i++) {
+ char *word = NULL;
+ word = dictionary_word(dict, WT_ANY);
+ parts[i] = word;
+ strncat(buf, word, OUTPUT_SIZE_MAX);
+ if (i < limit - 1) {
+ strcat(buf, " ");
+ }
+ }
+ return buf;
+}
+
+char *talk_acronym(struct Dictionary *dict, const char *fmt, char *s, char **parts) {
+ size_t len;
+ static char buf[OUTPUT_SIZE_MAX];
+ buf[0] = '\0';
+
+ len = strlen(s);
+ for (size_t i = 0; i < strlen(s); i++) {
+ char *word = NULL;
+ while(1) {
+ word = dictionary_word(dict, WT_ANY);
+ if (*word == s[i]) {
+ break;
+ }
+ /* TODO: Formatted acronyms are too slow. Need a better way.
+ if (strlen(fmt) < strlen(s)) {
+ return NULL;
+ }
+
+ char letter[2] = {'\0', '\0'};
+ for (size_t f = 0; f < strlen(fmt); f++) {
+ *letter = fmt[f];
+ word = talkf(dict, letter, NULL);
+ if (*word == s[i]) {
+ done = 1;
+ break;
+ }
+ }
+ */
+ }
+ parts[i] = word;
+ strncat(buf, word, OUTPUT_SIZE_MAX);
+ if (i < len - 1) {
+ strcat(buf, " ");
+ }
+ }
+ return buf;
+}
+
+int acronym_safe(const char *acronym, const char *pattern) {
+ size_t acronym_len;
+ int pattern_valid;
+ pattern_valid = 0;
+ acronym_len = strlen(acronym);
+ for (size_t i = 0; i < acronym_len; i++) {
+ if (*pattern == acronym[i]) {
+ pattern_valid = 1;
+ break;
+ }
+ }
+
+ return pattern_valid;
+}
+