]> git.cameronkatri.com Git - bsdgames-darwin.git/blobdiff - cgram/cgram.c
cgram: conform to lint's strict bool mode, KNF
[bsdgames-darwin.git] / cgram / cgram.c
index 3d33d85a1daebe4460e997c016b6e5d47032ad18..77c56a545cdc2307a8a22673f4bcc906b0343c82 100644 (file)
@@ -1,4 +1,4 @@
-/* $NetBSD: cgram.c,v 1.12 2021/02/22 16:28:20 rillig Exp $ */
+/* $NetBSD: cgram.c,v 1.19 2021/04/25 20:14:29 rillig Exp $ */
 
 /*-
  * Copyright (c) 2013, 2021 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: cgram.c,v 1.12 2021/02/22 16:28:20 rillig Exp $");
+__RCSID("$NetBSD: cgram.c,v 1.19 2021/04/25 20:14:29 rillig Exp $");
 #endif
 
 #include <assert.h>
@@ -72,6 +72,12 @@ ch_islower(char ch)
        return islower((unsigned char)ch) != 0;
 }
 
+static bool
+ch_isspace(char ch)
+{
+       return isspace((unsigned char)ch) != 0;
+}
+
 static bool
 ch_isupper(char ch)
 {
@@ -193,13 +199,26 @@ cur_max_y(void)
        return extent_y - 1;
 }
 
-static void
-readquote(void)
+static char
+char_left_of_cursor(void)
 {
-       FILE *f = popen(_PATH_FORTUNE, "r");
-       if (f == NULL)
-               err(1, "%s", _PATH_FORTUNE);
+       if (cursor_x > 0)
+               return lines.v[cursor_y].s[cursor_x - 1];
+       assert(cursor_y > 0);
+       return '\n'; /* eol of previous line */
+}
+
+static char
+char_at_cursor(void)
+{
+       if (cursor_x == cur_max_x())
+               return '\n';
+       return lines.v[cursor_y].s[cursor_x];
+}
 
+static void
+getquote(FILE *f)
+{
        struct string line;
        string_init(&line);
 
@@ -226,6 +245,30 @@ readquote(void)
        extent_y = (int)lines.num;
        for (int i = 0; i < extent_y; i++)
                extent_x = imax(extent_x, (int)lines.v[i].len);
+}
+
+static void
+readfile(const char *name)
+{
+       FILE *f = fopen(name, "r");
+       if (f == NULL)
+               err(1, "%s", name);
+
+       getquote(f);
+
+       if (fclose(f) != 0)
+               err(1, "%s", name);
+}
+
+
+static void
+readquote(void)
+{
+       FILE *f = popen(_PATH_FORTUNE, "r");
+       if (f == NULL)
+               err(1, "%s", _PATH_FORTUNE);
+
+       getquote(f);
 
        if (pclose(f) != 0)
                exit(1); /* error message must come from child process */
@@ -256,44 +299,28 @@ encode(void)
        }
 }
 
-static bool
-substitute(char ch)
+static void
+substitute(char a, char b)
 {
-       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[cursor_y].s[cursor_x];
-       if (!ch_isalpha(och)) {
-               beep();
-               return false;
-       }
-
-       char loch = ch_tolower(och);
-       char uoch = ch_toupper(och);
-       char lch = ch_tolower(ch);
-       char uch = ch_toupper(ch);
+       char la = ch_tolower(a);
+       char ua = ch_toupper(a);
+       char lb = ch_tolower(b);
+       char ub = ch_toupper(b);
 
        for (int y = 0; y < (int)lines.num; y++) {
                for (char *p = lines.v[y].s; *p != '\0'; p++) {
-                       if (*p == loch)
-                               *p = lch;
-                       else if (*p == uoch)
-                               *p = uch;
-                       else if (*p == lch)
-                               *p = loch;
-                       else if (*p == uch)
-                               *p = uoch;
+                       if (*p == la)
+                               *p = lb;
+                       else if (*p == ua)
+                               *p = ub;
+                       else if (*p == lb)
+                               *p = la;
+                       else if (*p == ub)
+                               *p = ua;
                }
        }
-       return true;
 }
 
-////////////////////////////////////////////////////////////
-
 static bool
 is_solved(void)
 {
@@ -303,6 +330,8 @@ is_solved(void)
        return true;
 }
 
+////////////////////////////////////////////////////////////
+
 static void
 redraw(void)
 {
@@ -333,30 +362,23 @@ redraw(void)
        }
 
        move(LINES - 1, 0);
-       if (is_solved())
-               addstr("*solved* ");
        addstr("~ to quit, * to cheat, ^pnfb to move");
 
+       if (is_solved()) {
+               if (extent_y + 1 - offset_y < LINES - 2)
+                       move(extent_y + 1 - offset_y, 0);
+               else
+                       addch(' ');
+               attron(A_BOLD | A_STANDOUT);
+               addstr("*solved*");
+               attroff(A_BOLD | A_STANDOUT);
+       }
+
        move(cursor_y - offset_y, cursor_x - offset_x);
 
        refresh();
 }
 
-static void
-opencurses(void)
-{
-       initscr();
-       cbreak();
-       noecho();
-       keypad(stdscr, true);
-}
-
-static void
-closecurses(void)
-{
-       endwin();
-}
-
 ////////////////////////////////////////////////////////////
 
 static void
@@ -383,30 +405,91 @@ scroll_into_view(void)
                offset_y = cursor_y - (LINES - 2);
 }
 
+static bool
+can_go_left(void)
+{
+       return cursor_y > 0 ||
+           (cursor_y == 0 && cursor_x > 0);
+}
+
+static bool
+can_go_right(void)
+{
+       return cursor_y < cur_max_y() ||
+           (cursor_y == cur_max_y() && cursor_x < cur_max_x());
+}
+
 static void
-handle_char_input(int ch)
+go_to_prev_line(void)
 {
-       if (isascii(ch) && ch_isalpha((char)ch)) {
-               if (substitute((char)ch)) {
-                       if (cursor_x < cur_max_x())
-                               cursor_x++;
-                       if (cursor_x == cur_max_x() &&
-                           cursor_y < cur_max_y()) {
-                               cursor_x = 0;
-                               cursor_y++;
-                       }
-               }
-       } else if (cursor_x < cur_max_x() &&
-           ch == lines.v[cursor_y].s[cursor_x]) {
+       cursor_y--;
+       cursor_x = cur_max_x();
+}
+
+static void
+go_to_next_line(void)
+{
+       cursor_x = 0;
+       cursor_y++;
+}
+
+static void
+go_left(void)
+{
+       if (cursor_x > 0)
+               cursor_x--;
+       else if (cursor_y > 0)
+               go_to_prev_line();
+}
+
+static void
+go_right(void)
+{
+       if (cursor_x < cur_max_x())
                cursor_x++;
-               if (cursor_x == cur_max_x() &&
-                   cursor_y < cur_max_y()) {
-                       cursor_x = 0;
-                       cursor_y++;
-               }
-       } else {
+       else if (cursor_y < cur_max_y())
+               go_to_next_line();
+}
+
+static void
+go_to_prev_word(void)
+{
+       while (can_go_left() && ch_isspace(char_left_of_cursor()))
+               go_left();
+
+       while (can_go_left() && !ch_isspace(char_left_of_cursor()))
+               go_left();
+}
+
+static void
+go_to_next_word(void)
+{
+       while (can_go_right() && !ch_isspace(char_at_cursor()))
+               go_right();
+
+       while (can_go_right() && ch_isspace(char_at_cursor()))
+               go_right();
+}
+
+static bool
+can_substitute_here(int ch)
+{
+       return isascii(ch) &&
+           ch_isalpha((char)ch) &&
+           cursor_x < cur_max_x() &&
+           ch_isalpha(char_at_cursor());
+}
+
+static void
+handle_char_input(int ch)
+{
+       if (ch == char_at_cursor())
+               go_right();
+       else if (can_substitute_here(ch)) {
+               substitute(char_at_cursor(), (char)ch);
+               go_right();
+       } else
                beep();
-       }
 }
 
 static bool
@@ -421,12 +504,7 @@ handle_key(void)
                break;
        case 2:                 /* ^B */
        case KEY_LEFT:
-               if (cursor_x > 0) {
-                       cursor_x--;
-               } else if (cursor_y > 0) {
-                       cursor_y--;
-                       cursor_x = cur_max_x();
-               }
+               go_left();
                break;
        case 5:                 /* ^E */
        case KEY_END:
@@ -434,12 +512,16 @@ handle_key(void)
                break;
        case 6:                 /* ^F */
        case KEY_RIGHT:
-               if (cursor_x < cur_max_x()) {
-                       cursor_x++;
-               } else if (cursor_y < cur_max_y()) {
-                       cursor_y++;
-                       cursor_x = 0;
-               }
+               go_right();
+               break;
+       case '\t':
+               go_to_next_word();
+               break;
+       case KEY_BTAB:
+               go_to_prev_word();
+               break;
+       case '\n':
+               go_to_next_line();
                break;
        case 12:                /* ^L */
                clear();
@@ -463,6 +545,8 @@ handle_key(void)
                break;
        case '~':
                return false;
+       case KEY_RESIZE:
+               break;
        default:
                handle_char_input(ch);
                break;
@@ -471,14 +555,22 @@ handle_key(void)
 }
 
 static void
-init(void)
+init(const char *filename)
 {
        stringarray_init(&lines);
        stringarray_init(&sollines);
        srandom((unsigned int)time(NULL));
-       readquote();
+       if (filename != NULL) {
+           readfile(filename);
+       } else {
+           readquote();
+       }
        encode();
-       opencurses();
+
+       initscr();
+       cbreak();
+       noecho();
+       keypad(stdscr, true);
 }
 
 static void
@@ -496,7 +588,8 @@ loop(void)
 static void
 clean_up(void)
 {
-       closecurses();
+       endwin();
+
        stringarray_cleanup(&sollines);
        stringarray_cleanup(&lines);
 }
@@ -504,9 +597,9 @@ clean_up(void)
 ////////////////////////////////////////////////////////////
 
 int
-main(void)
+main(int argc, char *argv[])
 {
-       init();
+       init(argc > 1 ? argv[1] : NULL);
        loop();
        clean_up();
 }