return (s);
if (!esc) return (s); default: esc = 0; break;
char	*next_cat __P((char *));void	 quiz __P((void));void	 score __P((u_int, u_int, u_int));void	 show_index __P((void));void	 usage __P((void));intmain(argc, argv)	int argc;	char *argv[];{	register int ch;	char *indexfile;	/* revoke */	setegid(getgid());	setgid(getgid());	indexfile = _PATH_QUIZIDX;	while ((ch = getopt(argc, argv, "i:t")) != -1)		switch(ch) {		case 'i':			indexfile = optarg;			break;		case 't':			tflag = 1;			break;		case '?':		default:			usage();		}	argc -= optind;	argv += optind;	switch(argc) {	case 0:		get_file(indexfile);		show_index();		break;	case 2:		get_file(indexfile);		get_cats(argv[0], argv[1]);		quiz();		break;	default:		usage();	}	exit(0);}voidget_file(file)	char *file;{	register FILE *fp;	register QE *qp;	size_t len;	char *lp;	if ((fp = fopen(file, "r")) == NULL)		err(1, "%s", file);	/*	 * XXX	 * Should really free up space from any earlier read list	 * but there are no reverse pointers to do so with.	 */	qp = &qlist;	qsize = 0;	while ((lp = fgetln(fp, &len)) != NULL) {		lp[--len] = '\0';		if (qp->q_text && qp->q_text[strlen(qp->q_text) - 1] == '\\')			qp->q_text = appdstr(qp->q_text, lp, len);		else {			if ((qp->q_next = malloc(sizeof(QE))) == NULL)				err(1, NULL);			qp = qp->q_next;			if ((qp->q_text = strdup(lp)) == NULL)				err(1, NULL);			qp->q_asked = qp->q_answered = FALSE;			qp->q_next = NULL;			++qsize;		}	}	(void)fclose(fp);}voidshow_index(){	register QE *qp;	register char *p, *s;	FILE *pf;	if ((pf = popen(_PATH_PAGER, "w")) == NULL)		err(1, "%s", _PATH_PAGER);	(void)fprintf(pf, "Subjects:\n\n");	for (qp = qlist.q_next; qp; qp = qp->q_next) {		for (s = next_cat(qp->q_text); s; s = next_cat(s)) {			if (!rxp_compile(s))				errx(1, "%s", rxperr);			if (p = rxp_expand())				(void)fprintf(pf, "%s ", p);		}		(void)fprintf(pf, "\n");	}	(void)fprintf(pf, "\n%s\n%s\n%s\n","For example, \"quiz victim killer\" prints a victim's name and you reply","with the killer, and \"quiz killer victim\" works the other way around.","Type an empty line to get the correct answer.");	(void)pclose(pf);}voidget_cats(cat1, cat2)	char *cat1, *cat2;{	register QE *qp;	int i;	char *s;	downcase(cat1);	downcase(cat2);	for (qp = qlist.q_next; qp; qp = qp->q_next) {		s = next_cat(qp->q_text);		catone = cattwo = i = 0;		while (s) {			if (!rxp_compile(s))				errx(1, "%s", rxperr);			i++;			if (rxp_match(cat1))				catone = i;			if (rxp_match(cat2))				cattwo = i;			s = next_cat(s);		}		if (catone && cattwo && catone != cattwo) {			if (!rxp_compile(qp->q_text))				errx(1, "%s", rxperr);			get_file(rxp_expand());			return;		}	}	errx(1, "invalid categories");}voidquiz(){	register QE *qp;	register int i;	size_t len;	u_int guesses, rights, wrongs;	int next;	char *answer, *s, *t, question[LINE_SZ];	srandom(time(NULL));	guesses = rights = wrongs = 0;	for (;;) {		if (qsize == 0)			break;		next = random() % qsize;		qp = qlist.q_next;		for (i = 0; i < next; i++)			qp = qp->q_next;		while (qp && qp->q_answered)			qp = qp->q_next;		if (!qp) {			qsize = next;			continue;		}		if (tflag && random() % 100 > 20) {			/* repeat questions in tutorial mode */			while (qp && (!qp->q_asked || qp->q_answered))				qp = qp->q_next;			if (!qp)				continue;		}		s = qp->q_text;		for (i = 0; i < catone - 1; i++)			s = next_cat(s);		if (!rxp_compile(s))			errx(1, "%s", rxperr);		t = rxp_expand();		if (!t || *t == '\0') {			qp->q_answered = TRUE;			continue;		}		(void)strcpy(question, t);		s = qp->q_text;		for (i = 0; i < cattwo - 1; i++)			s = next_cat(s);		if (!rxp_compile(s))			errx(1, "%s", rxperr);		t = rxp_expand();		if (!t || *t == '\0') {			qp->q_answered = TRUE;			continue;		}		qp->q_asked = TRUE;		(void)printf("%s?\n", question);		for (;; ++guesses) {			if ((answer = fgetln(stdin, &len)) == NULL) {				score(rights, wrongs, guesses);				exit(0);			}			answer[len - 1] = '\0';			downcase(answer);			if (rxp_match(answer)) {				(void)printf("Right!\n");				++rights;				qp->q_answered = TRUE;				break;			}			if (*answer == '\0') {				(void)printf("%s\n", t);				++wrongs;				if (!tflag)					qp->q_answered = TRUE;				break;			}			(void)printf("What?\n");		}	}	score(rights, wrongs, guesses);}char *next_cat(s)	register char *	s;{	for (;;)		switch (*s++) {		case '\0':			return (NULL);		case '\\':			break;		case ':':			return (s);		}	/* NOTREACHED */}