Source:NetHack 2.3e/unixunix.c
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. }