Implement pass-through options for ogg123
[oggquiz.git] / oggquiz.c
blobbdc23d1fb881fa51eec1f0bc2187cfb7d99729dc
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 <locale.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sysexits.h>
17 #include <time.h>
19 #include "options.h"
20 #include "oggfile.h"
21 #include "player.h"
22 #include "ui.h"
24 #define MIN(a, b) ((a) < (b)) ? (a) : (b)
26 enum {
27 FILENAMELEN = 1024
30 static void avoid_zombie_processes(void);
31 static int new_turn(struct ogg_oggfile *oggfiles, struct plr_context *plr_ctx, struct ui_context *ui_ctx, struct opts_options *opts);
33 int
34 main(int argc, char **argv)
36 char filename[FILENAMELEN];
37 char *newline;
38 int oggfileno;
39 struct ogg_oggfile *oggfiles;
40 struct opts_options opts;
41 struct ogg_context *ogg_ctx;
42 struct plr_context *plr_ctx;
43 struct ui_context *ui_ctx;
45 assert(argc >= 0);
46 assert(argv != NULL);
48 if (setlocale(LC_ALL, "") == NULL)
49 warnx("could not set locale");
51 opts_parse_options(&opts, argc, argv);
53 * After this point the opts_options structure is considered read
54 * only!
57 if ((ogg_ctx = ogg_context_open()) == NULL)
58 errx(EX_SOFTWARE, "could not open oggfile context");
59 if ((plr_ctx = plr_context_open(opts.ogg123, opts.ogg123_options)) == NULL)
60 errx(EX_SOFTWARE, "could not open player context");
61 if ((ui_ctx = ui_context_open()) == NULL)
62 errx(EX_SOFTWARE, "could not open ui context");
63 if ((oggfiles = malloc(opts.choices * sizeof(struct ogg_oggfile))) == NULL)
64 err(EX_SOFTWARE, "could not malloc oggfiles");
65 avoid_zombie_processes();
67 oggfileno = 0;
68 while (fgets(filename, FILENAMELEN, stdin) != NULL) {
69 if ((newline = strchr(filename, '\n')) != NULL)
70 newline[0] = '\0';
72 if (ogg_oggfile_create(ogg_ctx, &oggfiles[oggfileno], filename) == 0)
73 oggfileno++;
75 if (oggfileno == opts.choices) {
76 oggfileno = 0;
77 if (new_turn(oggfiles, plr_ctx, ui_ctx, &opts))
78 break;
82 plr_stop(plr_ctx);
83 plr_context_close(plr_ctx);
84 ui_context_close(ui_ctx);
85 if (ogg_context_close(ogg_ctx) != 0)
86 warn("could not close oggfile context");
88 return (0);
91 static int
92 new_turn(struct ogg_oggfile *oggfiles, struct plr_context *plr_ctx, struct ui_context *ui_ctx, struct opts_options *opts)
94 static int first_invocation = 0;
95 static struct ui_model model;
96 int correct;
97 int i;
98 char guess;
99 time_t start;
101 assert(oggfiles != NULL);
102 assert(opts != NULL);
104 if (!first_invocation) {
105 first_invocation = 1;
106 srand(time(NULL));
107 if ((model.scores = malloc(opts->players * sizeof(int))) == NULL)
108 err(EX_SOFTWARE, "could not malloc scores");
109 if ((model.oggfiles = malloc(opts->choices * sizeof(struct ui_oggfile))) == NULL)
110 err(EX_SOFTWARE, "could not malloc oggfiles");
111 for (i = 0; i < opts->players; i++) {
112 model.scores[i] = 0;
114 model.turn = 0;
115 model.players = opts->players;
116 model.choices = opts->choices;
118 model.turn++;
119 model.current_player = ((model.turn - 1) % model.players);
120 for (i = 0; i < model.choices; i++) {
121 model.oggfiles[i].title = oggfiles[i].title;
122 model.oggfiles[i].artist = oggfiles[i].artist;
123 model.oggfiles[i].album = oggfiles[i].album;
125 correct = rand() % model.choices;
126 model.correct = &model.oggfiles[correct];
127 ui_display_quiz(ui_ctx, &model);
128 plr_play(plr_ctx, oggfiles[correct].filename);
129 start = time(NULL);
130 do {
131 guess = ui_get_key();
132 if (guess == 'q')
133 return (1);
134 } while (guess < '1' || guess > '0' + opts->choices);
135 model.guess = &model.oggfiles[guess - '1'];
136 if (model.guess == model.correct)
137 model.score_delta = MIN(opts->time, time(NULL) - start);
138 else
139 model.score_delta = opts->time;
140 model.scores[model.current_player] += model.score_delta;
141 ui_display_result(ui_ctx, &model);
142 if (ui_get_key() == 'q')
143 return (1);
145 return (0);
148 static void
149 avoid_zombie_processes()
151 struct sigaction sa;
153 sa.sa_handler = SIG_IGN;
154 sa.sa_flags = 0;
155 sigemptyset(&(sa.sa_mask));
156 sigaddset(&(sa.sa_mask), SIGPIPE);
158 sigaction(SIGPIPE, &sa, NULL);