/* SCCS Id: @(#)pcsys.c 3.3 1999/12/10 /* NetHack may be freely redistributed. See license for details. */ /* * System related functions for MSDOS, OS/2, TOS, and Windows NT */ #define NEED_VARARGS #include "hack.h" #include "wintty.h" #include #include #ifndef MSDOS /* already done */ #include #endif #ifdef __GO32__ #define P_WAIT 0 #define P_NOWAIT 1 #endif #ifdef TOS #include #endif #if defined(MSDOS) && !defined(__GO32__) #define findfirst findfirst_file #define findnext findnext_file #define filesize filesize_nh #endif #if defined(MICRO) || defined(WIN32) || defined(OS2) void FDECL(nethack_exit,(int)); #else #define nethack_exit exit #endif static void NDECL(msexit); #ifdef MOVERLAY extern void __far __cdecl _movepause( void ); extern void __far __cdecl _moveresume( void ); extern unsigned short __far __cdecl _movefpause; extern unsigned short __far __cdecl _movefpaused; #define __MOVE_PAUSE_DISK 2 /* Represents the executable file */ #define __MOVE_PAUSE_CACHE 4 /* Represents the cache memory */ #endif /* MOVERLAY */ STATIC_DCL boolean NDECL(record_exists); #ifndef TOS STATIC_DCL boolean NDECL(comspec_exists); #endif #ifdef WIN32CON extern int GUILaunched; /* from nttty.c */ #endif #ifdef MICRO void flushout() { (void) fflush(stdout); return; } static const char *COMSPEC = # ifdef TOS "SHELL"; # else "COMSPEC"; # endif #define getcomspec() nh_getenv(COMSPEC) # ifdef SHELL int dosh() { extern char orgdir[]; char *comspec; int spawnstat; #if defined(MSDOS) && defined(NO_TERMS) int grmode; #endif if (comspec = getcomspec()) { # ifndef TOS /* TOS has a variety of shells */ suspend_nhwindows("To return to NetHack, enter \"exit\" at the system prompt.\n"); # else # if defined(MSDOS) && defined(NO_TERMS) grmode = iflags.grmode; # endif suspend_nhwindows((char *)0); # endif /* TOS */ chdirx(orgdir, 0); # ifdef __GO32__ if (system(comspec) < 0) { /* wsu@eecs.umich.edu */ # else # ifdef MOVERLAY /* Free the cache memory used by overlays, close .exe */ _movefpause |= __MOVE_PAUSE_DISK; _movefpause |= __MOVE_PAUSE_CACHE; _movepause(); # endif spawnstat = spawnl(P_WAIT, comspec, comspec, (char *)0); # ifdef MOVERLAY _moveresume(); # endif if ( spawnstat < 0) { # endif raw_printf("Can't spawn \"%s\"!", comspec); getreturn("to continue"); } # ifdef TOS /* Some shells (e.g. Gulam) turn the cursor off when they exit */ if (iflags.BIOS) (void)Cursconf(1, -1); # endif chdirx(hackdir, 0); get_scr_size(); /* maybe the screen mode changed (TH) */ # if defined(MSDOS) && defined(NO_TERMS) if (grmode) gr_init(); # endif resume_nhwindows(); } else pline("Can't find %s.",COMSPEC); return 0; } # endif /* SHELL */ # ifdef MFLOPPY void eraseall(path, files) const char *path, *files; { char buf[PATHLEN]; char *foundfile; foundfile = foundfile_buffer(); Sprintf(buf, "%s%s", path, files); if (findfirst(buf)) do { Sprintf(buf, "%s%s", path, foundfile); (void) unlink(buf); } while (findnext()); return; } /* * Rewritten for version 3.3 to be faster */ void copybones(mode) int mode; { char from[PATHLEN], to[PATHLEN], last[13]; char *frompath, *topath; char *foundfile; # ifndef TOS int status; char copy[8], *comspec; # endif if (!ramdisk) return; /* Find the name of the last file to be transferred */ frompath = (mode != TOPERM) ? permbones : levels; foundfile = foundfile_buffer(); last[0] = '\0'; Sprintf(from, "%s%s", frompath, allbones); topath = (mode == TOPERM) ? permbones : levels; # ifdef TOS eraseall(topath, allbones); # endif if (findfirst(from)) do { # ifdef TOS Sprintf(from, "%s%s", frompath, foundfile); Sprintf(to, "%s%s", topath, foundfile); if (_copyfile(from, to)) goto error_copying; # endif Strcpy(last, foundfile); } while (findnext()); # ifdef TOS else return; # else if (last[0]) { Sprintf(copy, "%cC copy",switchar()); /* Remove any bones files in `to' directory. */ eraseall(topath, allbones); /* Copy `from' to `to' */ Sprintf(to, "%s%s", topath, allbones); comspec = getcomspec(); status =spawnl(P_WAIT, comspec, comspec, copy, from, to, "> nul", (char *)0); } else return; # endif /* TOS */ /* See if the last file got there. If so, remove the ramdisk bones * files. */ Sprintf(to, "%s%s", topath, last); if (findfirst(to)) { if (mode == TOPERM) eraseall(frompath, allbones); return; } # ifdef TOS error_copying: # endif /* Last file didn't get there. */ Sprintf(to, "%s%s", topath, allbones); msmsg("Can't copy \"%s\" to \"%s\" -- ", from, to); # ifndef TOS if (status < 0) msmsg("can't spawn \"%s\"!", comspec); else # endif msmsg((freediskspace(topath) < filesize(from)) ? "insufficient disk space." : "bad path(s)?"); if (mode == TOPERM) { msmsg("Bones will be left in \"%s\"\n", *levels ? levels : hackdir); } else { /* Remove all bones files on the RAMdisk */ eraseall(levels, allbones); playwoRAMdisk(); } return; } void playwoRAMdisk() { int c; msmsg("Do you wish to play without a RAMdisk? [yn] (n)"); /* Set ramdisk false *before* exit-ing (because msexit calls * copybones) */ ramdisk = FALSE; c = tgetch(); if (c == 'Y') c = 'y'; if (c != 'y') { settty("Be seeing you...\n"); nethack_exit(EXIT_SUCCESS); } set_lock_and_bones(); return; } int saveDiskPrompt(start) int start; { char buf[BUFSIZ], *bp; char qbuf[QBUFSZ]; int fd; if (flags.asksavedisk) { /* Don't prompt if you can find the save file */ if ((fd = open_savefile()) >= 0) { (void) close(fd); return 1; } clear_nhwindow(WIN_MESSAGE); pline("If save file is on a save disk, insert that disk now."); mark_synch(); Sprintf(qbuf,"File name (default \"%s\"%s) ?", SAVEF, start ? "" : ", cancels save"); getlin(qbuf, buf); clear_nhwindow(WIN_MESSAGE); if (!start && *buf == '\033') return 0; /* Strip any whitespace. Also, if nothing was entered except * whitespace, do not change the value of SAVEF. */ for (bp = buf; *bp; bp++) if (!isspace(*bp)) { strncpy(SAVEF, bp, PATHLEN); break; } } return 1; } # endif /* MFLOPPY */ /* Return 1 if the record file was found */ STATIC_OVL boolean record_exists() { FILE *fp; fp = fopen_datafile(RECORD, "r", TRUE); if (fp) { fclose(fp); return TRUE; } return FALSE; } # ifdef TOS #define comspec_exists() 1 # else /* Return 1 if the comspec was found */ STATIC_OVL boolean comspec_exists() { int fd; char *comspec; if (comspec = getcomspec()) if ((fd = open(comspec, O_RDONLY)) >= 0) { (void) close(fd); return TRUE; } return FALSE; } # endif # ifdef MFLOPPY /* Prompt for game disk, then check for record file. */ void gameDiskPrompt() { if (flags.asksavedisk) { if (record_exists() && comspec_exists()) return; (void) putchar('\n'); getreturn("when the game disk has been inserted"); } if (comspec_exists() && record_exists()) return; if (!comspec_exists()) msmsg("\n\nWARNING: can't find command processor \"%s\"!\n", getcomspec()); if (!record_exists()) msmsg("\n\nWARNING: can't find record file \"%s\"!\n", RECORD); msmsg("If the game disk is not in, insert it now.\n"); getreturn("to continue"); return; } # endif /* MFLOPPY */ #endif /* MICRO */ /* * Add a backslash to any name not ending in /, \ or : There must * be room for the \ */ void append_slash(name) char *name; { char *ptr; if (!*name) return; ptr = name + (strlen(name) - 1); if (*ptr != '\\' && *ptr != '/' && *ptr != ':') { *++ptr = '\\'; *++ptr = '\0'; } return; } void getreturn(str) const char *str; { #ifdef TOS msmsg("Hit %s.", str); #else msmsg("Hit %s.", str); #endif while (Getchar() != '\n') ; return; } void msmsg VA_DECL(const char *, fmt) VA_START(fmt); VA_INIT(fmt, const char *); # if defined(MSDOS) if (iflags.grmode) gr_finish(); # endif Vprintf(fmt, VA_ARGS); flushout(); VA_END(); return; } /* * Follow the PATH, trying to fopen the file. */ #ifdef TOS # ifdef __MINT__ #define PATHSEP ':' # else #define PATHSEP ',' # endif #else #define PATHSEP ';' #endif FILE * fopenp(name, mode) const char *name, *mode; { char buf[BUFSIZ], *bp, *pp, lastch = 0; FILE *fp; /* Try the default directory first. Then look along PATH. */ (void) strncpy(buf, name, BUFSIZ - 1); buf[BUFSIZ-1] = '\0'; if (fp = fopen(buf, mode)) return fp; else { int ccnt = 0; pp = getenv("PATH"); while (pp && *pp) { bp = buf; while (*pp && *pp != PATHSEP) { lastch = *bp++ = *pp++; ccnt++; } if (lastch != '\\' && lastch != '/') { *bp++ = '\\'; ccnt++; } (void) strncpy(bp, name, (BUFSIZ - ccnt) - 2); bp[BUFSIZ-1] = '\0'; if (fp = fopen(buf, mode)) return fp; if (*pp) pp++; } } #ifdef OS2_CODEVIEW /* one more try for hackdir */ (void) strncpy(buf, hackdir, BUFSZ); buf[BUFSZ-1] = '\0'; if ((strlen(name) + 1 + strlen(buf)) < BUFSZ - 1) { append_slash(buf); Strcat(buf,name); } else impossible("fopenp() buffer too small for complete filename!"); if(fp = fopen(buf,mode)) return fp; #endif return (FILE *)0; } #if defined(MICRO) || defined(WIN32) || defined(OS2) void nethack_exit(code) int code; { msexit(); #ifdef MTHREAD_VIEW if (iflags.mthreaded) nh_thread_exit(code); /* no return from this */ else #endif exit(code); } /* Chdir back to original directory */ #ifdef TOS extern boolean run_from_desktop; /* set in pcmain.c */ #endif static void msexit() { #ifdef CHDIR extern char orgdir[]; #endif flushout(); #ifndef TOS # ifndef WIN32 enable_ctrlP(); /* in case this wasn't done */ # endif #endif #ifdef MFLOPPY if (ramdisk) copybones(TOPERM); #endif #ifdef CHDIR chdir(orgdir); /* chdir, not chdirx */ chdrive(orgdir); #endif #ifdef TOS if (run_from_desktop) getreturn("to continue"); /* so the user can read the score list */ # ifdef TEXTCOLOR if (colors_changed) restore_colors(); # endif #endif #ifdef WIN32CON /* Only if we started from the GUI, not the command prompt, * we need to get one last return, so the score board does * not vanish instantly after being created. * GUILaunched is defined and set in nttty.c. */ if (GUILaunched) getreturn("to end"); #endif return; } #ifdef WIN32 /* * This is a kludge. Just before the release of 3.3.0 the latest * version of a popular MAPI mail product was found to exhibit * a strange result where the current directory was changed out * from under NetHack resulting in a failure of all subsequent * file operations in NetHack. This routine is called prior * to all file open/renames/deletes in file.c. * * A more elegant solution will be sought after 3.3.0 is released. */ void dircheck() { char dirbuf[BUFSZ]; dirbuf[0] = '\0'; if (getcwd(dirbuf, sizeof dirbuf) != (char *)0) /* pline("%s,%s",dirbuf,hackdir); */ if (strcmp(dirbuf,hackdir) != 0) chdir(hackdir); /* chdir, not chdirx */ } #endif #endif /* MICRO || WIN32 || OS2 */