From 5a0076c3c81ddf2f5d67607053ad76c062c6dde5 Mon Sep 17 00:00:00 2001 From: naddy Date: Thu, 11 Mar 2021 21:18:25 +0000 Subject: [PATCH] quiz: handle line continuation in data files correctly, switch to getline(3) Specifically, the following quiz.db line foo:\ bar was parsed into "foo:bar\n", which made it impossible to answer correctly. Bug reported and inital fix from Alex Karle, partially reworked by yours truly, further input from millert@ --- games/quiz/quiz.c | 64 ++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/games/quiz/quiz.c b/games/quiz/quiz.c index 073c1700719..d4fd0604e0d 100644 --- a/games/quiz/quiz.c +++ b/games/quiz/quiz.c @@ -1,4 +1,4 @@ -/* $OpenBSD: quiz.c,v 1.30 2018/08/24 11:14:49 mestre Exp $ */ +/* $OpenBSD: quiz.c,v 1.31 2021/03/11 21:18:25 naddy Exp $ */ /* $NetBSD: quiz.c,v 1.9 1995/04/22 10:16:58 cgd Exp $ */ /*- @@ -48,7 +48,6 @@ static QE qlist; static int catone, cattwo, tflag; static u_int qsize; -char *appdstr(char *, const char *, size_t); void downcase(char *); void get_cats(char *, char *); void get_file(const char *); @@ -110,7 +109,8 @@ get_file(const char *file) { FILE *fp; QE *qp; - size_t len; + ssize_t len; + size_t qlen, size; char *lp; if ((fp = fopen(file, "r")) == NULL) @@ -123,26 +123,36 @@ get_file(const char *file) */ qp = &qlist; qsize = 0; - while ((lp = fgetln(fp, &len)) != NULL) { + qlen = 0; + lp = NULL; + size = 0; + while ((len = getline(&lp, &size, fp)) != -1) { if (lp[len - 1] == '\n') - --len; - if (qp->q_text && qp->q_text[0] != '\0' && - qp->q_text[strlen(qp->q_text) - 1] == '\\') - qp->q_text = appdstr(qp->q_text, lp, len); - else { + lp[--len] = '\0'; + if (qp->q_text) + qlen = strlen(qp->q_text); + if (qlen > 0 && qp->q_text[qlen - 1] == '\\') { + qp->q_text[--qlen] = '\0'; + qlen += len; + qp->q_text = realloc(qp->q_text, qlen + 1); + if (qp->q_text == NULL) + errx(1, "realloc"); + strlcat(qp->q_text, lp, qlen + 1); + } else { if ((qp->q_next = malloc(sizeof(QE))) == NULL) errx(1, "malloc"); qp = qp->q_next; - if ((qp->q_text = malloc(len + 1)) == NULL) - errx(1, "malloc"); - /* lp may not be zero-terminated; cannot use strlcpy */ - strncpy(qp->q_text, lp, len); - qp->q_text[len] = '\0'; + qp->q_text = strdup(lp); + if (qp->q_text == NULL) + errx(1, "strdup"); qp->q_asked = qp->q_answered = FALSE; qp->q_next = NULL; ++qsize; } } + free(lp); + if (ferror(fp)) + err(1, "getline"); (void)fclose(fp); } @@ -318,32 +328,6 @@ next_cat(const char *s) } } -char * -appdstr(char *s, const char *tp, size_t len) -{ - char *mp; - const char *sp; - int ch; - char *m; - - if ((m = malloc(strlen(s) + len + 1)) == NULL) - errx(1, "malloc"); - for (mp = m, sp = s; (*mp++ = *sp++) != '\0'; ) - ; - --mp; - if (*(mp - 1) == '\\') - --mp; - - while ((ch = *mp++ = *tp++) && ch != '\n') - ; - if (*(mp - 2) == '\\') - mp--; - *mp = '\0'; - - free(s); - return (m); -} - void score(u_int r, u_int w, u_int g) { -- 2.20.1