OSDN Git Service

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