abstract
| - 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 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 17. #include 18. #include "hack.h" /* mainly for index() which depends on BSD */ 19. 20. #include /* for time_t and stat */ 21. #include 22. #ifdef BSD 23. #include 24. #else 25. #include 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 is that this include file 106. * does not exist on all systems, and moreover, that it sometimes includes 107. * 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 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
", LLOCK, HLOCK); 194. switch(errnosv) { 195. case ENOENT: 196. printf("Perhaps there is no (empty) file %s ?
", HLOCK); 197. break; 198. case EACCES: 199. printf("It seems you don't have write permission here.
"); 200. break; 201. case EEXIST: 202. printf("(Try again or rm %s.)
", 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. }
|