Source:NetHack 2.3e/unixunix.c

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

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

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   16. #include  17. #include "hack.h"	/* mainly for index which depends on BSD */ 18.   19.   #include			/* for time_t and stat */ 20.  #include	  21. #ifdef BSD 22.  #include	  23. #else 24.  #include	  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	   is that this include file 105.  * does not exist on all systems, and moreover, that it sometimes includes 106.  *  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  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. }