1 /* $NetBSD: quiz.c,v 1.25 2009/08/27 00:24:11 dholland Exp $ */
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Jim R. Oldroyd at The Instruction Set and Keith Gabryelski at
9 * Commodore Business Machines.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/cdefs.h>
38 __COPYRIGHT("@(#) Copyright (c) 1991, 1993\
39 The Regents of the University of California. All rights reserved.");
44 static char sccsid
[] = "@(#)quiz.c 8.3 (Berkeley) 5/4/95";
46 __RCSID("$NetBSD: quiz.c,v 1.25 2009/08/27 00:24:11 dholland Exp $");
50 #include <sys/types.h>
61 #include "pathnames.h"
64 static int catone
, cattwo
, tflag
;
65 static unsigned qsize
;
67 static char *appdstr(char *, const char *, size_t);
68 static void downcase(char *);
69 static void get_cats(char *, char *);
70 static void get_file(const char *);
71 static const char *next_cat(const char *);
72 static void quiz(void);
73 static void score(unsigned, unsigned, unsigned);
74 static void show_index(void);
75 static void usage(void) __dead
;
78 main(int argc
, char *argv
[])
81 const char *indexfile
;
83 /* Revoke setgid privileges */
86 indexfile
= _PATH_QUIZIDX
;
87 while ((ch
= getopt(argc
, argv
, "i:t")) != -1)
109 get_cats(argv
[0], argv
[1]);
119 get_file(const char *file
)
126 if ((fp
= fopen(file
, "r")) == NULL
)
131 * Should really free up space from any earlier read list
132 * but there are no reverse pointers to do so with.
136 while ((lp
= fgetln(fp
, &len
)) != NULL
) {
137 if (lp
[len
- 1] == '\n')
139 if (qp
->q_text
&& qp
->q_text
[strlen(qp
->q_text
) - 1] == '\\')
140 qp
->q_text
= appdstr(qp
->q_text
, lp
, len
);
142 if ((qp
->q_next
= malloc(sizeof(QE
))) == NULL
)
145 if ((qp
->q_text
= malloc(len
+ 1)) == NULL
)
147 strncpy(qp
->q_text
, lp
, len
);
148 qp
->q_text
[len
] = '\0';
149 qp
->q_asked
= qp
->q_answered
= FALSE
;
168 if (!(pager
= getenv("PAGER")) || (*pager
== 0))
171 if ((pf
= popen(pager
, "w")) == NULL
)
173 (void)fprintf(pf
, "Subjects:\n\n");
174 for (qp
= qlist
.q_next
; qp
; qp
= qp
->q_next
) {
175 for (s
= next_cat(qp
->q_text
); s
; s
= next_cat(s
)) {
177 errx(1, "%s", rxperr
);
178 if ((p
= rxp_expand()) != NULL
)
179 (void)fprintf(pf
, "%s ", p
);
181 (void)fprintf(pf
, "\n");
183 (void)fprintf(pf
, "\n%s\n%s\n%s\n",
184 "For example, \"quiz victim killer\" prints a victim's name and you reply",
185 "with the killer, and \"quiz killer victim\" works the other way around.",
186 "Type an empty line to get the correct answer.");
191 get_cats(char *cat1
, char *cat2
)
199 for (qp
= qlist
.q_next
; qp
; qp
= qp
->q_next
) {
200 s
= next_cat(qp
->q_text
);
201 catone
= cattwo
= i
= 0;
204 errx(1, "%s", rxperr
);
212 if (catone
&& cattwo
&& catone
!= cattwo
) {
213 if (!rxp_compile(qp
->q_text
))
214 errx(1, "%s", rxperr
);
215 get_file(rxp_expand());
219 errx(1, "invalid categories");
228 unsigned guesses
, rights
, wrongs
;
230 char *answer
, *t
, question
[LINE_SZ
];
234 guesses
= rights
= wrongs
= 0;
238 next
= random() % qsize
;
240 for (i
= 0; i
< next
; i
++)
242 while (qp
&& qp
->q_answered
)
248 if (tflag
&& random() % 100 > 20) {
249 /* repeat questions in tutorial mode */
250 while (qp
&& (!qp
->q_asked
|| qp
->q_answered
))
256 for (i
= 0; i
< catone
- 1; i
++)
259 errx(1, "%s", rxperr
);
261 if (!t
|| *t
== '\0') {
262 qp
->q_answered
= TRUE
;
265 (void)strcpy(question
, t
);
267 for (i
= 0; i
< cattwo
- 1; i
++)
270 errx(1, "%s", rxperr
);
272 if (!t
|| *t
== '\0') {
273 qp
->q_answered
= TRUE
;
277 (void)printf("%s?\n", question
);
279 if ((answer
= fgetln(stdin
, &len
)) == NULL
||
280 answer
[len
- 1] != '\n') {
281 score(rights
, wrongs
, guesses
);
284 answer
[len
- 1] = '\0';
286 if (rxp_match(answer
)) {
287 (void)printf("Right!\n");
289 qp
->q_answered
= TRUE
;
292 if (*answer
== '\0') {
293 (void)printf("%s\n", t
);
296 qp
->q_answered
= TRUE
;
299 (void)printf("What?\n");
302 score(rights
, wrongs
, guesses
);
306 next_cat(const char *s
)
329 appdstr(char *s
, const char *tp
, size_t len
)
336 if ((m
= malloc(strlen(s
) + len
+ 1)) == NULL
)
338 for (mp
= m
, sp
= s
; (*mp
++ = *sp
++) != '\0'; )
341 if (*(mp
- 1) == '\\')
344 while ((ch
= *mp
++ = *tp
++) && ch
!= '\n')
353 score(unsigned r
, unsigned w
, unsigned g
)
355 (void)printf("Rights %d, wrongs %d,", r
, w
);
357 (void)printf(" extra guesses %d,", g
);
358 (void)printf(" score %d%%\n", (r
+ w
+ g
) ? r
* 100 / (r
+ w
+ g
) : 0);
366 for (; (ch
= *p
) != '\0'; ++p
)
367 if (isascii(ch
) && isupper(ch
))
374 (void)fprintf(stderr
, "quiz [-t] [-i file] category1 category2\n");