OSDN Git Service

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