Use new github account
[oggquiz.git] / oggquiz.c
blobec42529ac4e87866e92ba54a208305d76dfded4d
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 struct ui_model *create_ui_model(struct opts_options *opts);
32 void destroy_ui_model(struct ui_model *model);
33 static int new_turn(struct ogg_oggfile *oggfiles, struct ui_model *model, struct plr_context *plr_ctx, struct ui_context *ui_ctx, struct opts_options *opts);
35 int
36 main(int argc, char **argv)
38 char filename[FILENAMELEN];
39 char *newline;
40 int oggfileno;
41 struct ogg_oggfile *oggfiles;
42 struct opts_options opts;
43 struct ogg_context *ogg_ctx;
44 struct plr_context *plr_ctx;
45 struct ui_context *ui_ctx;
46 struct ui_model *ui_model;
48 assert(argc >= 0);
49 assert(argv != NULL);
51 if (setlocale(LC_ALL, "") == NULL)
52 warnx("could not set locale");
54 opts_parse_options(&opts, argc, argv);
56 * After this point the opts_options structure is considered read
57 * only!
60 if ((oggfiles = malloc(opts.choices * sizeof(struct ogg_oggfile))) == NULL)
61 err(EX_SOFTWARE, "could not malloc oggfiles");
62 if ((ogg_ctx = ogg_context_open()) == NULL)
63 errx(EX_SOFTWARE, "could not open oggfile context");
64 if ((plr_ctx = plr_context_open(opts.ogg123, opts.ogg123_options)) == NULL)
65 errx(EX_SOFTWARE, "could not open player context");
66 if ((ui_ctx = ui_context_open()) == NULL)
67 errx(EX_SOFTWARE, "could not open ui context");
68 if ((ui_model = create_ui_model(&opts))== NULL)
69 err(EX_SOFTWARE, "could not create ui_model");
70 avoid_zombie_processes();
72 srand(time(NULL));
73 oggfileno = 0;
74 while (fgets(filename, FILENAMELEN, stdin) != NULL) {
75 if ((newline = strchr(filename, '\n')) != NULL)
76 *newline = '\0';
78 if (ogg_oggfile_create(ogg_ctx, &oggfiles[oggfileno], filename) == 0)
79 oggfileno++;
81 if (oggfileno == opts.choices) {
82 oggfileno = 0;
83 if (new_turn(oggfiles, ui_model, plr_ctx, ui_ctx, &opts))
84 break;
87 plr_stop(plr_ctx);
89 destroy_ui_model(ui_model);
90 ui_context_close(ui_ctx);
91 plr_context_close(plr_ctx);
92 if (ogg_context_close(ogg_ctx) != 0)
93 warn("could not close oggfile context");
94 free(oggfiles);
96 return (0);
99 static int
100 new_turn(struct ogg_oggfile *oggfiles, struct ui_model *model,
101 struct plr_context *plr_ctx, struct ui_context *ui_ctx,
102 struct opts_options *opts)
104 int correct;
105 int i;
106 char guess;
107 time_t start;
109 assert(oggfiles != NULL);
110 assert(opts != NULL);
112 model->turn++;
113 model->current_player = ((model->turn - 1) % model->players);
114 for (i = 0; i < model->choices; i++) {
115 model->oggfiles[i].title = oggfiles[i].title;
116 model->oggfiles[i].artist = oggfiles[i].artist;
117 model->oggfiles[i].album = oggfiles[i].album;
119 correct = rand() % model->choices;
120 model->correct = &model->oggfiles[correct];
121 ui_display_quiz(ui_ctx, model);
122 plr_play(plr_ctx, oggfiles[correct].filename);
123 start = time(NULL);
124 do {
125 guess = ui_get_key();
126 if (guess == 'q')
127 return (1);
128 } while (guess < '1' || guess > '0' + opts->choices);
129 model->guess = &model->oggfiles[guess - '1'];
130 if (model->guess == model->correct)
131 model->score_delta = MIN(opts->time, time(NULL) - start);
132 else
133 model->score_delta = opts->time;
134 model->scores[model->current_player] += model->score_delta;
135 ui_display_result(ui_ctx, model);
136 if (ui_get_key() == 'q')
137 return (1);
139 return (0);
142 struct ui_model *
143 create_ui_model(struct opts_options *opts)
145 struct ui_model *model;
146 int i;
148 assert(opts != NULL);
150 if ((model = malloc(sizeof(*model))) == NULL)
151 err(EX_SOFTWARE, "could not malloc ui_model");
152 if ((model->scores = malloc(opts->players * sizeof(int))) == NULL)
153 err(EX_SOFTWARE, "could not malloc scores");
154 if ((model->oggfiles = malloc(opts->choices * sizeof(struct ui_oggfile))) == NULL)
155 err(EX_SOFTWARE, "could not malloc oggfiles");
156 for (i = 0; i < opts->players; i++) {
157 model->scores[i] = 0;
159 model->turn = 0;
160 model->players = opts->players;
161 model->choices = opts->choices;
163 return (model);
166 void
167 destroy_ui_model(struct ui_model *model)
169 assert(model != NULL);
171 free(model->scores);
172 free(model->oggfiles);
173 free(model);
176 static void
177 avoid_zombie_processes()
179 struct sigaction sa;
181 sa.sa_handler = SIG_IGN;
182 sa.sa_flags = 0;
183 sigemptyset(&(sa.sa_mask));
184 sigaddset(&(sa.sa_mask), SIGCHLD);
186 sigaction(SIGCHLD, &sa, NULL);