Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/games/cgram cgram: rewrite completely, fixing bugs and style



details:   https://anonhg.NetBSD.org/src/rev/de8c7796bca2
branches:  trunk
changeset: 952951:de8c7796bca2
user:      rillig <rillig%NetBSD.org@localhost>
date:      Sun Feb 21 20:33:42 2021 +0000

description:
cgram: rewrite completely, fixing bugs and style

Fixed bugs:

Do not consider the puzzle solved if all letters in the visible area are
substituted correctly.  To be properly solved, the whole puzzle must be
solved, even those parts that are currently off-screen.

Never place the cursor at the very right edge of the screen since that
does not work well with some terminals.  The maximum valid x coordinate
is COLS - 1.

Add horizontal scrolling.  Make all coordinate handling symmetric in
regard to the horizontal and vertical axes.  Previously, lines longer
than 80 characters could not be seen on the screen.

Improvements:

Remove the arbitrary limit of 128 characters per line.  Even if
fortune(6) may never generate such long lines, the code is easy enough
to adapt to other sources.

Properly clean up the allocated memory.  Previously, only the string
arrays were freed but not the strings themselves.

Stylistic:

Add RCS ID.

Fix ctype functions in lint's strict bool mode.

Avoid excessive calls to strlen whenever the cursor moves.  Given that
the whole screen is redrawn every time a key is pressed, this is an
unnecessary optimization, but the code smelled nevertheless.

diffstat:

 games/cgram/cgram.c |  477 +++++++++++++++++++++++++++++++--------------------
 1 files changed, 292 insertions(+), 185 deletions(-)

diffs (truncated from 628 to 300 lines):

diff -r 66c36234fe2d -r de8c7796bca2 games/cgram/cgram.c
--- a/games/cgram/cgram.c       Sun Feb 21 20:11:59 2021 +0000
+++ b/games/cgram/cgram.c       Sun Feb 21 20:33:42 2021 +0000
@@ -1,11 +1,11 @@
-/* $NetBSD: cgram.c,v 1.9 2021/02/21 17:16:00 rillig Exp $ */
+/* $NetBSD: cgram.c,v 1.10 2021/02/21 20:33:42 rillig Exp $ */
 
 /*-
- * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * Copyright (c) 2013, 2021 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
- * by David A. Holland.
+ * by David A. Holland and Roland Illig.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,6 +29,11 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
+#if defined(__RCSID) && !defined(lint)
+__RCSID("$NetBSD: cgram.c,v 1.10 2021/02/21 20:33:42 rillig Exp $");
+#endif
+
 #include <assert.h>
 #include <ctype.h>
 #include <curses.h>
@@ -43,19 +48,6 @@
 
 ////////////////////////////////////////////////////////////
 
-static char *
-xstrdup(const char *s)
-{
-       char *ret;
-
-       ret = malloc(strlen(s) + 1);
-       if (ret == NULL) {
-               errx(1, "Out of memory");
-       }
-       strcpy(ret, s);
-       return ret;
-}
-
 static char
 ch_toupper(char ch)
 {
@@ -71,29 +63,74 @@
 static bool
 ch_isalpha(char ch)
 {
-       return isalpha((unsigned char)ch);
+       return isalpha((unsigned char)ch) != 0;
 }
 
 static bool
 ch_islower(char ch)
 {
-       return islower((unsigned char)ch);
+       return islower((unsigned char)ch) != 0;
 }
 
 static bool
 ch_isupper(char ch)
 {
-       return isupper((unsigned char)ch);
+       return isupper((unsigned char)ch) != 0;
+}
+
+static int
+imax(int a, int b)
+{
+       return a > b ? a : b;
+}
+
+static int
+imin(int a, int b)
+{
+       return a < b ? a : b;
 }
 
 ////////////////////////////////////////////////////////////
 
+struct string {
+       char *s;
+       size_t len;
+       size_t cap;
+};
+
 struct stringarray {
-       char **v;
+       struct string *v;
        size_t num;
 };
 
 static void
+string_init(struct string *s)
+{
+       s->s = NULL;
+       s->len = 0;
+       s->cap = 0;
+}
+
+static void
+string_add(struct string *s, char ch)
+{
+       if (s->len >= s->cap) {
+               s->cap = 2 * s->cap + 16;
+               s->s = realloc(s->s, s->cap);
+               if (s->s == NULL)
+                       errx(1, "Out of memory");
+       }
+       s->s[s->len++] = ch;
+}
+
+static void
+string_finish(struct string *s)
+{
+       string_add(s, '\0');
+       s->len--;
+}
+
+static void
 stringarray_init(struct stringarray *a)
 {
        a->v = NULL;
@@ -103,18 +140,33 @@
 static void
 stringarray_cleanup(struct stringarray *a)
 {
+       for (size_t i = 0; i < a->num; i++)
+               free(a->v[i].s);
        free(a->v);
 }
 
 static void
-stringarray_add(struct stringarray *a, const char *s)
+stringarray_add(struct stringarray *a, struct string *s)
 {
-       a->v = realloc(a->v, (a->num + 1) * sizeof(a->v[0]));
-       if (a->v == NULL) {
+       size_t num = a->num++;
+       a->v = realloc(a->v, a->num * sizeof a->v[0]);
+       if (a->v == NULL)
                errx(1, "Out of memory");
+       a->v[num] = *s;
+}
+
+static void
+stringarray_dup(struct stringarray *dst, const struct stringarray *src)
+{
+       assert(dst->num == 0);
+       for (size_t i = 0; i < src->num; i++) {
+               struct string str;
+               string_init(&str);
+               for (const char *p = src->v[i].s; *p != '\0'; p++)
+                       string_add(&str, *p);
+               string_finish(&str);
+               stringarray_add(dst, &str);
        }
-       a->v[a->num] = xstrdup(s);
-       a->num++;
 }
 
 ////////////////////////////////////////////////////////////
@@ -122,43 +174,58 @@
 static struct stringarray lines;
 static struct stringarray sollines;
 static bool hinting;
-static int scrolldown;
-static int curx;
-static int cury;
+static int extent_x;
+static int extent_y;
+static int offset_x;
+static int offset_y;
+static int cursor_x;
+static int cursor_y;
+
+static int
+cur_max_x(void)
+{
+       return (int)lines.v[cursor_y].len;
+}
+
+static int
+cur_max_y(void)
+{
+       return extent_y - 1;
+}
 
 static void
 readquote(void)
 {
        FILE *f = popen(_PATH_FORTUNE, "r");
-       if (f == NULL) {
+       if (f == NULL)
                err(1, "%s", _PATH_FORTUNE);
+
+       struct string line;
+       string_init(&line);
+
+       int ch;
+       while ((ch = fgetc(f)) != EOF) {
+               if (ch == '\n') {
+                       string_finish(&line);
+                       stringarray_add(&lines, &line);
+                       string_init(&line);
+               } else if (ch == '\t') {
+                       string_add(&line, ' ');
+                       while (line.len % 8 != 0)
+                               string_add(&line, ' ');
+               } else if (ch == '\b') {
+                       if (line.len > 0)
+                               line.len--;
+               } else {
+                       string_add(&line, (char)ch);
+               }
        }
 
-       char buf[128], buf2[8 * sizeof(buf)];
-       while (fgets(buf, sizeof buf, f) != NULL) {
-               char *s = strrchr(buf, '\n');
-               assert(s != NULL);
-               assert(strlen(s) == 1);
-               *s = '\0';
+       stringarray_dup(&sollines, &lines);
 
-               int i, j;
-               for (i = j = 0; buf[i] != '\0'; i++) {
-                       if (buf[i] == '\t') {
-                               buf2[j++] = ' ';
-                               while (j % 8 != 0)
-                                       buf2[j++] = ' ';
-                       } else if (buf[i] == '\b') {
-                               if (j > 0)
-                                       j--;
-                       } else {
-                               buf2[j++] = buf[i];
-                       }
-               }
-               buf2[j] = '\0';
-
-               stringarray_add(&lines, buf2);
-               stringarray_add(&sollines, buf2);
-       }
+       extent_y = (int)lines.num;
+       for (int i = 0; i < extent_y; i++)
+               extent_x = imax(extent_x, (int)lines.v[i].len);
 
        pclose(f);
 }
@@ -178,8 +245,8 @@
                key[c] = t;
        }
 
-       for (int y = 0; y < (int)lines.num; y++) {
-               for (char *p = lines.v[y]; *p != '\0'; p++) {
+       for (int y = 0; y < extent_y; y++) {
+               for (char *p = lines.v[y].s; *p != '\0'; p++) {
                        if (ch_islower(*p))
                                *p = (char)('a' + key[*p - 'a']);
                        if (ch_isupper(*p))
@@ -191,13 +258,14 @@
 static bool
 substitute(char ch)
 {
-       assert(cury >= 0 && cury < (int)lines.num);
-       if (curx >= (int)strlen(lines.v[cury])) {
+       assert(cursor_x >= 0 && cursor_x < extent_x);
+       assert(cursor_y >= 0 && cursor_y < extent_y);
+       if (cursor_x >= cur_max_x()) {
                beep();
                return false;
        }
 
-       char och = lines.v[cury][curx];
+       char och = lines.v[cursor_y].s[cursor_x];
        if (!ch_isalpha(och)) {
                beep();
                return false;
@@ -209,7 +277,7 @@
        char uch = ch_toupper(ch);
 
        for (int y = 0; y < (int)lines.num; y++) {
-               for (char *p = lines.v[y]; *p != '\0'; p++) {
+               for (char *p = lines.v[y].s; *p != '\0'; p++) {
                        if (*p == loch)
                                *p = lch;
                        else if (*p == uoch)
@@ -225,44 +293,50 @@
 
 ////////////////////////////////////////////////////////////
 
+static bool
+is_solved(void)
+{



Home | Main Index | Thread Index | Old Index