OSDN Git Service

upgrade to 3.6.1
[jnethack/source.git] / sys / share / pcsys.c
1 /* NetHack 3.6  pcsys.c $NHDT-Date: 1524689500 2018/04/25 20:51:40 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.31 $ */
2 /*      Copyright (c) 2012 by Michael Allison              */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /*
6  *  System related functions for MSDOS, OS/2, TOS, and Windows NT
7  */
8
9 #define NEED_VARARGS
10 #include "hack.h"
11 #include "wintty.h"
12
13 #include <ctype.h>
14 #include <fcntl.h>
15 #if !defined(MSDOS) && !defined(WIN_CE) /* already done */
16 #include <process.h>
17 #endif
18 #ifdef __GO32__
19 #define P_WAIT 0
20 #define P_NOWAIT 1
21 #endif
22 #ifdef TOS
23 #include <osbind.h>
24 #endif
25 #if defined(MSDOS) && !defined(__GO32__)
26 #define findfirst findfirst_file
27 #define findnext findnext_file
28 #define filesize filesize_nh
29 #endif
30
31 #if defined(MICRO) || defined(WIN32) || defined(OS2)
32 void FDECL(nethack_exit, (int));
33 #else
34 #define nethack_exit exit
35 #endif
36 STATIC_DCL void NDECL(msexit);
37
38 #ifdef MOVERLAY
39 extern void __far __cdecl _movepause(void);
40 extern void __far __cdecl _moveresume(void);
41 extern unsigned short __far __cdecl _movefpause;
42 extern unsigned short __far __cdecl _movefpaused;
43 #define __MOVE_PAUSE_DISK 2  /* Represents the executable file */
44 #define __MOVE_PAUSE_CACHE 4 /* Represents the cache memory */
45 #endif                       /* MOVERLAY */
46
47 #ifdef MFLOPPY
48 STATIC_DCL boolean NDECL(record_exists);
49 #ifndef TOS
50 STATIC_DCL boolean NDECL(comspec_exists);
51 #endif
52 #endif
53
54 #ifdef WIN32
55 extern int GUILaunched; /* from nttty.c */
56 #endif
57
58 #if defined(MICRO) || defined(WIN32)
59
60 void
61 flushout()
62 {
63     (void) fflush(stdout);
64     return;
65 }
66
67 static const char *COMSPEC =
68 #ifdef TOS
69     "SHELL";
70 #else
71     "COMSPEC";
72 #endif
73
74 #define getcomspec() nh_getenv(COMSPEC)
75
76 #ifdef SHELL
77 int
78 dosh()
79 {
80     extern char orgdir[];
81     char *comspec;
82 #ifndef __GO32__
83     int spawnstat;
84 #endif
85 #if defined(MSDOS) && defined(NO_TERMS)
86     int grmode = iflags.grmode;
87 #endif
88     if ((comspec = getcomspec())) {
89 #ifndef TOS /* TOS has a variety of shells */
90         suspend_nhwindows(
91             "To return to NetHack, enter \"exit\" at the system prompt.\n");
92 #else
93 #if defined(MSDOS) && defined(NO_TERMS)
94         grmode = iflags.grmode;
95 #endif
96         suspend_nhwindows((char *) 0);
97 #endif /* TOS */
98 #ifndef NOCWD_ASSUMPTIONS
99         chdirx(orgdir, 0);
100 #endif
101 #ifdef __GO32__
102         if (system(comspec) < 0) { /* wsu@eecs.umich.edu */
103 #else
104 #ifdef MOVERLAY
105         /* Free the cache memory used by overlays, close .exe */
106         _movefpause |= __MOVE_PAUSE_DISK;
107         _movefpause |= __MOVE_PAUSE_CACHE;
108         _movepause();
109 #endif
110         spawnstat = spawnl(P_WAIT, comspec, comspec, (char *) 0);
111 #ifdef MOVERLAY
112         _moveresume();
113 #endif
114
115         if (spawnstat < 0) {
116 #endif
117             raw_printf("Can't spawn \"%s\"!", comspec);
118             getreturn("to continue");
119         }
120 #ifdef TOS
121         /* Some shells (e.g. Gulam) turn the cursor off when they exit */
122         if (iflags.BIOS)
123             (void) Cursconf(1, -1);
124 #endif
125 #ifndef NOCWD_ASSUMPTIONS
126         chdirx(hackdir, 0);
127 #endif
128         get_scr_size(); /* maybe the screen mode changed (TH) */
129 #if defined(MSDOS) && defined(NO_TERMS)
130         if (grmode)
131             gr_init();
132 #endif
133         resume_nhwindows();
134     } else
135         pline("Can't find %s.", COMSPEC);
136     return 0;
137 }
138 #endif /* SHELL */
139
140 #ifdef MFLOPPY
141
142 void
143 eraseall(path, files)
144 const char *path, *files;
145 {
146     char buf[PATHLEN];
147     char *foundfile;
148
149     foundfile = foundfile_buffer();
150     Sprintf(buf, "%s%s", path, files);
151     if (findfirst(buf))
152         do {
153             Sprintf(buf, "%s%s", path, foundfile);
154             (void) unlink(buf);
155         } while (findnext());
156     return;
157 }
158
159 /*
160  * Rewritten for version 3.3 to be faster
161  */
162 void
163 copybones(mode)
164 int mode;
165 {
166     char from[PATHLEN], to[PATHLEN], last[13];
167     char *frompath, *topath;
168     char *foundfile;
169 #ifndef TOS
170     int status;
171     char copy[8], *comspec;
172 #endif
173
174     if (!ramdisk)
175         return;
176
177     /* Find the name of the last file to be transferred
178      */
179     frompath = (mode != TOPERM) ? permbones : levels;
180     foundfile = foundfile_buffer();
181     last[0] = '\0';
182     Sprintf(from, "%s%s", frompath, allbones);
183     topath = (mode == TOPERM) ? permbones : levels;
184 #ifdef TOS
185     eraseall(topath, allbones);
186 #endif
187     if (findfirst(from))
188         do {
189 #ifdef TOS
190             Sprintf(from, "%s%s", frompath, foundfile);
191             Sprintf(to, "%s%s", topath, foundfile);
192             if (_copyfile(from, to))
193                 goto error_copying;
194 #endif
195             Strcpy(last, foundfile);
196         } while (findnext());
197 #ifdef TOS
198     else
199         return;
200 #else
201     if (last[0]) {
202         Sprintf(copy, "%cC copy", switchar());
203
204         /* Remove any bones files in `to' directory.
205          */
206         eraseall(topath, allbones);
207
208         /* Copy `from' to `to' */
209         Sprintf(to, "%s%s", topath, allbones);
210         comspec = getcomspec();
211         status = spawnl(P_WAIT, comspec, comspec, copy, from, to, "> nul",
212                         (char *) 0);
213     } else
214         return;
215 #endif /* TOS */
216
217     /* See if the last file got there.  If so, remove the ramdisk bones
218      * files.
219      */
220     Sprintf(to, "%s%s", topath, last);
221     if (findfirst(to)) {
222         if (mode == TOPERM)
223             eraseall(frompath, allbones);
224         return;
225     }
226
227 #ifdef TOS
228 error_copying:
229 #endif
230     /* Last file didn't get there.
231      */
232     Sprintf(to, "%s%s", topath, allbones);
233     msmsg("Can't copy \"%s\" to \"%s\" -- ", from, to);
234 #ifndef TOS
235     if (status < 0)
236         msmsg("can't spawn \"%s\"!", comspec);
237     else
238 #endif
239         msmsg((freediskspace(topath) < filesize(from))
240                   ? "insufficient disk space."
241                   : "bad path(s)?");
242     if (mode == TOPERM) {
243         msmsg("Bones will be left in \"%s\"\n", *levels ? levels : hackdir);
244     } else {
245         /* Remove all bones files on the RAMdisk */
246         eraseall(levels, allbones);
247         playwoRAMdisk();
248     }
249     return;
250 }
251
252 void
253 playwoRAMdisk()
254 {
255     int c;
256
257     msmsg("Do you wish to play without a RAMdisk? [yn] (n)");
258
259     /* Set ramdisk false *before* exit-ing (because msexit calls
260      * copybones)
261      */
262     ramdisk = FALSE;
263     c = tgetch();
264     if (c == 'Y')
265         c = 'y';
266     if (c != 'y') {
267         settty("Be seeing you...\n");
268         nethack_exit(EXIT_SUCCESS);
269     }
270     set_lock_and_bones();
271     return;
272 }
273
274 int
275 saveDiskPrompt(start)
276 int start;
277 {
278     char buf[BUFSIZ], *bp;
279     char qbuf[QBUFSZ];
280
281     int fd;
282
283     if (sysflags.asksavedisk) {
284         /* Don't prompt if you can find the save file */
285         if ((fd = open_savefile()) >= 0) {
286             (void) nhclose(fd);
287             return 1;
288         }
289         clear_nhwindow(WIN_MESSAGE);
290         pline("If save file is on a save disk, insert that disk now.");
291         mark_synch();
292         Sprintf(qbuf, "File name (default \"%s\"%s) ?", SAVEF,
293                 start ? "" : ", <Esc> cancels save");
294         getlin(qbuf, buf);
295         clear_nhwindow(WIN_MESSAGE);
296         if (!start && *buf == '\033')
297             return 0;
298
299         /* Strip any whitespace. Also, if nothing was entered except
300          * whitespace, do not change the value of SAVEF.
301          */
302         for (bp = buf; *bp; bp++)
303             if (!isspace((uchar) *bp)) {
304                 strncpy(SAVEF, bp, PATHLEN);
305                 break;
306             }
307     }
308     return 1;
309 }
310
311 /* Return 1 if the record file was found */
312 STATIC_OVL boolean
313 record_exists()
314 {
315     FILE *fp;
316
317     fp = fopen_datafile(RECORD, "r", TRUE);
318     if (fp) {
319         fclose(fp);
320         return TRUE;
321     }
322     return FALSE;
323 }
324 #endif /* MFLOPPY */
325
326 #ifdef TOS
327 #define comspec_exists() 1
328 #else
329 #ifdef MFLOPPY
330 /* Return 1 if the comspec was found */
331 STATIC_OVL boolean
332 comspec_exists()
333 {
334     int fd;
335     char *comspec;
336
337     if ((comspec = getcomspec()))
338         if ((fd = open(comspec, O_RDONLY)) >= 0) {
339             (void) nhclose(fd);
340             return TRUE;
341         }
342     return FALSE;
343 }
344 #endif /* MFLOPPY */
345 #endif
346
347 #ifdef MFLOPPY
348 /* Prompt for game disk, then check for record file.
349  */
350 void
351 gameDiskPrompt()
352 {
353     if (sysflags.asksavedisk) {
354         if (record_exists() && comspec_exists())
355             return;
356         (void) putchar('\n');
357         getreturn("when the game disk has been inserted");
358     }
359     if (comspec_exists() && record_exists())
360         return;
361
362     if (!comspec_exists())
363         msmsg("\n\nWARNING: can't find command processor \"%s\"!\n",
364               getcomspec());
365     if (!record_exists())
366         msmsg("\n\nWARNING: can't find record file \"%s\"!\n", RECORD);
367     msmsg("If the game disk is not in, insert it now.\n");
368     getreturn("to continue");
369     return;
370 }
371 #endif /* MFLOPPY */
372 #endif /* MICRO */
373
374 /*
375  * Add a backslash to any name not ending in /, \ or :   There must
376  * be room for the \
377  */
378 void
379 append_slash(name)
380 char *name;
381 {
382     char *ptr;
383
384     if (!*name)
385         return;
386     ptr = name + (strlen(name) - 1);
387     if (*ptr != '\\' && *ptr != '/' && *ptr != ':') {
388         *++ptr = '\\';
389         *++ptr = '\0';
390     }
391     return;
392 }
393
394 #ifdef WIN32
395 boolean getreturn_enabled;
396 int redirect_stdout;
397 #endif
398
399 void
400 getreturn(str)
401 const char *str;
402 {
403 #ifdef WIN32
404     if (!getreturn_enabled)
405         return;
406 #endif
407 #ifdef TOS
408     msmsg("Hit <Return> %s.", str);
409 #else
410     msmsg("Hit <Enter> %s.", str);
411 #endif
412     while (pgetchar() != '\n')
413         ;
414     return;
415 }
416
417 #ifndef WIN32
418 void msmsg
419 VA_DECL(const char *, fmt)
420 {
421     VA_START(fmt);
422     VA_INIT(fmt, const char *);
423 #if defined(MSDOS) && defined(NO_TERMS)
424     if (iflags.grmode)
425         gr_finish();
426 #endif
427     Vprintf(fmt, VA_ARGS);
428     flushout();
429     VA_END();
430     return;
431 }
432 #endif
433
434 /*
435  * Follow the PATH, trying to fopen the file.
436  */
437 #ifdef TOS
438 #ifdef __MINT__
439 #define PATHSEP ':'
440 #else
441 #define PATHSEP ','
442 #endif
443 #else
444 #define PATHSEP ';'
445 #endif
446
447 FILE *
448 fopenp(name, mode)
449 const char *name, *mode;
450 {
451     char buf[BUFSIZ], *bp, *pp, lastch = 0;
452     FILE *fp;
453
454     /* Try the default directory first.  Then look along PATH.
455      */
456     (void) strncpy(buf, name, BUFSIZ - 1);
457     buf[BUFSIZ - 1] = '\0';
458     if ((fp = fopen(buf, mode)))
459         return fp;
460     else {
461         int ccnt = 0;
462         pp = getenv("PATH");
463         while (pp && *pp) {
464             bp = buf;
465             while (*pp && *pp != PATHSEP) {
466                 lastch = *bp++ = *pp++;
467                 ccnt++;
468             }
469             if (lastch != '\\' && lastch != '/') {
470                 *bp++ = '\\';
471                 ccnt++;
472             }
473             (void) strncpy(bp, name, (BUFSIZ - ccnt) - 2);
474             bp[BUFSIZ - ccnt - 1] = '\0';
475             if ((fp = fopen(buf, mode)))
476                 return fp;
477             if (*pp)
478                 pp++;
479         }
480     }
481 #ifdef OS2_CODEVIEW /* one more try for hackdir */
482     (void) strncpy(buf, hackdir, BUFSZ);
483     buf[BUFSZ - 1] = '\0';
484     if ((strlen(name) + 1 + strlen(buf)) < BUFSZ - 1) {
485         append_slash(buf);
486         Strcat(buf, name);
487     } else
488         impossible("fopenp() buffer too small for complete filename!");
489     if (fp = fopen(buf, mode))
490         return fp;
491 #endif
492     return (FILE *) 0;
493 }
494
495 #if defined(MICRO) || defined(WIN32) || defined(OS2)
496 void
497 nethack_exit(code)
498 int code;
499 {
500     msexit();
501     exit(code);
502 }
503
504 /* Chdir back to original directory
505  */
506 #ifdef TOS
507 extern boolean run_from_desktop; /* set in pcmain.c */
508 #endif
509
510 STATIC_OVL void
511 msexit()
512 {
513 #ifdef CHDIR
514     extern char orgdir[];
515 #endif
516
517     flushout();
518 #ifndef TOS
519 #ifndef WIN32
520     enable_ctrlP(); /* in case this wasn't done */
521 #endif
522 #endif
523 #ifdef MFLOPPY
524     if (ramdisk)
525         copybones(TOPERM);
526 #endif
527 #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
528     chdir(orgdir); /* chdir, not chdirx */
529     chdrive(orgdir);
530 #endif
531 #ifdef TOS
532     if (run_from_desktop)
533         getreturn("to continue"); /* so the user can read the score list */
534 #ifdef TEXTCOLOR
535     if (colors_changed)
536         restore_colors();
537 #endif
538 #endif
539 #ifdef WIN32
540     /* Only if we started from the GUI, not the command prompt,
541      * we need to get one last return, so the score board does
542      * not vanish instantly after being created.
543      * GUILaunched is defined and set in nttty.c.
544      */
545     synch_cursor();
546     if (GUILaunched)
547         getreturn("to end");
548     synch_cursor();
549 #endif
550     getreturn_enabled = TRUE;
551     wait_synch();
552     return;
553 }
554 #endif /* MICRO || WIN32 || OS2 */