Subject: bin/6659: [PATCH] Rain: curses conversion patch
To: None <gnats-bugs@gnats.netbsd.org>
From: Joseph Myers <jsm28@cam.ac.uk>
List: netbsd-bugs
Date: 12/27/1998 22:16:59
>Number:         6659
>Category:       bin
>Synopsis:       [PATCH] Rain: curses conversion patch
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Dec 27 15:20:01 1998
>Last-Modified:
>Originator:     Joseph S. Myers
>Organization:
Trinity College, University of Cambridge, UK
>Release:        NetBSD-current of 1998-12-07
>Environment:
[
System: Linux decomino 2.0.36 #1 Mon Nov 16 14:25:34 UTC 1998 i686 unknown
Architecture: i686
]
>Description:

The appended patch converts rain(6) to use curses, thereby
significantly simplifying the code and improving its portability.  It
also adds a delay option from OpenBSD to make the display go at a
useful speed on fast terminals, and fixes signal handling to make it
reliable.

This is about the 47th NetBSD PR in the process of merging the changes
from the Linux port of the NetBSD games back into NetBSD, with about
12000 lines of diffs remaining to be merged (which quantity increases
as more changes, bug-fixes and improvements are made to the Linux
port).

>How-To-Repeat:

>Fix:

diff -ruN rain/Makefile rain+/Makefile
--- rain/Makefile	Wed Feb  4 12:18:44 1998
+++ rain+/Makefile	Sun Dec 27 21:57:27 1998
@@ -3,7 +3,7 @@
 
 PROG=	rain
 MAN=	rain.6
-DPADD=	${LIBTERMCAP}
-LDADD=	-ltermcap
+DPADD=	${LIBCURSES}
+LDADD=	-lcurses
 
 .include <bsd.prog.mk>
diff -ruN rain/rain.6 rain+/rain.6
--- rain/rain.6	Sun Oct 12 11:26:14 1997
+++ rain+/rain.6	Wed Dec 23 13:56:19 1998
@@ -41,21 +41,17 @@
 .Nd animated raindrops display
 .Sh SYNOPSIS
 .Nm
+.Op Fl d Ar delay
 .Sh DESCRIPTION
 The output of
 .Nm
 is modeled after the 
 .Tn VAX/VMS 
 program of the same name.
-The terminal has to be set for 9600 baud to obtain the proper effect.
-.Pp
-As with all programs that use
-.Tn termcap ,
-the 
-.Ev TERM
-environment variable must be set (and exported) to the type of the
-terminal being used.
-.Sh FILES
-.Pa /usr/share/misc/termcap
+To obtain the proper effect, either the terminal must be set for 9600
+baud or the
+.Fl d
+option must be used to specify a delay, in milliseconds, between each
+update.  A reasonable delay is 120; the default is 0.
 .Sh AUTHOR
 Eric P. Scott
diff -ruN rain/rain.c rain+/rain.c
--- rain/rain.c	Tue Oct 14 11:09:37 1997
+++ rain+/rain.c	Sun Dec 27 21:57:40 1998
@@ -53,185 +53,100 @@
  */
 
 #include <sys/types.h>
-#include <sys/ioctl.h>
+#include <curses.h>
 #include <err.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
-#include <termcap.h>
-#include <termios.h>
+#include <unistd.h>
 
-#define	cursor(c, r)	tputs(tgoto(CM, c, r), 1, fputchar)
+volatile sig_atomic_t sig_caught = 0;
 
-static struct termios sg, old_tty;
-
-void	fputchar __P((int));
 int	main __P((int, char **));
 void	onsig __P((int));
 
 
-char	*LL, *TE;
-
 int
 main(argc, argv)
 	int argc;
 	char **argv;
 {
-	extern char *UP;
 	int x, y, j;
-	char *CM, *BC, *DN, *ND, *term;
-	char *TI, *tcp, *mp, tcb[100];
 	long cols, lines;
+	unsigned int delay = 0;
+	int ch;
 	int xpos[5], ypos[5];
-#ifdef TIOCGWINSZ
-	struct winsize ws;
-#endif
-
-	if (!(term = getenv("TERM")))
-		errx(1, "TERM: parameter not set");
-	if (!(mp = malloc((u_int)1024)))
-		errx(1, "out of space");
-	if (tgetent(mp, term) <= 0)
-		errx(1, "unknown terminal type `%s'", term);
-	tcp = tcb;
-	if (!(CM = tgetstr("cm", &tcp)))
-		errx(1, "terminal not capable of cursor motion");
-	if (!(BC = tgetstr("bc", &tcp)))
-		BC = "\b";
-	if (!(DN = tgetstr("dn", &tcp)))
-		DN = "\n";
-	if (!(ND = tgetstr("nd", &tcp)))
-		ND = " ";
-#ifdef TIOCGWINSZ
-	if (ioctl(fileno(stdout), TIOCGWINSZ, &ws) != -1 &&
-	    ws.ws_col && ws.ws_row) {
-		cols = ws.ws_col;
-		lines = ws.ws_row;
-	} else
-#endif
-	{
-		if ((cols = tgetnum("co")) == -1)
-			cols = 80;
-		if ((lines = tgetnum("li")) == -1)
-			lines = 24;
-	}
-	cols -= 4;
-	lines -= 4;
-	TE = tgetstr("te", &tcp);
-	TI = tgetstr("ti", &tcp);
-	UP = tgetstr("up", &tcp);
-	if (!(LL = tgetstr("ll", &tcp))) {
-		if (!(LL = malloc((u_int)10))) {
-			fprintf(stderr, "%s: out of space.\n", *argv);
+
+	while ((ch = getopt(argc, argv, "d:h")) != -1)
+		switch (ch) {
+		case 'd':
+			if ((delay = (unsigned int)strtoul(optarg, (char **)NULL, 10)) < 1
+			    || delay > 1000)
+				errx(1, "invalid delay (1-1000)");
+			delay *= 1000;  /* ms -> us */
+			break;
+		case 'h':
+		default:
+			(void)fprintf(stderr, "usage: rain [-d delay]\n");
 			exit(1);
 		}
-		(void)strcpy(LL, tgoto(CM, 0, 23));
-	}
+
+	initscr();
+	cols = COLS - 4;
+	lines = LINES - 4;
+
 	(void)signal(SIGHUP, onsig);
 	(void)signal(SIGINT, onsig);
 	(void)signal(SIGQUIT, onsig);
 	(void)signal(SIGSTOP, onsig);
 	(void)signal(SIGTSTP, onsig);
 	(void)signal(SIGTERM, onsig);
-	tcgetattr(1, &sg);
-	old_tty = sg;
-	sg.c_iflag &= ~ICRNL;
-	sg.c_oflag &= ~ONLCR;
-	sg.c_lflag &= ~ECHO;
-	tcsetattr(1, TCSADRAIN, &sg);
-	if (TI)
-		tputs(TI, 1, fputchar);
-	tputs(tgetstr("cl", &tcp), 1, fputchar);
-	(void)fflush(stdout);
+
 	for (j = 4; j >= 0; --j) {
 		xpos[j] = random() % cols + 2;
 		ypos[j] = random() % lines + 2;
 	}
 	for (j = 0;;) {
+		if (sig_caught) {
+			endwin();
+			exit(0);
+		}
 		x = random() % cols + 2;
 		y = random() % lines + 2;
-		cursor(x, y);
-		fputchar('.');
-		cursor(xpos[j], ypos[j]);
-		fputchar('o');
+		mvaddch(y, x, '.');
+		mvaddch(ypos[j], xpos[j], 'o');
 		if (!j--)
 			j = 4;
-		cursor(xpos[j], ypos[j]);
-		fputchar('O');
+		mvaddch(ypos[j], xpos[j], 'O');
 		if (!j--)
 			j = 4;
-		cursor(xpos[j], ypos[j] - 1);
-		fputchar('-');
-		tputs(DN, 1, fputchar);
-		tputs(BC, 1, fputchar);
-		tputs(BC, 1, fputchar);
-		fputs("|.|", stdout);
-		tputs(DN, 1, fputchar);
-		tputs(BC, 1, fputchar);
-		tputs(BC, 1, fputchar);
-		fputchar('-');
+		mvaddch(ypos[j] - 1, xpos[j], '-');
+		mvaddstr(ypos[j], xpos[j] - 1, "|.|");
+		mvaddch(ypos[j] + 1, xpos[j], '-');
 		if (!j--)
 			j = 4;
-		cursor(xpos[j], ypos[j] - 2);
-		fputchar('-');
-		tputs(DN, 1, fputchar);
-		tputs(BC, 1, fputchar);
-		tputs(BC, 1, fputchar);
-		fputs("/ \\", stdout);
-		cursor(xpos[j] - 2, ypos[j]);
-		fputs("| O |", stdout);
-		cursor(xpos[j] - 1, ypos[j] + 1);
-		fputs("\\ /", stdout);
-		tputs(DN, 1, fputchar);
-		tputs(BC, 1, fputchar);
-		tputs(BC, 1, fputchar);
-		fputchar('-');
+		mvaddch(ypos[j] - 2, xpos[j], '-');
+		mvaddstr(ypos[j] - 1, xpos[j] - 1, "/ \\");
+		mvaddstr(ypos[j], xpos[j] - 2, "| O |");
+		mvaddstr(ypos[j] + 1, xpos[j] - 1, "\\ /");
+		mvaddch(ypos[j] + 2, xpos[j], '-');
 		if (!j--)
 			j = 4;
-		cursor(xpos[j], ypos[j] - 2);
-		fputchar(' ');
-		tputs(DN, 1, fputchar);
-		tputs(BC, 1, fputchar);
-		tputs(BC, 1, fputchar);
-		fputchar(' ');
-		tputs(ND, 1, fputchar);
-		fputchar(' ');
-		cursor(xpos[j] - 2, ypos[j]);
-		fputchar(' ');
-		tputs(ND, 1, fputchar);
-		fputchar(' ');
-		tputs(ND, 1, fputchar);
-		fputchar(' ');
-		cursor(xpos[j] - 1, ypos[j] + 1);
-		fputchar(' ');
-		tputs(ND, 1, fputchar);
-		fputchar(' ');
-		tputs(DN, 1, fputchar);
-		tputs(BC, 1, fputchar);
-		tputs(BC, 1, fputchar);
-		fputchar(' ');
+		mvaddch(ypos[j] - 2, xpos[j], ' ');
+		mvaddstr(ypos[j] - 1, xpos[j] - 1, "   ");
+		mvaddstr(ypos[j], xpos[j] - 2, "     ");
+		mvaddstr(ypos[j] + 1, xpos[j] - 1, "   ");
+		mvaddch(ypos[j] + 2, xpos[j], ' ');
 		xpos[j] = x;
 		ypos[j] = y;
-		(void)fflush(stdout);
+		refresh();
+		if (delay) usleep(delay);
 	}
 }
 
 void
 onsig(dummy)
-	int dummy;
-{
-	tputs(LL, 1, fputchar);
-	if (TE)
-		tputs(TE, 1, fputchar);
-	(void)fflush(stdout);
-	tcsetattr(1, TCSADRAIN, &old_tty);
-	exit(0);
-}
-
-void
-fputchar(c)
-	int c;
+	int dummy __attribute__((__unused__));
 {
-	(void)putchar(c);
+	sig_caught = 1;
 }
>Audit-Trail:
>Unformatted: