diceware-c

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

diceware.c (2212B)


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