Check return values explicitely
[oggquiz.git] / oggquiz.c
blob4e465adcde2ea5bd0f8de780e0d088680bc923c4
1 /*-
2 * "THE BEER-WARE LICENSE" (Revision 42):
3 * <tobias.rehbein@web.de> wrote this file. As long as you retain this notice
4 * you can do whatever you want with this stuff. If we meet some day, and you
5 * think this stuff is worth it, you can buy me a beer in return.
6 * Tobias Rehbein
7 */
9 #include <assert.h>
10 #include <err.h>
11 #include <getopt.h>
12 #include <locale.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <time.h>
18 #include "common.h"
19 #include "oggfile.h"
20 #include "oggquiz.h"
21 #include "player.h"
22 #include "ui.h"
24 #define MIN(a, b) ((a) < (b)) ? a : b
26 static const char *OGG123 = "/usr/local/bin/ogg123";
28 enum {
29 CHOICES = 4,
30 TIMEOUT = 60
33 /* Prototypes */
34 static void init_options(struct options *opts);
35 static int new_turn(struct oggfile *oggfiles, struct options *opts);
36 static void parse_options(struct options *opts, int argc, char **argv);
38 int
39 main(int argc, char **argv)
41 char filename[FILENAMELEN];
42 char *newline;
43 int oggfileno;
44 struct oggfile oggfiles[CHOICES];
45 struct options opts;
47 assert(argc >= 0);
48 assert(argv != NULL);
50 if (setlocale(LC_ALL, "") == NULL)
51 warnx("could not set locale");
53 init_options(&opts);
54 parse_options(&opts, argc, argv);
56 * After this point the global options structure is considered read
57 * only!
60 oggfile_setup();
61 ui_setup();
63 oggfileno = 0;
64 while (fgets(filename, FILENAMELEN, stdin) != NULL) {
65 if ((newline = strchr(filename, '\n')) != NULL)
66 newline[0] = '\0';
68 if (oggfile_create(&oggfiles[oggfileno], filename) == 0)
69 oggfileno++;
71 if (oggfileno == opts.choices) {
72 oggfileno = 0;
73 if (new_turn(oggfiles, &opts))
74 break;
78 ui_teardown();
79 oggfile_teardown();
80 player_stop();
82 return (0);
85 static int
86 new_turn(struct oggfile *oggfiles, struct options *opts)
88 static int first_invocation = 0;
89 static struct ui_model model;
90 int correct;
91 char guess;
92 time_t start;
94 assert(oggfiles != NULL);
95 assert(opts != NULL);
97 if (!first_invocation) {
98 first_invocation = 1;
99 srand(time(NULL));
100 /* abusing the correct variable as a temporary variable */
101 for (correct = 0; correct < opts->players; correct++) {
102 model.scores[correct] = 0;
103 model.turn = 0;
106 model.turn++;
107 model.current_player = ((model.turn - 1) % opts->players);
108 model.oggfiles = oggfiles;
109 correct = rand() % opts->choices;
110 model.correct = &oggfiles[correct];
111 ui_display_quiz(&model, opts);
112 player_play(model.correct, opts);
113 start = time(NULL);
114 do {
115 guess = ui_get_answer();
116 if (guess == 'q')
117 return (1);
118 } while (guess < '1' || guess > '0' + opts->choices);
119 model.guess = &oggfiles[guess - '1'];
120 if (model.guess == model.correct)
121 model.scores[model.current_player] += MIN(opts->time, time(NULL) - start);
122 else
123 model.scores[model.current_player] += opts->time;
124 ui_display_result(&model, opts);
125 ui_pause();
127 return (0);
130 static void
131 init_options(struct options *opts)
133 assert(opts != NULL);
135 opts->time = TIMEOUT;
136 opts->choices = CHOICES;
137 opts->players = PLAYERS;
138 SAFE_STRNCPY(opts->ogg123, OGG123, OPTIONLEN);
141 static void
142 parse_options(struct options *opts, int argc, char **argv)
144 int ch;
146 assert(opts != NULL);
147 assert(argc >= 0);
148 assert(argv != NULL);
150 struct option longopts[] = {
151 {"time", required_argument, NULL, 't'},
152 {"choices", required_argument, NULL, 'c'},
153 {"players", required_argument, NULL, 'p'},
154 {"ogg123", required_argument, NULL, 'o'},
155 {"help", no_argument, NULL, 'h'}
158 while ((ch = getopt_long(argc, argv, "t:c:p:o:e:h", longopts, NULL)) != -1)
159 switch (ch) {
160 case 't':
161 opts->time = (int)strtol(optarg, (char **)NULL, 10);
162 break;
163 case 'c':
164 opts->choices = (int)strtol(optarg, (char **)NULL, 10);
165 if (opts->choices < 1 || opts->choices > CHOICES)
166 errx(1, "choices must not exceed %d", CHOICES);
167 break;
168 case 'p':
169 opts->players = (int)strtol(optarg, (char **)NULL, 10);
170 if (opts->players < 1 || opts->players > PLAYERS)
171 errx(1, "players must not exceed %d", PLAYERS);
172 break;
173 case 'o':
174 if (strlen(optarg) >= OPTIONLEN)
175 errx(1, "length of argument 'o' must not exceed %d bytes", OPTIONLEN);
176 SAFE_STRNCPY(opts->ogg123, optarg, OPTIONLEN);
177 break;
178 default:
179 case 'h':
180 puts("oggquiz [-t | --time seconds] [-c | --choices choices] [-p | --players players]");
181 puts(" [-o | --ogg123 command]");
182 puts("oggquiz {-h | --help}");
183 exit(0);