OSDN Git Service

upgrade to 3.6.1
[jnethack/source.git] / sys / winnt / winnt.c
1 /* NetHack 3.6  winnt.c $NHDT-Date: 1524321419 2018/04/21 14:36:59 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.30 $ */
2 /* Copyright (c) NetHack PC Development Team 1993, 1994 */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /*
6  *  WIN32 system functions.
7  *
8  *  Initial Creation: Michael Allison - January 31/93
9  *
10  */
11
12 #define NEED_VARARGS
13 #include "hack.h"
14 #include <dos.h>
15 #ifndef __BORLANDC__
16 #include <direct.h>
17 #endif
18 #include <ctype.h>
19 #include "win32api.h"
20 #include "wintty.h"
21 #ifdef WIN32
22
23 /*
24  * The following WIN32 API routines are used in this file.
25  *
26  * GetDiskFreeSpace
27  * GetVolumeInformation
28  * GetUserName
29  * FindFirstFile
30  * FindNextFile
31  * FindClose
32  *
33  */
34
35 /* globals required within here */
36 HANDLE ffhandle = (HANDLE) 0;
37 WIN32_FIND_DATA ffd;
38 typedef HWND(WINAPI *GETCONSOLEWINDOW)();
39 static HWND GetConsoleHandle(void);
40 static HWND GetConsoleHwnd(void);
41
42 /* The function pointer nt_kbhit contains a kbhit() equivalent
43  * which varies depending on which window port is active.
44  * For the tty port it is tty_kbhit() [from nttty.c]
45  * For the win32 port it is win32_kbhit() [from winmain.c]
46  * It is initialized to point to def_kbhit [in here] for safety.
47  */
48
49 int def_kbhit(void);
50 int (*nt_kbhit)() = def_kbhit;
51
52 char
53 switchar()
54 {
55     /* Could not locate a WIN32 API call for this- MJA */
56     return '-';
57 }
58
59 long
60 freediskspace(path)
61 char *path;
62 {
63     char tmppath[4];
64     DWORD SectorsPerCluster = 0;
65     DWORD BytesPerSector = 0;
66     DWORD FreeClusters = 0;
67     DWORD TotalClusters = 0;
68
69     tmppath[0] = *path;
70     tmppath[1] = ':';
71     tmppath[2] = '\\';
72     tmppath[3] = '\0';
73     GetDiskFreeSpace(tmppath, &SectorsPerCluster, &BytesPerSector,
74                      &FreeClusters, &TotalClusters);
75     return (long) (SectorsPerCluster * BytesPerSector * FreeClusters);
76 }
77
78 /*
79  * Functions to get filenames using wildcards
80  */
81 int
82 findfirst(path)
83 char *path;
84 {
85     if (ffhandle) {
86         FindClose(ffhandle);
87         ffhandle = (HANDLE) 0;
88     }
89     ffhandle = FindFirstFile(path, &ffd);
90     return (ffhandle == INVALID_HANDLE_VALUE) ? 0 : 1;
91 }
92
93 int
94 findnext()
95 {
96     return FindNextFile(ffhandle, &ffd) ? 1 : 0;
97 }
98
99 char *
100 foundfile_buffer()
101 {
102     return &ffd.cFileName[0];
103 }
104
105 long
106 filesize(file)
107 char *file;
108 {
109     if (findfirst(file)) {
110         return ((long) ffd.nFileSizeLow);
111     } else
112         return -1L;
113 }
114
115 /*
116  * Chdrive() changes the default drive.
117  */
118 void
119 chdrive(str)
120 char *str;
121 {
122     char *ptr;
123     char drive;
124     if ((ptr = index(str, ':')) != (char *) 0) {
125         drive = toupper((uchar) *(ptr - 1));
126         _chdrive((drive - 'A') + 1);
127     }
128 }
129
130 static int
131 max_filename()
132 {
133     DWORD maxflen;
134     int status = 0;
135
136     status = GetVolumeInformation((LPTSTR) 0, (LPTSTR) 0, 0, (LPDWORD) 0,
137                                   &maxflen, (LPDWORD) 0, (LPTSTR) 0, 0);
138     if (status)
139         return maxflen;
140     else
141         return 0;
142 }
143
144 int
145 def_kbhit()
146 {
147     return 0;
148 }
149
150 /*
151  * Strip out troublesome file system characters.
152  */
153
154 void nt_regularize(s) /* normalize file name */
155 register char *s;
156 {
157     register unsigned char *lp;
158
159     for (lp = s; *lp; lp++)
160         if (*lp == '?' || *lp == '"' || *lp == '\\' || *lp == '/'
161             || *lp == '>' || *lp == '<' || *lp == '*' || *lp == '|'
162 /*JP
163             || *lp == ':' || (*lp > 127))
164 */
165             || *lp == ':')
166             *lp = '_';
167 }
168
169 /*
170  * This is used in nhlan.c to implement some of the LAN_FEATURES.
171  */
172 char *
173 get_username(lan_username_size)
174 int *lan_username_size;
175 {
176     static TCHAR username_buffer[BUFSZ];
177     unsigned int status;
178     DWORD i = BUFSZ - 1;
179
180     /* i gets updated with actual size */
181     status = GetUserName(username_buffer, &i);
182     if (status)
183         username_buffer[i] = '\0';
184     else
185         Strcpy(username_buffer, "NetHack");
186     if (lan_username_size)
187         *lan_username_size = strlen(username_buffer);
188     return username_buffer;
189 }
190
191 #if 0
192 char *getxxx()
193 {
194 char     szFullPath[MAX_PATH] = "";
195 HMODULE  hInst = NULL;          /* NULL gets the filename of this module */
196
197 GetModuleFileName(hInst, szFullPath, sizeof(szFullPath));
198 return &szFullPath[0];
199 }
200 #endif
201
202 /* fatal error */
203 /*VARARGS1*/
204 void error
205 VA_DECL(const char *, s)
206 {
207     char buf[BUFSZ];
208     VA_START(s);
209     VA_INIT(s, const char *);
210     /* error() may get called before tty is initialized */
211     if (iflags.window_inited)
212         end_screen();
213     if (!strncmpi(windowprocs.name, "tty", 3)) {
214         buf[0] = '\n';
215         (void) vsprintf(&buf[1], s, VA_ARGS);
216         Strcat(buf, "\n");
217         msmsg(buf);
218     } else {
219         (void) vsprintf(buf, s, VA_ARGS);
220         Strcat(buf, "\n");
221         raw_printf(buf);
222     }
223     VA_END();
224     exit(EXIT_FAILURE);
225 }
226
227 void
228 Delay(int ms)
229 {
230     (void) Sleep(ms);
231 }
232
233 extern void NDECL(backsp);
234
235 void
236 win32_abort()
237 {
238     if (wizard) {
239         int c, ci, ct;
240
241         if (!iflags.window_inited)
242             c = 'n';
243         ct = 0;
244         msmsg("Execute debug breakpoint wizard?");
245         while ((ci = nhgetch()) != '\n') {
246             if (ct > 0) {
247                 backsp(); /* \b is visible on NT */
248                 (void) putchar(' ');
249                 backsp();
250                 ct = 0;
251                 c = 'n';
252             }
253             if (ci == 'y' || ci == 'n' || ci == 'Y' || ci == 'N') {
254                 ct = 1;
255                 c = ci;
256                 msmsg("%c", c);
257             }
258         }
259         if (c == 'y')
260             DebugBreak();
261     }
262     abort();
263 }
264
265 static char interjection_buf[INTERJECTION_TYPES][1024];
266 static int interjection[INTERJECTION_TYPES];
267
268 void
269 interject_assistance(num, interjection_type, ptr1, ptr2)
270 int num;
271 int interjection_type;
272 genericptr_t ptr1;
273 genericptr_t ptr2;
274 {
275     switch (num) {
276     case 1: {
277         char *panicmsg = (char *) ptr1;
278         char *datadir = (char *) ptr2;
279         char *tempdir = nh_getenv("TEMP");
280         interjection_type = INTERJECT_PANIC;
281         interjection[INTERJECT_PANIC] = 1;
282         /*
283          * ptr1 = the panic message about to be delivered.
284          * ptr2 = the directory prefix of the dungeon file
285          *        that failed to open.
286          * Check to see if datadir matches tempdir or a
287          * common windows temp location. If it does, inform
288          * the user that they are probably trying to run the
289          * game from within their unzip utility, so the required
290          * files really don't exist at the location. Instruct
291          * them to unpack them first.
292          */
293         if (panicmsg && datadir) {
294             if (!strncmpi(datadir, "C:\\WINDOWS\\TEMP", 15)
295                 || strstri(datadir, "TEMP")
296                 || (tempdir && strstri(datadir, tempdir))) {
297                 (void) strncpy(
298                     interjection_buf[INTERJECT_PANIC],
299                     "\nOne common cause of this error is attempting to "
300                     "execute\n"
301                     "the game by double-clicking on it while it is "
302                     "displayed\n"
303                     "inside an unzip utility.\n\n"
304                     "You have to unzip the contents of the zip file into a\n"
305                     "folder on your system, and then run \"NetHack.exe\" or "
306                     "\n"
307                     "\"NetHackW.exe\" from there.\n\n"
308                     "If that is not the situation, you are encouraged to\n"
309                     "report the error as shown above.\n\n",
310                     1023);
311             }
312         }
313     } break;
314     }
315 }
316
317 void
318 interject(interjection_type)
319 int interjection_type;
320 {
321     if (interjection_type >= 0 && interjection_type < INTERJECTION_TYPES)
322         msmsg(interjection_buf[interjection_type]);
323 }
324
325 #ifdef RUNTIME_PASTEBUF_SUPPORT
326
327 void port_insert_pastebuf(buf)
328 char *buf;
329 {
330     /* This implementation will utilize the windows clipboard
331      * to accomplish this.
332      */
333
334     char *tmp = buf;
335     HGLOBAL hglbCopy; 
336     WCHAR *w, w2[2];
337     int cc, rc, abytes;
338     LPWSTR lpwstrCopy;
339     HANDLE hresult;
340
341     if (!buf)
342         return; 
343  
344     cc = strlen(buf);
345     /* last arg=0 means "tell me the size of the buffer that I need" */
346     rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, buf, -1, w2, 0);
347     if (!rc) return;
348
349     abytes = rc * sizeof(WCHAR);
350     w = (WCHAR *)alloc(abytes);     
351     /* Housekeeping need: +free(w) */
352
353     rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, buf, -1, w, rc);
354     if (!rc) {
355         free(w);
356         return;
357     }
358     if (!OpenClipboard(NULL)) {
359         free(w);
360         return;
361     }
362     /* Housekeeping need: +CloseClipboard(), free(w) */
363
364     EmptyClipboard(); 
365
366     /* allocate global mem obj to hold the text */
367  
368     hglbCopy = GlobalAlloc(GMEM_MOVEABLE, abytes);
369     if (hglbCopy == NULL) { 
370         CloseClipboard(); 
371         free(w);
372         return;
373     } 
374     /* Housekeeping need: +GlobalFree(hglbCopy), CloseClipboard(), free(w) */
375  
376     lpwstrCopy = (LPWSTR)GlobalLock(hglbCopy);
377     /* Housekeeping need: +GlobalUnlock(hglbCopy), GlobalFree(hglbCopy),
378                             CloseClipboard(), free(w) */
379
380     memcpy(lpwstrCopy, w, abytes);
381     GlobalUnlock(hglbCopy);
382     /* Housekeeping need: GlobalFree(hglbCopy), CloseClipboard(), free(w) */
383
384     /* put it on the clipboard */
385     hresult = SetClipboardData(CF_UNICODETEXT, hglbCopy);
386     if (!hresult) {
387         raw_printf("Error copying to clipboard.\n");
388         GlobalFree(hglbCopy); /* only needed if clipboard didn't accept data */
389     }
390     /* Housekeeping need: CloseClipboard(), free(w) */
391  
392     CloseClipboard(); 
393     free(w);
394     return;
395 }
396
397 static HWND
398 GetConsoleHandle(void)
399 {
400     HMODULE hMod = GetModuleHandle("kernel32.dll");
401     GETCONSOLEWINDOW pfnGetConsoleWindow =
402         (GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow");
403     if (pfnGetConsoleWindow)
404         return pfnGetConsoleWindow();
405     else
406         return GetConsoleHwnd();
407 }
408
409 static HWND
410 GetConsoleHwnd(void)
411 {
412     int iterations = 0;
413     HWND hwndFound = 0;
414     char OldTitle[1024], NewTitle[1024], TestTitle[1024];
415
416     /* Get current window title */
417     GetConsoleTitle(OldTitle, sizeof OldTitle);
418
419     (void) sprintf(NewTitle, "NETHACK%d/%d", GetTickCount(),
420                    GetCurrentProcessId());
421     SetConsoleTitle(NewTitle);
422
423     GetConsoleTitle(TestTitle, sizeof TestTitle);
424     while (strcmp(TestTitle, NewTitle) != 0) {
425         iterations++;
426         /* sleep(0); */
427         GetConsoleTitle(TestTitle, sizeof TestTitle);
428     }
429     hwndFound = FindWindow(NULL, NewTitle);
430     SetConsoleTitle(OldTitle);
431     /*       printf("%d iterations\n", iterations); */
432     return hwndFound;
433 }
434
435 #endif
436
437 #ifdef RUNTIME_PORT_ID
438 /*
439  * _M_IX86 is Defined for x86 processors. This is not defined for x64
440  * processors.
441  * _M_X64  is Defined for x64 processors.
442  * _M_IA64 is Defined for Itanium Processor Family 64-bit processors.
443  * _WIN64  is Defined for applications for Win64.
444  */
445 #ifndef _M_IX86
446 #ifdef _M_X64
447 #define TARGET_PORT "x64"
448 #endif
449 #ifdef _M_IA64
450 #define TARGET_PORT "IA64"
451 #endif
452 #endif
453
454 #ifndef TARGET_PORT
455 #define TARGET_PORT "x86"
456 #endif
457
458 char *
459 get_port_id(buf)
460 char *buf;
461 {
462     Strcpy(buf, TARGET_PORT);
463     return buf;
464 }
465 #endif /* RUNTIME_PORT_ID */
466
467 #endif /* WIN32 */
468
469 /*winnt.c*/