diff options
author | Christian Weisgerber <naddy@cvs.openbsd.org> | 2021-03-11 21:18:26 +0000 |
---|---|---|
committer | Christian Weisgerber <naddy@cvs.openbsd.org> | 2021-03-11 21:18:26 +0000 |
commit | 7dfd18519518be5e9660d39ed05247fc876e45f3 (patch) | |
tree | f3f941180ca739a2d7ae26dc34ed8bb5d49db7bc /games | |
parent | 970c0223fc7fe064cf34b3375db80e8ce71010e7 (diff) |
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@
Diffstat (limited to 'games')
-rw-r--r-- | games/quiz/quiz.c | 64 |
1 files 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) { |