Source:NetHack 2.3e/unixunix.c

From NetHackWiki
Jump to navigation Jump to search

Below is the full text to unixunix.c from the source code of NetHack 2.3e.

Warning! This is the source code from an old release. For newer releases, see Source code

Screenshots and source code from Hack are used under the CWI license.

1.    /*	SCCS Id: @(#)unixunix.c	2.3	87/12/12
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    
4.    /* This file collects some Unix dependencies; pager.c contains some more */
5.    
6.    /*
7.     * The time is used for:
8.     *	- seed for rand()
9.     *	- year on tombstone and yymmdd in record file
10.    *	- phase of the moon (various monsters react to NEW_MOON or FULL_MOON)
11.    *	- night and midnight (the undead are dangerous at midnight)
12.    *	- determination of what files are "very old"
13.    */
14.   
15.   #include <stdio.h>
16.   #include <errno.h>
17.   #include "hack.h"	/* mainly for index() which depends on BSD */
18.   
19.   #include	<sys/types.h>		/* for time_t and stat */
20.   #include	<sys/stat.h>
21.   #ifdef BSD
22.   #include	<sys/time.h>
23.   #else
24.   #include	<time.h>
25.   #endif
26.   
27.   extern char *getenv();
28.   extern time_t time();
29.   
30.   setrandom()
31.   {
32.   	(void) srand((int) time ((time_t *) 0));
33.   }
34.   
35.   struct tm *
36.   getlt()
37.   {
38.   	time_t date;
39.   	struct tm *localtime();
40.   
41.   	(void) time(&date);
42.   	return(localtime(&date));
43.   }
44.   
45.   getyear()
46.   {
47.   	return(1900 + getlt()->tm_year);
48.   }
49.   
50.   char *
51.   getdate()
52.   {
53.   	static char datestr[7];
54.   	register struct tm *lt = getlt();
55.   
56.   	(void) sprintf(datestr, "%2d%2d%2d",
57.   		lt->tm_year, lt->tm_mon + 1, lt->tm_mday);
58.   	if(datestr[2] == ' ') datestr[2] = '0';
59.   	if(datestr[4] == ' ') datestr[4] = '0';
60.   	return(datestr);
61.   }
62.   
63.   phase_of_the_moon()			/* 0-7, with 0: new, 4: full */
64.   {					/* moon period: 29.5306 days */
65.   					/* year: 365.2422 days */
66.   	register struct tm *lt = getlt();
67.   	register int epact, diy, golden;
68.   
69.   	diy = lt->tm_yday;
70.   	golden = (lt->tm_year % 19) + 1;
71.   	epact = (11 * golden + 18) % 30;
72.   	if ((epact == 25 && golden > 11) || epact == 24)
73.   		epact++;
74.   
75.   	return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 );
76.   }
77.   
78.   night()
79.   {
80.   	register int hour = getlt()->tm_hour;
81.   
82.   	return(hour < 6 || hour > 21);
83.   }
84.   
85.   midnight()
86.   {
87.   	return(getlt()->tm_hour == 0);
88.   }
89.   
90.   struct stat buf, hbuf;
91.   
92.   gethdate(name) char *name; {
93.   /* old version - for people short of space */
94.   /*
95.   /* register char *np;
96.   /*	if(stat(name, &hbuf))
97.   /*		error("Cannot get status of %s.",
98.   /*			(np = rindex(name, '/')) ? np+1 : name);
99.   /*
100.  /* version using PATH from: seismo!gregc@ucsf-cgl.ARPA (Greg Couch) */
101.  
102.  
103.  /*
104.   * The problem with   #include	<sys/param.h>   is that this include file
105.   * does not exist on all systems, and moreover, that it sometimes includes
106.   * <sys/types.h> again, so that the compiler sees these typedefs twice.
107.   */
108.  #define		MAXPATHLEN	1024
109.  
110.  register char *np, *path;
111.  char filename[MAXPATHLEN+1];
112.  	if (index(name, '/') != NULL || (path = getenv("PATH")) == NULL)
113.  		path = "";
114.  
115.  	for (;;) {
116.  		if ((np = index(path, ':')) == NULL)
117.  			np = path + strlen(path);	/* point to end str */
118.  		if (np - path <= 1)			/* %% */
119.  			(void) strcpy(filename, name);
120.  		else {
121.  			(void) strncpy(filename, path, np - path);
122.  			filename[np - path] = '/';
123.  			(void) strcpy(filename + (np - path) + 1, name);
124.  		}
125.  		if (stat(filename, &hbuf) == 0)
126.  			return;
127.  		if (*np == '\0')
128.  			break;
129.  		path = np + 1;
130.  	}
131.  	error("Cannot get status of %s.",
132.  		(np = rindex(name, '/')) ? np+1 : name);
133.  }
134.  
135.  uptodate(fd) {
136.  	if(fstat(fd, &buf)) {
137.  		pline("Cannot get status of saved level? ");
138.  		return(0);
139.  	}
140.  	if(buf.st_mtime < hbuf.st_mtime) {
141.  		pline("Saved level is out of date. ");
142.  		return(0);
143.  	}
144.  	return(1);
145.  }
146.  
147.  /* see whether we should throw away this xlock file */
148.  veryold(fd) {
149.  	register int i;
150.  	time_t date;
151.  
152.  	if(fstat(fd, &buf)) return(0);			/* cannot get status */
153.  	if(buf.st_size != sizeof(int)) return(0);	/* not an xlock file */
154.  	(void) time(&date);
155.  	if(date - buf.st_mtime < 3L*24L*60L*60L) {	/* recent */
156.  		extern int errno;
157.  		int lockedpid;	/* should be the same size as hackpid */
158.  
159.  		if(read(fd, (char *)&lockedpid, sizeof(lockedpid)) !=
160.  			sizeof(lockedpid))
161.  			/* strange ... */
162.  			return(0);
163.  
164.  		/* From: Rick Adams <seismo!rick>
165.  		/* This will work on 4.1cbsd, 4.2bsd and system 3? & 5.
166.  		/* It will do nothing on V7 or 4.1bsd. */
167.  #ifndef NETWORK
168.  		/* It will do a VERY BAD THING if the playground is shared
169.  		   by more than one machine! -pem */
170.    		if(!(kill(lockedpid, 0) == -1 && errno == ESRCH))
171.  #endif
172.  			return(0);
173.  	}
174.  	(void) close(fd);
175.  	for(i = 1; i <= MAXLEVEL; i++) {		/* try to remove all */
176.  		glo(i);
177.  		(void) unlink(lock);
178.  	}
179.  	glo(0);
180.  	if(unlink(lock)) return(0);			/* cannot remove it */
181.  	return(1);					/* success! */
182.  }
183.  
184.  getlock()
185.  {
186.  	extern int errno, hackpid, locknum;
187.  	register int i = 0, fd;
188.  
189.  	(void) fflush(stdout);
190.  
191.  	/* we ignore QUIT and INT at this point */
192.  	if (link(HLOCK, LLOCK) == -1) {
193.  		register int errnosv = errno;
194.  
195.  		perror(HLOCK);
196.  		printf("Cannot link %s to %s\n", LLOCK, HLOCK);
197.  		switch(errnosv) {
198.  		case ENOENT:
199.  		    printf("Perhaps there is no (empty) file %s ?\n", HLOCK);
200.  		    break;
201.  		case EACCES:
202.  		    printf("It seems you don't have write permission here.\n");
203.  		    break;
204.  		case EEXIST:
205.  		    printf("(Try again or rm %s.)\n", LLOCK);
206.  		    break;
207.  		default:
208.  		    printf("I don't know what is wrong.");
209.  		}
210.  		getret();
211.  		error("");
212.  		/*NOTREACHED*/
213.  	}
214.  
215.  	regularize(lock);
216.  	glo(0);
217.  	if(locknum > 25) locknum = 25;
218.  
219.  	do {
220.  		if(locknum) lock[0] = 'a' + i++;
221.  
222.  		if((fd = open(lock, 0)) == -1) {
223.  			if(errno == ENOENT) goto gotlock;    /* no such file */
224.  			perror(lock);
225.  			(void) unlink(LLOCK);
226.  			error("Cannot open %s", lock);
227.  		}
228.  
229.  		if(veryold(fd))	/* if true, this closes fd and unlinks lock */
230.  			goto gotlock;
231.  		(void) close(fd);
232.  	} while(i < locknum);
233.  
234.  	(void) unlink(LLOCK);
235.  	error(locknum ? "Too many hacks running now."
236.  		      : "There is a game in progress under your name.");
237.  gotlock:
238.  	fd = creat(lock, FMASK);
239.  	if(unlink(LLOCK) == -1)
240.  		error("Cannot unlink %s.", LLOCK);
241.  	if(fd == -1) {
242.  		error("cannot creat lock file.");
243.  	} else {
244.  		if(write(fd, (char *) &hackpid, sizeof(hackpid))
245.  		    != sizeof(hackpid)){
246.  			error("cannot write lock");
247.  		}
248.  		if(close(fd) == -1) {
249.  			error("cannot close lock");
250.  		}
251.  	}
252.  }	
253.  
254.  #ifdef MAIL
255.  
256.  /*
257.   * Notify user when new mail has arrived. [Idea from Merlyn Leroy, but
258.   * I don't know the details of his implementation.]
259.   * { Later note: he disliked my calling a general mailreader and felt that
260.   *   hack should do the paging itself. But when I get mail, I want to put it
261.   *   in some folder, reply, etc. - it would be unreasonable to put all these
262.   *   functions in hack. }
263.   * The mail daemon '2' is at present not a real monster, but only a visual
264.   * effect. Thus, makemon() is superfluous. This might become otherwise,
265.   * however. The motion of '2' is less restrained than usual: diagonal moves
266.   * from a DOOR are possible. He might also use SDOOR's. Also, '2' is visible
267.   * in a ROOM, even when you are Blind.
268.   * Its path should be longer when you are Telepat-hic and Blind.
269.   *
270.   * Interesting side effects:
271.   *	- You can get rich by sending yourself a lot of mail and selling
272.   *	  it to the shopkeeper. Unfortunately mail isn't very valuable.
273.   *	- You might die in case '2' comes along at a critical moment during
274.   *	  a fight and delivers a scroll the weight of which causes you to
275.   *	  collapse.
276.   *
277.   * Possible extensions:
278.   *	- Open the file MAIL and do fstat instead of stat for efficiency.
279.   *	  (But sh uses stat, so this cannot be too bad.)
280.   *	- Examine the mail and produce a scroll of mail called "From somebody".
281.   *	- Invoke MAILREADER in such a way that only this single letter is read.
282.   *
283.   *	- Make him lose his mail when a Nymph steals the letter.
284.   *	- Do something to the text when the scroll is enchanted or cancelled.
285.   */
286.  #include	"mkroom.h"
287.  static struct stat omstat,nmstat;
288.  static char *mailbox;
289.  static long laststattime;
290.  
291.  getmailstatus() {
292.  	if(!(mailbox = getenv("MAIL")))
293.  		return;
294.  	if(stat(mailbox, &omstat)){
295.  #ifdef PERMANENT_MAILBOX
296.  		pline("Cannot get status of MAIL=%s .", mailbox);
297.  		mailbox = 0;
298.  #else
299.  		omstat.st_mtime = 0;
300.  #endif
301.  	}
302.  }
303.  
304.  ckmailstatus() {
305.  	if(!mailbox
306.  #ifdef MAILCKFREQ
307.  		    || moves < laststattime + MAILCKFREQ
308.  #endif
309.  							)
310.  		return;
311.  	laststattime = moves;
312.  	if(stat(mailbox, &nmstat)){
313.  #ifdef PERMANENT_MAILBOX
314.  		pline("Cannot get status of MAIL=%s anymore.", mailbox);
315.  		mailbox = 0;
316.  #else
317.  		nmstat.st_mtime = 0;
318.  #endif
319.  	} else if(nmstat.st_mtime > omstat.st_mtime) {
320.  		if(nmstat.st_size)
321.  			newmail();
322.  		getmailstatus();	/* might be too late ... */
323.  	}
324.  }
325.  
326.  newmail() {
327.  	/* produce a scroll of mail */
328.  	register struct obj *obj;
329.  	register struct monst *md;
330.  	extern char plname[];
331.  	extern struct obj *mksobj(), *addinv();
332.  	extern struct monst *makemon();
333.  	extern struct permonst pm_mail_daemon;
334.  
335.  	obj = mksobj(SCR_MAIL);
336.  	if(md = makemon(&pm_mail_daemon, u.ux, u.uy)) /* always succeeds */
337.  		mdrush(md,0);
338.  
339.  	pline("\"Hello, %s%s! I have some mail for you.\"", 
340.  		(Badged) ? "Officer " : "", plname);
341.  	if(md) {
342.  		if(dist(md->mx,md->my) > 2)
343.  			pline("\"Catch!\"");
344.  		more();
345.  
346.  		/* let him disappear again */
347.  		mdrush(md,1);
348.  		mondead(md);
349.  	}
350.  
351.  	obj = addinv(obj);
352.  	(void) identify(obj);		/* set known and do prinv() */
353.  }
354.  
355.  /* make md run through the cave */
356.  mdrush(md,away)
357.  register struct monst *md;
358.  boolean away;
359.  {
360.  	register int uroom = inroom(u.ux, u.uy);
361.  	if(uroom >= 0) {
362.  		register int tmp = rooms[uroom].fdoor;
363.  		register int cnt = rooms[uroom].doorct;
364.  		register int fx = u.ux, fy = u.uy;
365.  		while(cnt--) {
366.  			if(dist(fx,fy) < dist(doors[tmp].x, doors[tmp].y)){
367.  				fx = doors[tmp].x;
368.  				fy = doors[tmp].y;
369.  			}
370.  			tmp++;
371.  		}
372.  		tmp_at(-1, md->data->mlet);	/* open call */
373.  		if(away) {	/* interchange origin and destination */
374.  			unpmon(md);
375.  			tmp = fx; fx = md->mx; md->mx = tmp;
376.  			tmp = fy; fy = md->my; md->my = tmp;
377.  		}
378.  		while(fx != md->mx || fy != md->my) {
379.  			register int dx,dy,nfx = fx,nfy = fy,d1,d2;
380.  
381.  			tmp_at(fx,fy);
382.  			d1 = DIST(fx,fy,md->mx,md->my);
383.  			for(dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++)
384.  			    if(dx || dy) {
385.  				d2 = DIST(fx+dx,fy+dy,md->mx,md->my);
386.  				if(d2 < d1) {
387.  				    d1 = d2;
388.  				    nfx = fx+dx;
389.  				    nfy = fy+dy;
390.  				}
391.  			    }
392.  			if(nfx != fx || nfy != fy) {
393.  			    fx = nfx;
394.  			    fy = nfy;
395.  			} else {
396.  			    if(!away) {
397.  				md->mx = fx;
398.  				md->my = fy;
399.  			    }
400.  			    break;
401.  			} 
402.  		}
403.  		tmp_at(-1,-1);			/* close call */
404.  	}
405.  	if(!away)
406.  		pmon(md);
407.  }
408.  
409.  readmail() {
410.  #ifdef DEF_MAILREADER			/* This implies that UNIX is defined */
411.  	register char *mr = 0;
412.  	more();
413.  	if(!(mr = getenv("MAILREADER")))
414.  		mr = DEF_MAILREADER;
415.  	if(child(1)){
416.  		execl(mr, mr, (char *) 0);
417.  		exit(1);
418.  	}
419.  #else
420.  	(void) page_file(mailbox, FALSE);
421.  #endif
422.  	/* get new stat; not entirely correct: there is a small time
423.  	   window where we do not see new mail */
424.  	getmailstatus();
425.  }
426.  #endif /* MAIL /**/
427.  
428.  regularize(s)	/* normalize file name - we don't like ..'s or /'s */
429.  register char *s;
430.  {
431.  	register char *lp;
432.  
433.  	while((lp = index(s, '.')) || (lp = index(s, '/')))
434.  		*lp = '_';
435.  }