abstract
| - 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
", LLOCK, HLOCK); 197. switch(errnosv) { 198. case ENOENT: 199. printf("Perhaps there is no (empty) file %s ?
", HLOCK); 200. break; 201. case EACCES: 202. printf("It seems you don't have write permission here.
"); 203. break; 204. case EEXIST: 205. printf("(Try again or rm %s.)
", 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. }
|