aboutsummaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
authorOskari Timperi <oskari.timperi@iki.fi>2015-09-17 01:04:49 +0300
committerOskari Timperi <oskari.timperi@iki.fi>2015-09-17 01:04:49 +0300
commit396a8ad5b3291776d455a10ebb4951904dbe01bd (patch)
treeee80bddfa4589b7f362b4b1a4c6f0ab3336d4e29 /main.c
downloaddiceware-396a8ad5b3291776d455a10ebb4951904dbe01bd.tar.gz
diceware-396a8ad5b3291776d455a10ebb4951904dbe01bd.zip
initial commit
Diffstat (limited to 'main.c')
-rw-r--r--main.c254
1 files changed, 254 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..e0f7a99
--- /dev/null
+++ b/main.c
@@ -0,0 +1,254 @@
+#include "randgen.h"
+#include "htable.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+/*
+ Generates a random id of length `size-1` consisting of characters in the set
+ [1-6] and places it in the buffer pointed to by `id`. The buffer is NULL
+ terminated.
+*/
+int get_random_id(struct randgen *randgen, char *id, size_t size)
+{
+ size_t n = 0;
+ unsigned char buf[512];
+ size_t i;
+
+ assert(randgen != NULL);
+ assert(id != NULL);
+ assert(size > 0);
+
+ while (n < size-1)
+ {
+ if (randgen_generate(randgen, buf, sizeof(buf)) == -1)
+ return -1;
+
+ for (i = 0; i < sizeof(buf) && n < size-1; ++i)
+ {
+ if (buf[i] >= '1' && buf[i] <= '6')
+ {
+ id[n++] = buf[i];
+ }
+ }
+ }
+
+ id[size-1] = '\0';
+
+ return 0;
+}
+
+/*
+ Makes a copy of the supplied string. If `len` is < 0, strlen() is used to
+ calculate the string length. The resulting string is always NULL terminated.
+*/
+char *my_strdup(const char *s, int len)
+{
+ char *result;
+ assert(s != NULL);
+ if (len < 0)
+ len = strlen(s);
+ result = (char *) malloc(sizeof(char) * (len+1));
+ memcpy(result, s, len);
+ result[len] = '\0';
+ return result;
+}
+
+/*
+ Parse a line from a diceware dictionary file. An acceptable line is of the
+ form:
+
+ 11111 aaabbbccc
+
+ where 11111 is the word id in decimal digits and aaabbbccc is a word
+ stopping at first whitespace.
+
+ Returns a pointer to a htable_entry on success, NULL otherwise. Calls
+ exit() if memory could not be allocated.
+*/
+struct htable_entry *parse_line(const char *line)
+{
+ struct htable_entry *entry;
+ char id[32];
+ char word[256];
+
+ assert(line != NULL);
+
+ if (sscanf(line, "%31[1-6] %255s", id, word) != 2)
+ {
+ return NULL;
+ }
+
+ entry = (struct htable_entry *) malloc(sizeof(*entry));
+ if (!entry)
+ {
+ fprintf(stderr, "%s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ entry->id = my_strdup(id, -1);
+ entry->word = my_strdup(word, -1);
+
+ return entry;
+}
+
+/*
+ Loads a diceware dictionary file. Returns 0 on success and -1 on error.
+*/
+int load_dictionary(const char *filename, struct htable *dict)
+{
+ FILE *fp;
+ int rc = -1;
+ struct htable_entry *entry;
+ char line[256];
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ {
+ fprintf(stderr, "could not open %s: %s\n", filename, strerror(errno));
+ goto cleanup;
+ }
+
+ while (1)
+ {
+ if (!fgets(line, sizeof(line), fp))
+ break;
+
+ if ((entry = parse_line(line)) == NULL)
+ continue;
+
+ htable_put(dict, entry);
+ }
+
+ rc = 0;
+
+cleanup:
+
+ if (fp)
+ fclose(fp);
+
+ return rc;
+}
+
+/*
+ Returns a random word from a dictionary.
+*/
+char *get_random_word(struct randgen *randgen, struct htable *dict)
+{
+ struct htable_entry *entry;
+ char id[6];
+
+ assert(randgen != NULL);
+ assert(dict != NULL);
+
+ if (get_random_id(randgen, id, sizeof(id)) == -1)
+ {
+ fprintf(stderr, "%s\n", "get_random_id failed");
+ return NULL;
+ }
+
+ entry = htable_get(dict, id);
+
+ if (!entry)
+ {
+ fprintf(stderr, "no such word: %s\n", id);
+ return NULL;
+ }
+
+ return entry->word;
+}
+
+void usage(const char *prog)
+{
+ static const char *usagestr =
+ "%s [-d DICTIONARY] [-n COUNT]"
+#ifndef _WIN32
+ " [-r DEVICE]"
+#endif
+ "\n\n"
+ "\t-d use DICTIONARY as the dictionary file\n"
+ "\t-n output COUNT words\n"
+#ifndef _WIN32
+ "\t-r read random bytes from DEVICE\n"
+#endif
+ "\n";
+
+ fprintf(stderr, usagestr, prog);
+
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+ const char *dictfilename = "diceware.txt";
+ const char *randomdevice = NULL;
+
+ int words = 6;
+ int i = 0;
+ struct htable dict;
+ struct randgen *randgen = NULL;
+ int rc = 0;
+
+ memset(&dict, 0, sizeof(dict));
+
+ for (i = 1; i < argc; ++i)
+ {
+ if (!strcmp(argv[i], "-d") && i+1 < argc)
+ {
+ dictfilename = argv[++i];
+ }
+ else if (!strcmp(argv[i], "-n") && i+1 < argc)
+ {
+ words = atoi(argv[++i]);
+ }
+#ifndef _WIN32
+ else if (!strcmp(argv[i], "-r") && i+1 < argc)
+ {
+ randomdevice = argv[++i];
+ }
+#endif
+ else if (!strcmp(argv[i], "-h"))
+ {
+ usage(argv[0]);
+ }
+ else
+ {
+ usage(argv[0]);
+ }
+ }
+
+ if ((randgen = randgen_open(randomdevice)) == NULL)
+ goto error;
+
+ htable_init(&dict, 11000);
+
+ if (load_dictionary(dictfilename, &dict) == -1)
+ goto error;
+
+ for (i = 0; i < words; ++i)
+ {
+ char *word = get_random_word(randgen, &dict);
+ if (!word)
+ {
+ goto error;
+ }
+ printf("%s%s", i ? " " : "", word);
+ }
+
+ printf("\n");
+
+ goto finally;
+
+error:
+
+ rc = 1;
+
+finally:
+
+ randgen_close(randgen);
+
+ htable_deinit(&dict);
+
+ return rc;
+}