[comp.sources.d] termcap lib and nethack

guy%gorodish@Sun.COM (Guy Harris) (08/05/87)

> What library did you sysV users use for terminal capabilities?  I used
> curses (not my idea) and the output was all garbled.  I would have to redraw
> the screen every once in a while to figure out where I was.

I tried bringing it up on a Sun here in the S5 environment with the
S5R3.1 version of "curses" (and bunches of other stuff not in SunOS
3.x, but that's neither here nor there).  Once I fixed a couple of
bugs in that version of "curses" (including one @##!$%@! null-pointer
bug), I didn't see any such problem when I tried it briefly.

One of those bugs would have prevented it from running at all (a
routine wasn't null-terminating a string, so it would think the
(simulated) "bs" capability was false); the other might conceivably
have broken things on machines that do allow dereferencing of null
pointers, especially if said dereferencing yields a non-null string.

Perhaps bugs in the "termcap" emulation in various versions of the S5
"curses" were causing the problems?

Oh yes, I *did* notice some problems with the code itself:

	1) The Makefile, for some inexplicable reason, links "hack"
	   by using full-frontal "ld" rather than using "cc".  This
	   makes some rather dubious assumptions about the arguments
	   that "cc" passes to "ld", and as such is a rather bad
	   practice.  (Somebody had problems linking "logo" a while
	   ago, and they were doing it with "ld" rather than "cc",
	   which was causing at least some of their problems; if
	   the Makefile for "logo" was using "ld", and the "ld"
	   command it was using was the bogus one the person was
	   having problems with, the Makefile's should be strung up.)

	   It also passes the "-X" flag.  In V7-flavored versions of
	   UNIX (including [24]BSD), this flag tells "ld" to remove
	   some symbols from the symbol table.  In S5R3, at least, it
	   is not a valid flag to "ld".  In either case, the Makefile
	   has no business [fm]ucking with this flag in the general
	   case; if it is needed by some benighted implementation,
	   this should be mentioned in the comments in the Makefile
	   or something and MADE OPTIONAL.

	2) "install" doesn't depend on what it's installing.  It is
	   not required to do so, but it is considered uncool if it
	   doesn't.

	3) In "cmd.c", a "char" is compared against 0377.  If "char"s
	   are signed on your machine, and it properly implements the
	   C conversion rules, this comparison will always indicate
	   that the "char" is unequal to 0377, since the "char" with
	   the value '\377' yields the value -1 when coerced to
	   "int".  Yes, kids, there *will* be compilers that
	   implement those rules properly; the little warning our
	   compiler issues in this case about the conversion being
	   done incorrectly now for bug compatibility, but being done
	   correctly in 4.0, should be taken very seriously indeed.

	4) In "config.h", it claims that "Some include files are in a
	   different place under SYSV".  This is certainly true,
	   except that one of the include files is not in a
	   "different place" under System V, it doesn't exist at all!
	   This include file is <sys/wait.h>.  This include file
	   defines a structure which probably seemed like a good idea
	   to the Berkloids at the time, but which really wasn't; the
	   return value of "wait" is defined by every other UNIX
	   variant as an "int" with certain bits meaning certain
	   things, not as a "struct" containing bitfields.  In fact,
	   the definition as a "struct" is *machine-dependent*,
	   because the order of bitfields in a structure is
	   machine-dependent; our <sys/wait.h> has #ifdefs to fix
	   this.

	   The only place in the entire program where this structure
	   is used is in one "wait" call in "pager.c"; this "wait"
	   call only uses it to cast 0 to an appropriate pointer
	   type.  Since in most versions of UNIX the appropriate
	   pointer type is "(int *)0" - in fact, the *really*
	   appropriate pointer type in *all* versions of UNIX is
	   "(int *)0", except that the Berkloids decided to promote
	   this new structure and put it in the documentation and the
	   "lint" library - it is better not to waste time with
	   <sys/wait.h> and just to use "(int *)0".  This also
	   eliminates the need for the NOWAITINCLUDE #define
	   constant in "config.h".

Here are a bunch of context diffs to fix the aforementioned problems:

Makefile.unix:
*** Makefile.unix.orig	Wed Aug  5 01:19:11 1987
--- Makefile.unix	Wed Aug  5 01:20:21 1987
***************
*** 19,25 ****
  SHELLDIR = /usr/games
  MANDIR  = /usr/man/man6
  CFLAGS = -O
! LFLAGS = -X
  
  HACKCSRC = alloc.c apply.c bones.c cmd.c decl.c do.c do_name.c do_wear.c\
  	dog.c dogmove.c dothrow.c eat.c end.c engrave.c fight.c fountain.c\
--- 19,25 ----
  SHELLDIR = /usr/games
  MANDIR  = /usr/man/man6
  CFLAGS = -O
! LFLAGS =
  
  HACKCSRC = alloc.c apply.c bones.c cmd.c decl.c do.c do_name.c do_wear.c\
  	dog.c dogmove.c dothrow.c eat.c end.c engrave.c fight.c fountain.c\
***************
*** 57,63 ****
  
  $(GAME):	specifics $(HOBJ) Makefile
  	@echo "Loading ..."
! 	@ld $(LFLAGS) -o $(GAME) /lib/crt0.o $(HOBJ) $(TERMLIB) -lc
  
  all:	$(GAME) lint
  	@echo "Done."
--- 57,63 ----
  
  $(GAME):	specifics $(HOBJ) Makefile
  	@echo "Loading ..."
! 	@$(CC) $(LFLAGS) -g -o $(GAME) $(HOBJ) /argonsrc/5lib/libcurses/screen/obj/termcap.o $(TERMLIB)
  
  all:	$(GAME) lint
  	@echo "Done."
***************
*** 131,137 ****
  	chmod 666 $(GAMEDIR)/*
  	chmod 777 $(GAMEDIR) $(GAMEDIR)/save
  
! install: $(VARAUX)
  	-rm -f $(GAMEDIR)/$(GAME)
  	-rm -f $(GAMEDIR)/bones*
  	-rm -f $(GAMEDIR)/save/*
--- 131,137 ----
  	chmod 666 $(GAMEDIR)/*
  	chmod 777 $(GAMEDIR) $(GAMEDIR)/save
  
! install: $(VARAUX) $(GAME)
  	-rm -f $(GAMEDIR)/$(GAME)
  	-rm -f $(GAMEDIR)/bones*
  	-rm -f $(GAMEDIR)/save/*

cmd.c:
*** cmd.c.orig	Tue Aug  4 23:40:10 1987
--- cmd.c	Tue Aug  4 23:55:18 1987
***************
*** 244,252 ****
  	}
  
  	/* Special case of *cmd == ' ' handled better below */
! 	if(!*cmd || *cmd == 0377) {
  #else
! 	if(!*cmd || *cmd == 0377 || (flags.no_rest_on_space && *cmd == ' ')){
  #endif
  		bell();
  		flags.move = 0;
--- 244,252 ----
  	}
  
  	/* Special case of *cmd == ' ' handled better below */
! 	if(!*cmd || *cmd == '\377') {
  #else
! 	if(!*cmd || *cmd == '\377' || (flags.no_rest_on_space && *cmd == ' ')){
  #endif
  		bell();
  		flags.move = 0;


config.h:
*** config.h.orig	Tue Aug  4 23:40:33 1987
--- config.h	Wed Aug  5 01:42:03 1987
***************
*** 11,17 ****
   * Some include files are in a different place under SYSV
   * 	BSD		   SYSV
   * <strings.h>		<string.h>
-  * <sys/wait.h>		<wait.h>
   * <sys/time.h>		<time.h>
   * <sgtty.h>		<termio.h>
   * Some routines are called differently
--- 11,16 ----
***************
*** 32,41 ****
  /* #define APOLLO		/* same for the Apollo */
  /* #define STUPID		/* avoid some complicated expressions if
  			   your C compiler chokes on them */
- /* #define NOWAITINCLUDE	/* neither <wait.h> nor <sys/wait.h> exists */
- #ifdef MSDOS
- #define	NOWAITINCLUDE
- #endif
  
  #define WIZARD  "mike"	/* the person allowed to use the -D option */
  #define RECORD	"record"/* the file containing the list of topscorers */
--- 31,36 ----

pager.c:
*** pager.c.orig	Tue Aug  4 23:40:28 1987
--- pager.c	Wed Aug  5 00:11:29 1987
***************
*** 382,406 ****
  }
  #endif /* SHELL /**/
  
- #ifdef NOWAITINCLUDE
- union wait {		/* used only for the cast  (union wait *) 0  */
- 	int w_status;
- 	struct {
- 		unsigned short w_Termsig:7;
- 		unsigned short w_Coredump:1;
- 		unsigned short w_Retcode:8;
- 	} w_T;
- };
- 
- #else
- 
- #ifdef BSD
- #include	<sys/wait.h>
- #else
- #include	<wait.h>
- #endif
- #endif /* NOWAITINCLUDE /**/
- 
  child(wt) {
  register int f = fork();
  	if(f == 0){		/* child */
--- 382,387 ----
***************
*** 419,425 ****
  	/* fork succeeded; wait for child to exit */
  	(void) signal(SIGINT,SIG_IGN);
  	(void) signal(SIGQUIT,SIG_IGN);
! 	(void) wait((union wait *) 0);
  	gettty();
  	setftty();
  	(void) signal(SIGINT,done1);
--- 400,406 ----
  	/* fork succeeded; wait for child to exit */
  	(void) signal(SIGINT,SIG_IGN);
  	(void) signal(SIGQUIT,SIG_IGN);
! 	(void) wait((int *) 0);
  	gettty();
  	setftty();
  	(void) signal(SIGINT,done1);
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com