blarson@skat.usc.edu (Bob Larson) (02/01/88)
Here are the additional files and changes needed to make nethack 2.2 work on os9/68k, including a couple of minor bug fixes, portability fixes, and some hacks to get it to work. Read "readme.osk". # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # config.h.osk # makefile.osk # readme.osk # osk.c # osktty.c # oskunix.c # By: Jim Omura () cat << \SHAR_EOF > config.h.osk /* SCCS Id: @(#)config.h 2.2 87/11/11 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ #ifndef CONFIG /* make sure the compiler does not see the typedefs twice */ #define CONFIG #define CHDIR /* delete if no chdir() available */ /* * Some include files are in a different place under SYSV * BSD SYSV * <strings.h> <string.h> * <sys/time.h> <time.h> * <sgtty.h> <termio.h> * Some routines are called differently * index strchr * rindex strrchr * Also, the code for suspend and various ioctls is only given for BSD4.2 */ /* #define MSDOS /* define for MS-DOS (actually defined by compiler) */ /* #define UNIX /* delete if no fork(), exec() available */ /* #define GENIX /* Yet Another Unix Clone */ /* #define BSD /* defind for 4.n BSD */ /* #define SYSV /* define for System V */ /* #define OSK /* defined by os9/68k C compiler */ /* #define BETA /* if a beta-test copy [MRS] */ #define VERSION "2.2a" /* version number. */ /* #define PYRAMID_BUG /* avoid a bug on the Pyramid */ /* #define APOLLO /* same for the Apollo */ /* #define STUPID /* avoid some complicated expressions if your C compiler chokes on them */ /* #define TERMINFO /* uses "curses" rather than termcap */ #ifdef __TURBOC__ #define alloc malloc #define signal ssignal #endif #define WIZARD "blarson" /* the person allowed to use the -D option */ #define RECORD "record"/* the file containing the list of topscorers */ #define NEWS "news" /* the file containing the latest hack news */ #define HELP "help" /* the file containing a description of the commands */ #define SHELP "hh" /* abbreviated form of the same */ #define RUMORFILE "rumors" /* a file with fortune cookies */ #define DATAFILE "data" /* a file giving the meaning of symbols used */ #ifdef OSK #include <modes.h> #define FMASK (S_IREAD|S_IWRITE) /* file creation mask */ #else #define FMASK 0660 /* file creation mask */ #endif #ifdef UNIX /* #define HLOCK "perm" /* an empty file used for locking purposes */ /* #define LLOCK "safelock" /* link to previous */ /* * Define DEF_PAGER as your default pager, e.g. "/bin/cat" or "/usr/ucb/more" * If defined, it can be overridden by the environment variable PAGER. * Hack will use its internal pager if DEF_PAGER is not defined. * (This might be preferable for security reasons.) * #define DEF_PAGER ".../mydir/mypager" */ /* * If you define MAIL, then the player will be notified of new mail * when it arrives. If you also define DEF_MAILREADER then this will * be the default mail reader, and can be overridden by the environment * variable MAILREADER; otherwise an internal pager will be used. * A stat system call is done on the mailbox every MAILCKFREQ moves. */ /* #define MAIL */ /* #define DEF_MAILREADER "/usr/bin/mail" /* or e.g. /bin/mail */ /* #define MAILCKFREQ 1 */ #define SHELL /* do not delete the '!' command */ #ifdef BSD #define SUSPEND /* let ^Z suspend the game */ #endif #ifdef BSD /* Use the high quality random number routines. */ extern long random(); #define rand() random() #define srand(seed) srandom(seed) #else extern long lrand48(); #define rand() lrand48() #define srand(seed) srand48(seed) #endif #endif /* UNIX /**/ #ifdef CHDIR /* * If you define HACKDIR, then this will be the default playground; * otherwise it will be the current directory. */ #define HACKDIR "/dd/games/lib/nethackdir" /* * Some system administrators are stupid enough to make Hack suid root * or suid daemon, where daemon has other powers besides that of reading or * writing Hack files. In such cases one should be careful with chdir's * since the user might create files in a directory of his choice. * Of course SECURE is meaningful only if HACKDIR is defined. */ /* #define SECURE /* do setuid(getuid()) after chdir() */ /* * If it is desirable to limit the number of people that can play Hack * simultaneously, define HACKDIR, SECURE and MAX_NR_OF_PLAYERS. * #define MAX_NR_OF_PLAYERS 6 */ #endif /* CHDIR /**/ /* size of terminal screen is (at least) (ROWNO+2) by COLNO */ #define COLNO 80 #define ROWNO 22 #ifdef BSD #include <strings.h> /* declarations for strcat etc. */ #define memcpy(d, s, n) bcopy(s, d, n) #define memcmp(s1, s2, n) bcmp(s2, s1, n) #else #ifdef OSK #include <strings.h> #include <time.h> #else #include <string.h> /* idem on System V */ #define index strchr #define rindex strrchr #endif #endif /* * small signed integers (8 bits suffice) * typedef char schar; * will do when you have signed characters; otherwise use * typedef short int schar; */ typedef char schar; /* * small unsigned integers (8 bits suffice - but 7 bits do not) * - these are usually object types; be careful with inequalities! - * typedef unsigned char uchar; * will be satisfactory if you have an "unsigned char" type; otherwise use * typedef unsigned short int uchar; */ typedef unsigned char uchar; /* * small integers in the range 0 - 127, usually coordinates * although they are nonnegative they must not be declared unsigned * since otherwise comparisons with signed quantities are done incorrectly */ typedef schar xchar; typedef xchar boolean; /* 0 or 1 */ #define TRUE 1 #define FALSE 0 /* * Declaration of bitfields in various structs; if your C compiler * doesnt handle bitfields well, e.g., if it is unable to initialize * structs containing bitfields, then you might use * #define Bitfield(x,n) uchar x * since the bitfields used never have more than 7 bits. (Most have 1 bit.) * otherwise: * #define Bitfield(x,n) unsigned x:n */ #define Bitfield(x,n) uchar x #define SIZE(x) (int)(sizeof(x) / sizeof(x[0])) #ifdef MSDOS #include <fcntl.h> #define exit msexit /* do chdir first */ #ifdef getchar # undef getchar #endif /* getchar /**/ #define getchar tgetch #define DGK /* MS DOS specific enhancements by dgk */ #ifdef DGK # include "msdos.h" /* contains necessary externs for msdos.c */ # define SHELL /* via exec of COMMAND.COM */ # define PATHLEN 64 /* maximum pathlength */ # define FILENAME 80 /* maximum filename length (conservative) */ # define FROMPERM 1 /* for ramdisk use */ # define TOPERM 2 /* for ramdisk use */ # define glo(x) name_file(lock, x) /* name_file used for bones */ extern char *configfile; #endif /* DGK /**/ #endif /* MSDOS /**/ /* * Conditional compilation of special options are controlled here. * If you define the following flags, you will add not only to the * complexity of the game but also to the size of the load module. */ #define DOGNAME /* Name of your first dog as an option */ #define SPELLS /* Spell casting by M. Stephenson */ #define PRAYERS /* Prayer code by M. Stephenson */ #define KAA /* Various changes made by Ken Arromdee */ #define MARKER /* Magic marker modification from Gil Neiger */ #define NEWCLASS /* Samurai/Ninja etc. by M. Stephenson */ #define SAFE_ATTACK /* Safe attack code by Don Kneller */ #define PROBING /* Wand of probing code by Gil Neiger */ #define DIAGS /* Diagnostics after death/quit by Gil Neiger */ #define SORTING /* Sorted inventory by Don Kneller */ #define DGKMOD /* Additional features by Don Kneller */ #define REDO /* support for redoing last command - DGK */ #define HARD /* Enhanced wizard code by M. Stephenson */ #define WALKIES /* Leash code by M. Stephenson */ #define NEWTRAPS /* Magic and Squeeky board traps by Scott R. Turner*/ #define FREEHAND /* Cannot use Pick-axe without wielding it. */ #define SPIDERS /* Spiders and webs by Scott R. Turner */ #define FOUNTAINS /* Fountain code by SRT (+ GAN + EB) */ #define KOPS /* Keystone Kops by Scott R. Turner */ #define ROCKMOLE /* Rockmoles by Scott R. Turner */ #define COM_COMPL /* Command line completion by John S. Bien */ #define GRAPHICS /* Funky screen character support (Eric S. Raymond) */ #define HACKOPTIONS /* Support DGK-style HACKOPTIONS processing (ESR) */ #define RPH /* Various hacks by Richard P. Hughey */ #define KJSMODS /* Various changes made by Kevin Sweet */ #define BVH /* Additions by Bruce Holloway */ #define SAC /* Soldiers, barracks by Steve Creps */ #if defined(MSDOS) && defined(GRAPHICS) #define MSDOSCOLOR #endif /* * Status Line options. */ #define GOLD_ON_BOTL #define EXP_ON_BOTL #ifdef REDO #define DOAGAIN '\001' /* Used in tty.c and cmd.c */ #endif #ifdef DGKMOD #define LARGEST_INT ((1 << 15) - 1) #endif #endif /* CONFIG /**/ SHAR_EOF cat << \SHAR_EOF > makefile.osk # Hack or Quest Makefile. # osk version (based on unix version) by blarson@ecla.usc.edu # Warning: osk make doesn't beleive the dependencies!!!!!! # you must make each .r file by hand! # flags may have to be changed as required CFLAGS = -dvoid=int LFLAGS = -i TERMLIB = -l=/dd/lib/termlib.l # make NetHack GAME = nethack GAMEUID = games GAMEGRP = bin # GAMEDIR also appears in config.h as "HACKDIR". GAMEDIR = /dd/games/lib/$(GAME)dir SHELLDIR = /dd/games MANDIR = /dd/man MANEXT = man 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 hack.c invent.c lev.c unixmain.c makemon.c mhitu.c\ mklev.c mkmaze.c mkobj.c mkshop.c mon.c monmove.c monst.c o_init.c\ objnam.c options.c osk.c pager.c polyself.c potion.c pray.c pri.c\ prisym.c read.c rip.c rnd.c rumors.c save.c search.c shk.c shknam.c\ sit.c spell.c steal.c termcap.c timeout.c topl.c topten.c track.c\ trap.c osktty.c u_init.c oskunix.c vault.c version.c wield.c wizard.c\ worm.c worn.c write.c zap.c CSOURCES = $(HACKCSRC) makedefs.c HSOURCES = config.h date.h edog.h eshk.h extern.h flag.h func_tab.h\ gen.h gold.h hack.h mfndpos.h mkroom.h monst.h msdos.h\ obj.h objclass.h objects.h onames.h permonst.h rm.h\ spell.h trap.h wseg.h you.h SOURCES = $(CSOURCES) $(HSOURCES) AUX = help hh nethack.$(MANEXT) nethack.sh VARAUX = data rumors DISTR = $(SOURCES) $(AUX) $(VARAUX) README.OLD README\ Makefile Makefile.pc Make.ini HOBJ1 = alloc.r apply.r bones.r cmd.r decl.r do.r do_name.r\ do_wear.r dog.r dogmove.r dothrow.r eat.r end.r engrave.r fight.r\ fountain.r hack.r invent.r lev.r unixmain.r makemon.r mhitu.r\ mklev.r mkmaze.r mkobj.r mkshop.r mon.r monmove.r monst.r o_init.r osk.r HOBJ2 = objnam.r options.r pager.r polyself.r potion.r pray.r pri.r\ prisym.r read.r rip.r rnd.r rumors.r save.r search.r shk.r shknam.r\ sit.r spell.r steal.r termcap.r timeout.r topl.r topten.r track.r\ trap.r osktty.r u_init.r oskunix.r vault.r version.r wield.r wizard.r\ worm.r worn.r write.r zap.r nethack: $(HOBJ1) hobj2.r cc $(LFLAGS) -f=$(GAME) $(HOBJ1) hobj2.r $(TERMLIB) hobj2.r: $(HOBJ2) merge $(HOBJ2) >-hobj2.r makedefs: makedefs.r alloc.r osk.r config.h cc -f=./makedefs alloc.r makedefs.r osk.r RUMORFILES= rumors.base rumors.kaa rumors.mrx rumors: config.h $(RUMORFILES) makedefs ./makedefs -r data: config.h data.base makedefs ./makedefs -d date.h: $(SOURCES) makedefs ./makedefs -D trap.h: config.h makedefs ./makedefs -t onames.h: makedefs objects.h ./makedefs -o unixmain.r: unixmain.c osktty.r: osktty.c oskunix.r: oskunix.c initial: deldir -q $(GAMEDIR) makdir $(SHELLDIR) makdir $(GAMEDIR) $(GAMEDIR)/save touch $(GAMEDIR)/perm touch $(GAMEDIR)/record attr -r -pr $(GAMEDIR)/* attr -r -w -pr -pw $(GAMEDIR) $(GAMEDIR)/save install: $(VARAUX) $(GAME) makdir $(GAMEDIR) makdir $(GAMEDIR)/save del $(GAMEDIR)/$(GAME) del $(GAMEDIR)/bones* $(GAMEDIR)/alock* $(GAMEDIR)/wizard* del $(GAMEDIR)/save/* touch $(GAMEDIR)/perm $(GAMEDIR)/record copy -r -b=16 -w=$(GAMEDIR) help hh rumors data copy -r -b=16 -w=$(GAMEDIR)/$(GAME) $(GAME) attr -e -pe $(GAMEDIR)/$(GAME) copy -r -b=16 $(GAME).$(MANEXT) $(MANDIR)/$(GAME).$(MANEXT) clean: del *.r spotless: clean del $(GAME) makedefs del Makefile $(VARAUX) osk.r: osk.c apply.r: apply.c hack.h edog.h mkroom.h bones.r: bones.c hack.h hack.r: hack.c hack.h cmd.r: cmd.c hack.h func_tab.h decl.r: decl.c hack.h mkroom.h do.r: do.c hack.h do_name.r: do_name.c hack.h do_wear.r: do_wear.c hack.h dog.r: dog.c hack.h edog.h mkroom.h dogmove.r: dogmove.c hack.h mfndpos.h edog.h mkroom.h dothrow.r: dothrow.c hack.h eat.r: eat.c hack.h end.r: end.c hack.h engrave.r: engrave.c hack.h fight.r: fight.c hack.h fountain.r: fountain.c hack.h mkroom.h invent.r: invent.c hack.h wseg.h lev.r: lev.c hack.h mkroom.h wseg.h makemon.r: makemon.c hack.h mhitu.r: mhitu.c hack.h mklev.r: mklev.c hack.h mkroom.h mkmaze.r: mkmaze.c hack.h mkroom.h mkobj.r: mkobj.c hack.h mkshop.r: mkshop.c hack.h mkroom.h eshk.h mon.r: mon.c hack.h mfndpos.h monmove.r: monmove.c hack.h mfndpos.h monst.r: monst.c hack.h eshk.h o_init.r: o_init.c config.h objects.h onames.h objnam.r: objnam.c hack.h options.r: options.c hack.h pager.r: pager.c hack.h polyself.r: polyself.c hack.h potion.r: potion.c hack.h pray.r: pray.c hack.h pri.r: pri.c hack.h prisym.r: prisym.c hack.h wseg.h read.r: read.c hack.h rip.r: rip.c hack.h rumors.r: rumors.c hack.h save.r: save.c hack.h search.r: search.c hack.h shk.r: shk.c hack.h mfndpos.h mkroom.h eshk.h shknam.r: shknam.c hack.h sit.r: sit.c hack.h spell.r: spell.c hack.h steal.r: steal.c hack.h termcap.r: termcap.c hack.h timeout.r: timeout.c hack.h topl.r: topl.c hack.h topten.r: topten.c hack.h track.r: track.c hack.h trap.r: trap.c hack.h edog.h mkroom.h u_init.r: u_init.c hack.h vault.r: vault.c hack.h mkroom.h wield.r: wield.c hack.h wizard.r: wizard.c hack.h worm.r: worm.c hack.h wseg.h worn.r: worn.c hack.h write.r: write.c hack.h zap.r: zap.c hack.h version.r: version.c hack.h date.h rnd.r: rnd.c config.h extern.h: config.h spell.h obj.h touch extern.h hack.h: extern.h flag.h gold.h monst.h objclass.h rm.h trap.h you.h touch hack.h objects.h: config.h objclass.h touch objects.h you.h: config.h onames.h permonst.h touch you.h SHAR_EOF cat << \SHAR_EOF > readme.osk os9/68k nethack notes I couldn't get make to work properly, even with the -b options. hobj2.r is an artifact of a shell limitation. I wound up creating empty files and requesting .r files be made as nessisary to get it to work. This is not a small program. I had to deiniz my ramdisk to get it to load or run. (I have 1/2 meg.) It also takes lots of disk space. /dd/games/lib/nethackdir gets big. You may want to put it elsewhere. (see makefile.osk and config.h.osk) The lock code does not work. You have to enforce only one game at a time some other way (such as not enough memory) until it gets fixed. This is based on nethack 2.2, with all its known bugs. (Such as the dogname one.) I've also noticed rooms near the left edge have a blank top wall, this gets fixed in a redraw. SHAR_EOF cat << \SHAR_EOF > osk.c #include <stdio.h> rename(old, new) char *old, *new; { int os9fork(); int child; char *eargv[4]; extern char **environ; int status; eargv[0] = "rename"; eargv[1] = old; eargv[2] = new; eargv[3] = (char *)NULL; unlink(new); child = os9exec(os9fork, eargv[0], eargv, environ, 0, 0); if(child == -1) return -1; while(wait(&status) != child) {} errno = status & 0xffff; return errno ? -1 : 0; } perror(s) char *s; { extern int errno; fprintf(stderr, "%s: %d\n", s, errno); } fputc(f) FILE *f; { return putc(f); } /* a pseuto-random number generator of questionable quality. Even * if it was ok to begin with, I probably got the translation from * fortran wrong. */ static int cseed = 12345; static int tseed = 1073; srand(seed) int seed; { if(seed == 1) { cseed = 12345; tseed = 1073; } else { if(seed < 0) seed = -seed; cseed = tseed = seed; } } int rand() { tseed = (tseed << 15) | (((unsigned)tseed >> 15) ^ (tseed >> 17)); tseed = (tseed >> 17) | ((tseed << 17) ^ (tseed << 15)); cseed = (cseed << 16) + ((unsigned)cseed >> 11) + (cseed << 10) + (cseed << 8) + (cseed << 7) + (cseed << 6) + (cseed << 3) + (cseed << 2) + cseed; return (tseed ^ cseed) & 0x7fffffff; } SHAR_EOF cat << \SHAR_EOF > osktty.c /* SCCS Id: @(#)unixtty.c 2.1 87/11/09 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* tty.c - (Unix) version */ /* With thanks to the people who sent code for SYSV - hpscdi!jon, * arnold@ucsf-cgl, wcs@bo95b, cbcephus!pds and others. */ #include <stdio.h> #include "extern.h" #include "hack.h" #include "func_tab.h" /* * Some systems may have getchar() return EOF for various reasons, and * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs. */ #ifndef BSD #define NR_OF_EOFS 20 #endif #include <sgstat.h> #define termstruct sgbuf #define kill_sym sg_dlnch #define erase_sym sg_bspch #define EXTABS 0xffffffff #define tabflgs sg_tabcr #define ECHO 0xffffffff #define echoflgs sg_echo /* #define cbrkflgs sg_flags */ /* #define CBRKMASK CBREAK */ /* #define CBRKON /* empty */ #define OSPEED(x) (x).sg_baud #define GTTY(x) (_gs_opt(0, x)) #define STTY(x) (_ss_opt(0, x)) #define getioctls() {} #define setioctls() {} extern short ospeed; static char erase_char, kill_char; static boolean settty_needed = FALSE; struct termstruct inittyb, curttyb; /* * Get initial state of terminal, set ospeed (for termcap routines) * and switch off tab expansion if necessary. * Called by startup() in termcap.c and after returning from ! or ^Z */ gettty(){ if(GTTY(&inittyb) < 0) perror("Hack (gettty)"); curttyb = inittyb; ospeed = OSPEED(inittyb); erase_char = inittyb.erase_sym; kill_char = inittyb.kill_sym; getioctls(); /* do not expand tabs - they might be needed inside a cm sequence */ if(curttyb.tabflgs & EXTABS) { curttyb.tabflgs &= ~EXTABS; setctty(); } settty_needed = TRUE; } /* reset terminal to original state */ settty(s) char *s; { clear_screen(); end_screen(); if(s) printf(s); (void) fflush(stdout); if(STTY(&inittyb) < 0) perror("Hack (settty)"); flags.echo = (inittyb.echoflgs & ECHO) ? ON : OFF; #ifdef OSK flags.cbreak = stdin->_flag & _UNBUF ? ON : OFF; #else flags.cbreak = (CBRKON(inittyb.cbrkflgs & CBRKMASK)) ? ON : OFF; #endif setioctls(); } setctty(){ if(STTY(&curttyb) < 0) perror("Hack (setctty)"); } setftty(){ register int ef = 0; /* desired value of flags & ECHO */ register int change = 0; #ifndef OSK register int cf = CBRKON(CBRKMASK); /* desired value of flags & CBREAK */ #endif flags.echo = OFF; flags.cbreak = ON; /* Should use (ECHO|CRMOD) here instead of ECHO */ if((curttyb.echoflgs & ECHO) != ef){ curttyb.echoflgs &= ~ECHO; /* curttyb.echoflgs |= ef; */ change++; } #ifdef OSK if(!(stdin->_flag & _UNBUF)) stdin->_flag |= _UNBUF; if(curttyb.sg_eofch) curttyb.sg_eofch = 0, change++; if(curttyb.sg_kbich) curttyb.sg_kbich = 0, change++; if(curttyb.sg_kbach) curttyb.sg_kbach = 0, change++; #else if((curttyb.cbrkflgs & CBRKMASK) != cf){ curttyb.cbrkflgs &= ~CBRKMASK; curttyb.cbrkflgs |= cf; #ifdef USG /* be satisfied with one character; no timeout */ curttyb.c_cc[VMIN] = 1; /* was VEOF */ curttyb.c_cc[VTIME] = 0; /* was VEOL */ #endif change++; } #endif if(change){ setctty(); } start_screen(); } /* fatal error */ /*VARARGS1*/ error(s,x,y) char *s; { if(settty_needed) settty((char *) 0); printf(s,x,y); putchar('\n'); exit(1); } /* * Read a line closed with '\n' into the array char bufp[BUFSZ]. * (The '\n' is not stored. The string is closed with a '\0'.) * Reading can be interrupted by an escape ('\033') - now the * resulting string is "\033". */ getlin(bufp) register char *bufp; { register char *obufp = bufp; register int c; flags.toplin = 2; /* nonempty, no --More-- required */ for(;;) { (void) fflush(stdout); if((c = getchar()) == EOF) { *bufp = 0; return; } if(c == '\033') { *obufp = c; obufp[1] = 0; return; } if(c == erase_char || c == '\b') { if(bufp != obufp) { bufp--; putstr("\b \b"); /* putsym converts \b */ } else bell(); } else if(c == '\n') { *bufp = 0; return; } else if(' ' <= c && c < '\177') { /* avoid isprint() - some people don't have it ' ' is not always a printing char */ *bufp = c; bufp[1] = 0; putstr(bufp); if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO) bufp++; } else if(c == kill_char || c == '\177') { /* Robert Viduya */ /* this test last - @ might be the kill_char */ while(bufp != obufp) { bufp--; putstr("\b \b"); } } else bell(); } } getret() { cgetret(""); } cgetret(s) register char *s; { putsym('\n'); if(flags.standout) standoutbeg(); putstr("Hit "); putstr(flags.cbreak ? "space" : "return"); putstr(" to continue: "); if(flags.standout) standoutend(); xwaitforspace(s); } char morc; /* tell the outside world what char he used */ xwaitforspace(s) register char *s; /* chars allowed besides space or return */ { register int c; morc = 0; while((c = readchar()) != '\n') { if(flags.cbreak) { if(c == ' ') break; if(s && index(s,c)) { morc = c; break; } bell(); } } } static int last_multi; char * parse() { static char inline[COLNO]; register foo; multi = 0; flags.move = 1; if(!Invisible) curs_on_u(); else home(); while((foo = readchar()) >= '0' && foo <= '9') { multi = 10*multi+foo-'0'; #ifdef DGKMOD if (multi < 0 || multi > LARGEST_INT) multi = LARGEST_INT; if (multi > 9) { remember_topl(); home(); cl_end(); printf("Count: %d", multi); } #endif last_multi = multi; } # ifdef REDO if (foo == DOAGAIN || in_doagain) multi = last_multi; else { savech(0); /* reset input queue */ savech(foo); } # endif if(multi) { multi--; save_cm = inline; } inline[0] = foo; inline[1] = 0; if(foo == 'g' || foo == 'G'){ inline[1] = getchar(); #ifdef QUEST if(inline[1] == foo) inline[2] = getchar(); else #endif inline[2] = 0; } if(foo == 'm' || foo == 'M'){ inline[1] = getchar(); inline[2] = 0; } clrlin(); return(inline); } char readchar() { register int sym; (void) fflush(stdout); if((sym = getchar()) == EOF) #ifdef NR_OF_EOFS { /* * Some SYSV systems seem to return EOFs for various reasons * (?like when one hits break or for interrupted systemcalls?), * and we must see several before we quit. */ register int cnt = NR_OF_EOFS; while (cnt--) { clearerr(stdin); /* omit if clearerr is undefined */ if((sym = getchar()) != EOF) goto noteof; } end_of_input(); noteof: ; } #else end_of_input(); #endif /* NR_OF_EOFS /**/ if(flags.toplin == 1) flags.toplin = 2; return((char) sym); } end_of_input() { settty("End of input?\n"); clearlocks(); exit(0); } #ifdef COM_COMPL /* Read in an extended command - doing command line completion for * when enough character have been entered to make a unique command. * This is just a modified getlin(). -jsb */ get_ext_cmd(bufp) register char *bufp; { register char *obufp = bufp; register int c; int com_index, index; flags.toplin = 2; /* nonempty, no --More-- required */ for(;;) { (void) fflush(stdout); if((c = readchar()) == EOF) { *bufp = 0; return; } if(c == '\033') { *obufp = c; obufp[1] = 0; return; } if(c == erase_char || c == '\b') { if(bufp != obufp) { bufp--; putstr("\b \b"); /* putsym converts \b */ } else bell(); } else if(c == '\n') { *bufp = 0; return; } else if(' ' <= c && c < '\177') { /* avoid isprint() - some people don't have it ' ' is not always a printing char */ *bufp = c; bufp[1] = 0; index = 0; com_index = -1; while(extcmdlist[index].ef_txt != (char *) 0){ if(!strncmp(obufp, extcmdlist[index].ef_txt, strlen(obufp))) if(com_index == -1) /* No matches yet*/ com_index = index; else /* More than 1 match */ com_index = -2; index++; } if(com_index >= 0){ strcpy(obufp, extcmdlist[com_index].ef_txt); /* finish print our string */ putstr(bufp); bufp = obufp; /* reset it */ if(strlen(obufp) < BUFSIZ-1 && strlen(obufp) < COLNO) /* set bufp at the end of our * string */ bufp += strlen(obufp); } else { putstr(bufp); if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO) bufp++; } } else if(c == kill_char || c == '\177') { /* Robert Viduya */ /* this test last - @ might be the kill_char */ while(bufp != obufp) { bufp--; putstr("\b \b"); } } else bell(); } } #endif COM_COMPL SHAR_EOF cat << \SHAR_EOF > oskunix.c /* SCCS Id: @(#)unixunix.c 1.4 87/08/08 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* hack.unix.c - version 1.0.3 */ /* This file collects some Unix dependencies; pager.c contains some more */ /* * The time is used for: * - seed for rand() * - year on tombstone and yymmdd in record file * - phase of the moon (various monsters react to NEW_MOON or FULL_MOON) * - night and midnight (the undead are dangerous at midnight) * - determination of what files are "very old" */ #include <stdio.h> #include <errno.h> #include "hack.h" /* mainly for index() which depends on BSD */ #ifdef OSK #include <direct.h> #else #include <sys/types.h> /* for time_t and stat */ #include <sys/stat.h> #ifdef BSD #include <sys/time.h> #else #include <time.h> #endif #endif extern char *getenv(); extern time_t time(); setrandom() { (void) srand((int) time ((time_t *) 0)); } struct tm * getlt() { time_t date; struct tm *localtime(); (void) time(&date); return(localtime(&date)); } getyear() { return(1900 + getlt()->tm_year); } char * getdate() { static char datestr[7]; register struct tm *lt = getlt(); (void) sprintf(datestr, "%2d%2d%2d", lt->tm_year, lt->tm_mon + 1, lt->tm_mday); if(datestr[2] == ' ') datestr[2] = '0'; if(datestr[4] == ' ') datestr[4] = '0'; return(datestr); } phase_of_the_moon() /* 0-7, with 0: new, 4: full */ { /* moon period: 29.5306 days */ /* year: 365.2422 days */ register struct tm *lt = getlt(); register int epact, diy, golden; diy = lt->tm_yday; golden = (lt->tm_year % 19) + 1; epact = (11 * golden + 18) % 30; if ((epact == 25 && golden > 11) || epact == 24) epact++; return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 ); } night() { register int hour = getlt()->tm_hour; return(hour < 6 || hour > 21); } midnight() { return(getlt()->tm_hour == 0); } #ifdef OSK struct fildes buf, hbuf; #else struct stat buf, hbuf; #endif gethdate(name) char *name; { /* old version - for people short of space */ /* /* register char *np; /* if(stat(name, &hbuf)) /* error("Cannot get status of %s.", /* (np = rindex(name, '/')) ? np+1 : name); /* /* version using PATH from: seismo!gregc@ucsf-cgl.ARPA (Greg Couch) */ /* * The problem with #include <sys/param.h> is that this include file * does not exist on all systems, and moreover, that it sometimes includes * <sys/types.h> again, so that the compiler sees these typedefs twice. */ #define MAXPATHLEN 1024 register char *np, *path; char filename[MAXPATHLEN+1]; #ifdef OSK int i; #endif if (index(name, '/') != NULL || (path = getenv("PATH")) == NULL) path = ""; for (;;) { if ((np = index(path, ':')) == NULL) np = path + strlen(path); /* point to end str */ if (np - path <= 1) /* %% */ (void) strcpy(filename, name); else { (void) strncpy(filename, path, np - path); filename[np - path] = '/'; (void) strcpy(filename + (np - path) + 1, name); } #ifdef OSK if ((i = open(filename, S_IREAD)) != -1) if(_gs_gfd(i, &hbuf, sizeof hbuf) != -1) { close(i); return; } else close(i); #else if (stat(filename, &hbuf) == 0) return; #endif if (*np == '\0') break; path = np + 1; } error("Cannot get status of %s.", (np = rindex(name, '/')) ? np+1 : name); } uptodate(fd) { #ifdef OSK if(_gs_gfd(fd, &buf, sizeof buf) < 0) { #else if(fstat(fd, &buf)) { #endif pline("Cannot get status of saved level? "); return(0); } #ifdef OSK if(memcmp(buf.fd_date, hbuf.fd_date, sizeof buf.fd_date) < 0) { #else if(buf.st_mtime < hbuf.st_mtime) { #endif pline("Saved level is out of date. "); return(0); } return(1); } /* see whether we should throw away this xlock file */ veryold(fd) { #ifdef OSK return 0; /* OSK should not need this */ #else register int i; time_t date; if(fstat(fd, &buf)) return(0); /* cannot get status */ if(buf.st_size != sizeof(int)) return(0); /* not an xlock file */ (void) time(&date); if(date - buf.st_mtime < 3L*24L*60L*60L) { /* recent */ extern int errno; int lockedpid; /* should be the same size as hackpid */ if(read(fd, (char *)&lockedpid, sizeof(lockedpid)) != sizeof(lockedpid)) /* strange ... */ return(0); /* From: Rick Adams <seismo!rick> /* This will work on 4.1cbsd, 4.2bsd and system 3? & 5. /* It will do nothing on V7 or 4.1bsd. */ if(!(kill(lockedpid, 0) == -1 && errno == ESRCH)) return(0); } (void) close(fd); for(i = 1; i <= MAXLEVEL; i++) { /* try to remove all */ glo(i); (void) unlink(lock); } glo(0); if(unlink(lock)) return(0); /* cannot remove it */ return(1); /* success! */ #endif } getlock() { #ifdef OSK /* implament later using OSK file locks */ lock[0] = 'a'; #else extern int errno, hackpid, locknum; register int i = 0, fd; (void) fflush(stdout); /* we ignore QUIT and INT at this point */ if (link(HLOCK, LLOCK) == -1) { register int errnosv = errno; perror(HLOCK); printf("Cannot link %s to %s\n", LLOCK, HLOCK); switch(errnosv) { case ENOENT: printf("Perhaps there is no (empty) file %s ?\n", HLOCK); break; case EACCES: printf("It seems you don't have write permission here.\n"); break; case EEXIST: printf("(Try again or rm %s.)\n", LLOCK); break; default: printf("I don't know what is wrong."); } getret(); error(""); /*NOTREACHED*/ } regularize(lock); glo(0); if(locknum > 25) locknum = 25; do { if(locknum) lock[0] = 'a' + i++; if((fd = open(lock, 0)) == -1) { if(errno == ENOENT) goto gotlock; /* no such file */ perror(lock); (void) unlink(LLOCK); error("Cannot open %s", lock); } if(veryold(fd)) /* if true, this closes fd and unlinks lock */ goto gotlock; (void) close(fd); } while(i < locknum); (void) unlink(LLOCK); error(locknum ? "Too many hacks running now." : "There is a game in progress under your name."); gotlock: fd = creat(lock, FMASK); if(unlink(LLOCK) == -1) error("Cannot unlink %s.", LLOCK); if(fd == -1) { error("cannot creat lock file."); } else { if(write(fd, (char *) &hackpid, sizeof(hackpid)) != sizeof(hackpid)){ error("cannot write lock"); } if(close(fd) == -1) { error("cannot close lock"); } } #endif } #ifdef MAIL /* * Notify user when new mail has arrived. [Idea from Merlyn Leroy, but * I don't know the details of his implementation.] * { Later note: he disliked my calling a general mailreader and felt that * hack should do the paging itself. But when I get mail, I want to put it * in some folder, reply, etc. - it would be unreasonable to put all these * functions in hack. } * The mail daemon '2' is at present not a real monster, but only a visual * effect. Thus, makemon() is superfluous. This might become otherwise, * however. The motion of '2' is less restrained than usual: diagonal moves * from a DOOR are possible. He might also use SDOOR's. Also, '2' is visible * in a ROOM, even when you are Blind. * Its path should be longer when you are Telepat-hic and Blind. * * Interesting side effects: * - You can get rich by sending yourself a lot of mail and selling * it to the shopkeeper. Unfortunately mail isn't very valuable. * - You might die in case '2' comes along at a critical moment during * a fight and delivers a scroll the weight of which causes you to * collapse. * * Possible extensions: * - Open the file MAIL and do fstat instead of stat for efficiency. * (But sh uses stat, so this cannot be too bad.) * - Examine the mail and produce a scroll of mail called "From somebody". * - Invoke MAILREADER in such a way that only this single letter is read. * * - Make him lose his mail when a Nymph steals the letter. * - Do something to the text when the scroll is enchanted or cancelled. */ #include "mkroom.h" static struct stat omstat,nmstat; static char *mailbox; static long laststattime; getmailstatus() { if(!(mailbox = getenv("MAIL"))) return; if(stat(mailbox, &omstat)){ #ifdef PERMANENT_MAILBOX pline("Cannot get status of MAIL=%s .", mailbox); mailbox = 0; #else omstat.st_mtime = 0; #endif } } ckmailstatus() { if(!mailbox #ifdef MAILCKFREQ || moves < laststattime + MAILCKFREQ #endif ) return; laststattime = moves; if(stat(mailbox, &nmstat)){ #ifdef PERMANENT_MAILBOX pline("Cannot get status of MAIL=%s anymore.", mailbox); mailbox = 0; #else nmstat.st_mtime = 0; #endif } else if(nmstat.st_mtime > omstat.st_mtime) { if(nmstat.st_size) newmail(); getmailstatus(); /* might be too late ... */ } } newmail() { /* produce a scroll of mail */ register struct obj *obj; register struct monst *md; extern char plname[]; extern struct obj *mksobj(), *addinv(); extern struct monst *makemon(); extern struct permonst pm_mail_daemon; obj = mksobj(SCR_MAIL); if(md = makemon(&pm_mail_daemon, u.ux, u.uy)) /* always succeeds */ mdrush(md,0); pline("\"Hello, %s! I have some mail for you.\"", plname); if(md) { if(dist(md->mx,md->my) > 2) pline("\"Catch!\""); more(); /* let him disappear again */ mdrush(md,1); mondead(md); } obj = addinv(obj); (void) identify(obj); /* set known and do prinv() */ } /* make md run through the cave */ mdrush(md,away) register struct monst *md; boolean away; { register int uroom = inroom(u.ux, u.uy); if(uroom >= 0) { register int tmp = rooms[uroom].fdoor; register int cnt = rooms[uroom].doorct; register int fx = u.ux, fy = u.uy; while(cnt--) { if(dist(fx,fy) < dist(doors[tmp].x, doors[tmp].y)){ fx = doors[tmp].x; fy = doors[tmp].y; } tmp++; } tmp_at(-1, md->data->mlet); /* open call */ if(away) { /* interchange origin and destination */ unpmon(md); tmp = fx; fx = md->mx; md->mx = tmp; tmp = fy; fy = md->my; md->my = tmp; } while(fx != md->mx || fy != md->my) { register int dx,dy,nfx = fx,nfy = fy,d1,d2; tmp_at(fx,fy); d1 = DIST(fx,fy,md->mx,md->my); for(dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++) if(dx || dy) { d2 = DIST(fx+dx,fy+dy,md->mx,md->my); if(d2 < d1) { d1 = d2; nfx = fx+dx; nfy = fy+dy; } } if(nfx != fx || nfy != fy) { fx = nfx; fy = nfy; } else { if(!away) { md->mx = fx; md->my = fy; } break; } } tmp_at(-1,-1); /* close call */ } if(!away) pmon(md); } readmail() { #ifdef DEF_MAILREADER /* This implies that UNIX is defined */ register char *mr = 0; more(); if(!(mr = getenv("MAILREADER"))) mr = DEF_MAILREADER; if(child(1)){ execl(mr, mr, (char *) 0); exit(1); } #else (void) page_file(mailbox, FALSE); #endif /* get new stat; not entirely correct: there is a small time window where we do not see new mail */ getmailstatus(); } #endif /* MAIL /**/ regularize(s) /* normalize file name - we don't like ..'s or /'s */ register char *s; { register char *lp; while((lp = index(s, '.')) || (lp = index(s, '/'))) *lp = '_'; } SHAR_EOF # End of shell archive exit 0 Bob Larson Arpa: Blarson@Ecla.Usc.Edu blarson@skat.usc.edu Uucp: {sdcrdcf,cit-vax}!oberon!skat!blarson Prime mailing list: info-prime-request%fns1@ecla.usc.edu oberon!fns1!info-prime-request