Source:NetHack 1.3d/unixunix.c

From NetHackWiki
Jump to: navigation, search

Below is the full text to unixunix.c from the source code of NetHack 1.3d. To link to a particular line, write [[NetHack 1.3d/unixunix.c#line123]], for example.

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

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

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