diceware-c

Interactive Diceware Generator
git clone git://git.sgregoratto.me/diceware-c
Log | Files | Refs

diceware.c (2114B)


      1 #include "config.h"
      2 #if HAVE_ERR
      3 #include <err.h>
      4 #endif
      5 #include <stdint.h>
      6 #include <stdio.h>
      7 #include <stdlib.h>
      8 
      9 #include "rng.h"
     10 #include "diceware.h"
     11 
     12 /* Enough for ten six-character words and their seperators */
     13 static char buf[70] = {0};
     14 static size_t buflen = 0;
     15 
     16 int
     17 main(int argc, char **argv)
     18 {
     19 	int num;
     20 	const char *errstr;
     21 
     22 	if (argc > 2) {
     23 		warnx("too many arguments: %s", argv[2]);
     24 	} else if (argc == 2) {
     25 		if (argv[1][0] == '-' && argv[1][1] == 'h')
     26 			goto usage;
     27 		num = strtonum(argv[1], 1, 10, &errstr);
     28 		if (errstr != NULL)
     29 			errx(1, "number of words is %s: %s", errstr, argv[1]);
     30 
     31 		generate(num);
     32 	} else {
     33 		interactive();
     34 	}
     35 
     36 	return 0;
     37 usage:
     38 	fprintf(stderr, "usage: %s [num-words]\n", getprogname());
     39 
     40 	return 1;
     41 }
     42 
     43 void
     44 generate(int num_words)
     45 {
     46 	static char roll[6] = {0};
     47 	const char *word;
     48 	uint32_t num, rem;
     49 
     50 	for (int i = 0; i < num_words; i++) {
     51 		num = rng_uniform(NUM_WORDS);
     52 		word = words[num];
     53 
     54 		for (size_t i = 0; i < 5; i++) {
     55 			rem = num % 6;
     56 			roll[4 - i] = rem + '1';
     57 			num /= 6;
     58 		}
     59 
     60 		fprintf(stderr, "%s %s\n", roll, word);
     61 		buflen = strlcat(buf, word, sizeof(buf));
     62 		buf[buflen] = ' ';
     63 	}
     64 	buf[buflen] = '\n';
     65 
     66 	(void)fwrite(buf, 1, buflen + 1, stdout);
     67 }
     68 
     69 void
     70 interactive(void)
     71 {
     72 	static const uint32_t exps[5] = {1296, 216, 36, 6, 1};
     73 	uint32_t num;
     74 	char *line = NULL;
     75 	size_t size = 0;
     76 	ssize_t len;
     77 	size_t i = 0;
     78 
     79 	do {
     80 		fprintf(stderr, "Roll %2zu: ", i + 1);
     81 		len = getline(&line, &size, stdin);
     82 		if (len == -1) {
     83 			if (feof(stdin))
     84 				break;
     85 			else if (ferror(stdin))
     86 				err(1, "getline");
     87 		} else if (len != 6) {
     88 			warnx("roll is not 5 numbers long, skipping");
     89 			continue;
     90 		}
     91 		line[len] = '\0';
     92 
     93 		num = 0;
     94 		for (size_t j = 0; j < 5; j++) {
     95 			if (line[j] < '1' || line[j] > '6') {
     96 				warnx("invalid roll, skipping: %s", line);
     97 				continue;
     98 			}
     99 			num += (line[j] - '1') * exps[j];
    100 		}
    101 
    102 		buflen = strlcat(buf, words[num], sizeof(buf));
    103 		buf[buflen] = ' ';
    104 		i++;
    105 	} while (i < 10);
    106 	fputc('\n', stderr);
    107 	free(line);
    108 
    109 	buf[buflen] = '\n';
    110 	fputs("Your password is: ", stderr);
    111 	(void)fwrite(buf, 1, buflen + 1, stdout);
    112 }