From 0199f6555377ad9d2bc9fc40f3c3df2c081d2f57 Mon Sep 17 00:00:00 2001 From: Colin P. Mccabe Date: Thu, 20 Dec 2018 13:48:09 -0800 Subject: [PATCH] Some improvements to random_word * Change name from random-word to random_word. * Make the path to the dictionary configurable. * Add random_word to the Makefile. --- .gitignore | 1 + Makefile | 4 +- random-word.c | 115 -------------------------------------------- random_word.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 116 deletions(-) delete mode 100644 random-word.c create mode 100644 random_word.c diff --git a/.gitignore b/.gitignore index 74827ca..da93917 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ hexconv msgpack-translate directory_merge pickrand +random_word audiobooker # diff --git a/Makefile b/Makefile index a5aeef5..db04831 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CFLAGS=-Wall -O2 -all: audiobooker bytor errno_speak show_default_sockopts simple_time vimstart hexconv +all: audiobooker bytor errno_speak show_default_sockopts random_word simple_time vimstart hexconv audiobooker: go build audiobooker.go @@ -18,5 +18,7 @@ vimstart: vimstart.o hexconv: hexconv.o +random_word: random_word.o + clean: rm -rf bytor errno_speak show_default_sockopts simple_time vimstart hexconv *.o diff --git a/random-word.c b/random-word.c deleted file mode 100644 index d751d06..0000000 --- a/random-word.c +++ /dev/null @@ -1,115 +0,0 @@ -#include -#include -#include -#include -#include - -#define DICT "/usr/share/dict/linux.words" -#define STARTING_SZ 8192 -#define MAX_ARRAY_SZ 1073741824 - -struct dict { - int num_words; - int array_sz; - char *words[0]; -}; - -static int alloc_dict(struct dict **d, int array_sz) -{ - struct dict *nd; - int num_bytes; - if (array_sz > MAX_ARRAY_SZ) { - fprintf(stderr, "can't allocate a words array bigger " - "than %d\n", MAX_ARRAY_SZ); - return EINVAL; - } - - num_bytes = sizeof(struct dict) + (array_sz * sizeof(char*)); - nd = realloc(*d, num_bytes); - if (!nd) { - fprintf(stderr, "failed to realloc to size %d\n", - num_bytes); - return ENOSPC; - } - *d = nd; - - nd->array_sz = array_sz; - return 0; -} - -static struct dict* read_dict(FILE *fp) -{ - char word[500]; - struct dict *d = - malloc(sizeof(struct dict) + (STARTING_SZ * sizeof(char*))); - if (! d) { - fprintf(stderr, "failed to allocate dict\n"); - return NULL; - } - d->num_words = 0; - d->array_sz = STARTING_SZ; - - while (1) { - if (! fgets(word, sizeof(word), fp)) { - if (ferror(fp)) { - int err = errno; - fprintf(stderr, "%s: error reading line %d: " - "%s (%d)\n", - __func__, d->num_words + 1, - strerror(err), err); - } - else { - return d; - } - } - d->words[d->num_words] = strdup(word); - if (!d->words[d->num_words]) { - fprintf(stderr, "failed to allocate word %d\n", - d->num_words); - free(d); - return NULL; - } - d->num_words++; - if (d->num_words >= d->array_sz) { - if (alloc_dict(&d, d->array_sz * 2)) { - free(d); - return NULL; - } - } - } -} - -static const char* choose_random_word(struct dict *dict) -{ - int choice = random() % dict->num_words; - - return dict->words[choice]; -} - -int main(void) -{ - FILE *fp; - const char *word; - struct dict *dict; - struct timeval tv; - - gettimeofday(&tv, NULL); - srandom(tv.tv_usec * tv.tv_sec); - - fp = fopen(DICT, "r"); - if (! fp) { - int err = errno; - fprintf(stderr, "failed to open %s: %s (%d).\n", - DICT, strerror(err), err); - return 1; - } - dict = read_dict(fp); - if (! dict) - return 1; - fclose(fp); - - word = choose_random_word(dict); - fputs(word, stdout); - - return 0; -} diff --git a/random_word.c b/random_word.c new file mode 100644 index 0000000..f29bc7d --- /dev/null +++ b/random_word.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include +#include +#include + +#define DEFAULT_DICT_PATH "/usr/share/dict/linux.words" +#define STARTING_SZ 8192 +#define MAX_ARRAY_SZ 1073741824 + +struct dict { + int num_words; + int array_sz; + char *words[0]; +}; + +static int alloc_dict(struct dict **d, int array_sz) +{ + struct dict *nd; + int num_bytes; + if (array_sz > MAX_ARRAY_SZ) { + fprintf(stderr, "can't allocate a words array bigger " + "than %d\n", MAX_ARRAY_SZ); + return EINVAL; + } + + num_bytes = sizeof(struct dict) + (array_sz * sizeof(char*)); + nd = realloc(*d, num_bytes); + if (!nd) { + fprintf(stderr, "failed to realloc to size %d\n", + num_bytes); + return ENOSPC; + } + *d = nd; + + nd->array_sz = array_sz; + return 0; +} + +static struct dict* read_dict(FILE *fp) +{ + char word[500]; + struct dict *d = + malloc(sizeof(struct dict) + (STARTING_SZ * sizeof(char*))); + if (! d) { + fprintf(stderr, "failed to allocate dict\n"); + return NULL; + } + d->num_words = 0; + d->array_sz = STARTING_SZ; + + while (1) { + if (! fgets(word, sizeof(word), fp)) { + if (ferror(fp)) { + int err = errno; + fprintf(stderr, "%s: error reading line %d: " + "%s (%d)\n", + __func__, d->num_words + 1, + strerror(err), err); + } + else { + return d; + } + } + d->words[d->num_words] = strdup(word); + if (!d->words[d->num_words]) { + fprintf(stderr, "failed to allocate word %d\n", + d->num_words); + free(d); + return NULL; + } + d->num_words++; + if (d->num_words >= d->array_sz) { + if (alloc_dict(&d, d->array_sz * 2)) { + free(d); + return NULL; + } + } + } +} + +static const char* choose_random_word(struct dict *dict) +{ + int choice = random() % dict->num_words; + + return dict->words[choice]; +} + +static void print_usage(char *program_name) +{ + printf("%s: prints a random word from a linebreak-delimited file.\n", + program_name); + printf("options:\n"); + printf("\t-d: the dictionary file to use. Default: %s.\n", + DEFAULT_DICT_PATH); + printf("\t-h: this help message.\n"); +} + +static void parse_args(char **argv, int argc, char **dict_path) +{ + char c; + *dict_path = DEFAULT_DICT_PATH; + opterr = 0; + while ((c = getopt(argc, argv, "d:h")) != -1) { + switch (c) { + case 'd': + *dict_path = optarg; + break; + case 'h': + print_usage(argv[0]); + exit(0); + break; + default: + fprintf (stderr, "Argument parsing error.\n"); + exit(1); + } + } +} + +int main(int argc, char **argv) +{ + FILE *fp; + char *dict_path; + const char *word; + struct dict *dict; + struct timeval tv; + + parse_args(argv, argc, &dict_path); + gettimeofday(&tv, NULL); + srandom(tv.tv_usec * tv.tv_sec); + + fp = fopen(dict_path, "r"); + if (! fp) { + int err = errno; + fprintf(stderr, "failed to open %s: %s (%d).\n", + dict_path, strerror(err), err); + return 1; + } + dict = read_dict(fp); + if (! dict) + return 1; + fclose(fp); + + word = choose_random_word(dict); + fputs(word, stdout); + + return 0; +} -- 1.6.6.rc1.39.g9a42