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  *  Included in both console and window based clients on the windows platform.
9  *
10  *  Initial Creation: Michael Allison - January 31/93
11  *
12  */
13 
14 #include "win10.h"
15 #include "winos.h"
16 
17 #define NEED_VARARGS
18 #include "hack.h"
19 #include <dos.h>
20 #ifndef __BORLANDC__
21 #include <direct.h>
22 #endif
23 #include <ctype.h>
24 #ifdef TTY_GRAPHICS
25 #include "wintty.h"
26 #endif
27 #ifdef WIN32
28 
29 /*
30  * The following WIN32 API routines are used in this file.
31  *
32  * GetDiskFreeSpace
33  * GetVolumeInformation
34  * GetUserName
35  * FindFirstFile
36  * FindNextFile
37  * FindClose
38  *
39  */
40 
41 /* runtime cursor display control switch */
42 boolean win32_cursorblink;
43 
44 /* globals required within here */
45 HANDLE ffhandle = (HANDLE) 0;
46 WIN32_FIND_DATA ffd;
47 extern int GUILaunched;
48 boolean getreturn_enabled;
49 int redirect_stdout;
50 
51 typedef HWND(WINAPI *GETCONSOLEWINDOW)();
52 static HWND GetConsoleHandle(void);
53 static HWND GetConsoleHwnd(void);
54 #if !defined(TTY_GRAPHICS)
55 extern void NDECL(backsp);
56 #endif
57 int NDECL(windows_console_custom_nhgetch);
58 extern void NDECL(safe_routines);
59 
60 /* The function pointer nt_kbhit contains a kbhit() equivalent
61  * which varies depending on which window port is active.
62  * For the tty port it is tty_kbhit() [from nttty.c]
63  * For the win32 port it is win32_kbhit() [from winmain.c]
64  * It is initialized to point to def_kbhit [in here] for safety.
65  */
66 
67 int def_kbhit(void);
68 int (*nt_kbhit)() = def_kbhit;
69 
70 char
switchar()71 switchar()
72 {
73     /* Could not locate a WIN32 API call for this- MJA */
74     return '-';
75 }
76 
77 long
freediskspace(path)78 freediskspace(path)
79 char *path;
80 {
81     char tmppath[4];
82     DWORD SectorsPerCluster = 0;
83     DWORD BytesPerSector = 0;
84     DWORD FreeClusters = 0;
85     DWORD TotalClusters = 0;
86 
87     tmppath[0] = *path;
88     tmppath[1] = ':';
89     tmppath[2] = '\\';
90     tmppath[3] = '\0';
91     GetDiskFreeSpace(tmppath, &SectorsPerCluster, &BytesPerSector,
92                      &FreeClusters, &TotalClusters);
93     return (long) (SectorsPerCluster * BytesPerSector * FreeClusters);
94 }
95 
96 /*
97  * Functions to get filenames using wildcards
98  */
99 int
findfirst(path)100 findfirst(path)
101 char *path;
102 {
103     if (ffhandle) {
104         FindClose(ffhandle);
105         ffhandle = (HANDLE) 0;
106     }
107     ffhandle = FindFirstFile(path, &ffd);
108     return (ffhandle == INVALID_HANDLE_VALUE) ? 0 : 1;
109 }
110 
111 int
findnext()112 findnext()
113 {
114     return FindNextFile(ffhandle, &ffd) ? 1 : 0;
115 }
116 
117 char *
foundfile_buffer()118 foundfile_buffer()
119 {
120     return &ffd.cFileName[0];
121 }
122 
123 long
filesize(file)124 filesize(file)
125 char *file;
126 {
127     if (findfirst(file)) {
128         return ((long) ffd.nFileSizeLow);
129     } else
130         return -1L;
131 }
132 
133 /*
134  * Chdrive() changes the default drive.
135  */
136 void
chdrive(str)137 chdrive(str)
138 char *str;
139 {
140     char *ptr;
141     char drive;
142     if ((ptr = index(str, ':')) != (char *) 0) {
143         drive = toupper((uchar) *(ptr - 1));
144         _chdrive((drive - 'A') + 1);
145     }
146 }
147 
148 static int
max_filename()149 max_filename()
150 {
151     DWORD maxflen;
152     int status = 0;
153 
154     status = GetVolumeInformation((LPTSTR) 0, (LPTSTR) 0, 0, (LPDWORD) 0,
155                                   &maxflen, (LPDWORD) 0, (LPTSTR) 0, 0);
156     if (status)
157         return maxflen;
158     else
159         return 0;
160 }
161 
162 int
def_kbhit()163 def_kbhit()
164 {
165     return 0;
166 }
167 
168 /*
169  * Strip out troublesome file system characters.
170  */
171 
nt_regularize(s)172 void nt_regularize(s) /* normalize file name */
173 register char *s;
174 {
175     register unsigned char *lp;
176 
177     for (lp = s; *lp; lp++)
178         if (*lp == '?' || *lp == '"' || *lp == '\\' || *lp == '/'
179             || *lp == '>' || *lp == '<' || *lp == '*' || *lp == '|'
180             || *lp == ':' || (*lp > 127))
181             *lp = '_';
182 }
183 
184 /*
185  * This is used in nhlan.c to implement some of the LAN_FEATURES.
186  */
187 char *
get_username(lan_username_size)188 get_username(lan_username_size)
189 int *lan_username_size;
190 {
191     static TCHAR username_buffer[BUFSZ];
192     DWORD i = BUFSZ - 1;
193     BOOL allowUserName = TRUE;
194 
195     Strcpy(username_buffer, "NetHack");
196 
197 #ifndef WIN32CON
198     /* Our privacy policy for the windows store version of nethack makes
199      * a promise about not collecting any personally identifiable information.
200      * Do not allow getting user name if we being run from windows store
201      * version of nethack.  In 3.7, we should remove use of username.
202      */
203     allowUserName = !win10_is_desktop_bridge_application();
204 #endif
205 
206     if (allowUserName) {
207         /* i gets updated with actual size */
208         if (GetUserName(username_buffer, &i))
209             username_buffer[i] = '\0';
210     }
211 
212     if (lan_username_size)
213         *lan_username_size = strlen(username_buffer);
214     return username_buffer;
215 }
216 
217 #if 0
218 char *getxxx()
219 {
220 char     szFullPath[MAX_PATH] = "";
221 HMODULE  hInst = NULL;  	/* NULL gets the filename of this module */
222 
223 GetModuleFileName(hInst, szFullPath, sizeof(szFullPath));
224 return &szFullPath[0];
225 }
226 #endif
227 
228 extern void NDECL(mswin_raw_print_flush);
229 extern void FDECL(mswin_raw_print, (const char *));
230 
231 /* fatal error */
232 /*VARARGS1*/
233 void error
VA_DECL(const char *,s)234 VA_DECL(const char *, s)
235 {
236     char buf[BUFSZ];
237     VA_START(s);
238     VA_INIT(s, const char *);
239     /* error() may get called before tty is initialized */
240     if (iflags.window_inited)
241         end_screen();
242     if (WINDOWPORT("tty")) {
243         buf[0] = '\n';
244         (void) vsnprintf(&buf[1], sizeof buf - (1 + sizeof "\n"), s, VA_ARGS);
245         Strcat(buf, "\n");
246         msmsg(buf);
247     } else {
248         (void) vsnprintf(buf, sizeof buf - sizeof "\n", s, VA_ARGS);
249         Strcat(buf, "\n");
250         raw_printf(buf);
251     }
252     if (windowprocs.win_raw_print == mswin_raw_print)
253         mswin_raw_print_flush();
254     VA_END();
255     exit(EXIT_FAILURE);
256 }
257 
258 void
Delay(int ms)259 Delay(int ms)
260 {
261     (void) Sleep(ms);
262 }
263 
264 void
win32_abort()265 win32_abort()
266 {
267     int c;
268 
269     if (WINDOWPORT("mswin") || WINDOWPORT("tty")) {
270         if (iflags.window_inited)
271             exit_nhwindows((char *) 0);
272         iflags.window_inited = FALSE;
273     }
274     if (!WINDOWPORT("mswin") && !WINDOWPORT("safe-startup"))
275         safe_routines();
276     if (wizard) {
277         raw_print("Execute debug breakpoint wizard?");
278         if ((c = nhgetch()) == 'y' || c == 'Y')
279             DebugBreak();
280     }
281     abort();
282 }
283 
284 static char interjection_buf[INTERJECTION_TYPES][1024];
285 static int interjection[INTERJECTION_TYPES];
286 
287 void
interject_assistance(num,interjection_type,ptr1,ptr2)288 interject_assistance(num, interjection_type, ptr1, ptr2)
289 int num;
290 int interjection_type;
291 genericptr_t ptr1;
292 genericptr_t ptr2;
293 {
294     switch (num) {
295     case 1: {
296         char *panicmsg = (char *) ptr1;
297         char *datadir = (char *) ptr2;
298         char *tempdir = nh_getenv("TEMP");
299         interjection_type = INTERJECT_PANIC;
300         interjection[INTERJECT_PANIC] = 1;
301         /*
302          * ptr1 = the panic message about to be delivered.
303          * ptr2 = the directory prefix of the dungeon file
304          *        that failed to open.
305          * Check to see if datadir matches tempdir or a
306          * common windows temp location. If it does, inform
307          * the user that they are probably trying to run the
308          * game from within their unzip utility, so the required
309          * files really don't exist at the location. Instruct
310          * them to unpack them first.
311          */
312         if (panicmsg && datadir) {
313             if (!strncmpi(datadir, "C:\\WINDOWS\\TEMP", 15)
314                 || strstri(datadir, "TEMP")
315                 || (tempdir && strstri(datadir, tempdir))) {
316                 (void) strncpy(
317                     interjection_buf[INTERJECT_PANIC],
318                     "\nOne common cause of this error is attempting to "
319                     "execute\n"
320                     "the game by double-clicking on it while it is "
321                     "displayed\n"
322                     "inside an unzip utility.\n\n"
323                     "You have to unzip the contents of the zip file into a\n"
324                     "folder on your system, and then run \"NetHack.exe\" or "
325                     "\n"
326                     "\"NetHackW.exe\" from there.\n\n"
327                     "If that is not the situation, you are encouraged to\n"
328                     "report the error as shown above.\n\n",
329                     1023);
330             }
331         }
332     } break;
333     }
334 }
335 
336 void
interject(interjection_type)337 interject(interjection_type)
338 int interjection_type;
339 {
340     if (interjection_type >= 0 && interjection_type < INTERJECTION_TYPES)
341         msmsg(interjection_buf[interjection_type]);
342 }
343 
344 #ifdef RUNTIME_PASTEBUF_SUPPORT
345 
port_insert_pastebuf(buf)346 void port_insert_pastebuf(buf)
347 char *buf;
348 {
349     /* This implementation will utilize the windows clipboard
350      * to accomplish this.
351      */
352 
353     char *tmp = buf;
354     HGLOBAL hglbCopy;
355     WCHAR *w, w2[2];
356     int cc, rc, abytes;
357     LPWSTR lpwstrCopy;
358     HANDLE hresult;
359 
360     if (!buf)
361         return;
362 
363     cc = strlen(buf);
364     /* last arg=0 means "tell me the size of the buffer that I need" */
365     rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, buf, -1, w2, 0);
366     if (!rc) return;
367 
368     abytes = rc * sizeof(WCHAR);
369     w = (WCHAR *)alloc(abytes);
370     /* Housekeeping need: +free(w) */
371 
372     rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, buf, -1, w, rc);
373     if (!rc) {
374         free(w);
375         return;
376     }
377     if (!OpenClipboard(NULL)) {
378         free(w);
379         return;
380     }
381     /* Housekeeping need: +CloseClipboard(), free(w) */
382 
383     EmptyClipboard();
384 
385     /* allocate global mem obj to hold the text */
386 
387     hglbCopy = GlobalAlloc(GMEM_MOVEABLE, abytes);
388     if (hglbCopy == NULL) {
389         CloseClipboard();
390         free(w);
391         return;
392     }
393     /* Housekeeping need: +GlobalFree(hglbCopy), CloseClipboard(), free(w) */
394 
395     lpwstrCopy = (LPWSTR)GlobalLock(hglbCopy);
396     /* Housekeeping need: +GlobalUnlock(hglbCopy), GlobalFree(hglbCopy),
397                             CloseClipboard(), free(w) */
398 
399     memcpy(lpwstrCopy, w, abytes);
400     GlobalUnlock(hglbCopy);
401     /* Housekeeping need: GlobalFree(hglbCopy), CloseClipboard(), free(w) */
402 
403     /* put it on the clipboard */
404     hresult = SetClipboardData(CF_UNICODETEXT, hglbCopy);
405     if (!hresult) {
406         raw_printf("Error copying to clipboard.\n");
407         GlobalFree(hglbCopy); /* only needed if clipboard didn't accept data */
408     }
409     /* Housekeeping need: CloseClipboard(), free(w) */
410 
411     CloseClipboard();
412     free(w);
413     return;
414 }
415 
416 static HWND
GetConsoleHandle(void)417 GetConsoleHandle(void)
418 {
419     HMODULE hMod = GetModuleHandle("kernel32.dll");
420     GETCONSOLEWINDOW pfnGetConsoleWindow =
421         (GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow");
422     if (pfnGetConsoleWindow)
423         return pfnGetConsoleWindow();
424     else
425         return GetConsoleHwnd();
426 }
427 
428 static HWND
GetConsoleHwnd(void)429 GetConsoleHwnd(void)
430 {
431     int iterations = 0;
432     HWND hwndFound = 0;
433     char OldTitle[1024], NewTitle[1024], TestTitle[1024];
434 
435     /* Get current window title */
436     GetConsoleTitle(OldTitle, sizeof OldTitle);
437 
438     (void) sprintf(NewTitle, "NETHACK%d/%d", GetTickCount(),
439                    GetCurrentProcessId());
440     SetConsoleTitle(NewTitle);
441 
442     GetConsoleTitle(TestTitle, sizeof TestTitle);
443     while (strcmp(TestTitle, NewTitle) != 0) {
444         iterations++;
445         /* sleep(0); */
446         GetConsoleTitle(TestTitle, sizeof TestTitle);
447     }
448     hwndFound = FindWindow(NULL, NewTitle);
449     SetConsoleTitle(OldTitle);
450     /*       printf("%d iterations\n", iterations); */
451     return hwndFound;
452 }
453 
454 #endif
455 
456 #ifdef RUNTIME_PORT_ID
457 /*
458  * _M_IX86 is Defined for x86 processors. This is not defined for x64
459  * processors.
460  * _M_X64  is Defined for x64 processors.
461  * _M_IA64 is Defined for Itanium Processor Family 64-bit processors.
462  * _WIN64  is Defined for applications for Win64.
463  */
464 #ifndef _M_IX86
465 #ifdef _M_X64
466 #define TARGET_PORT "x64"
467 #endif
468 #ifdef _M_IA64
469 #define TARGET_PORT "IA64"
470 #endif
471 #endif
472 
473 #ifndef TARGET_PORT
474 #define TARGET_PORT "x86"
475 #endif
476 
477 char *
get_port_id(buf)478 get_port_id(buf)
479 char *buf;
480 {
481     Strcpy(buf, TARGET_PORT);
482     return buf;
483 }
484 #endif /* RUNTIME_PORT_ID */
485 
486 /* nhassert_failed is called when an nhassert's condition is false */
nhassert_failed(const char * exp,const char * file,int line)487 void nhassert_failed(const char * exp, const char * file, int line)
488 {
489     char message[128];
490     _snprintf(message, sizeof(message),
491                 "NHASSERT(%s) in '%s' at line %d\n", exp, file, line);
492 
493     if (IsDebuggerPresent()) {
494         OutputDebugStringA(message);
495         DebugBreak();
496     }
497 
498     // strip off the newline
499     message[strlen(message) - 1] = '\0';
500     error(message);
501 }
502 
503 void
nethack_exit(code)504 nethack_exit(code)
505 int code;
506 {
507     /* Only if we started from the GUI, not the command prompt,
508      * we need to get one last return, so the score board does
509      * not vanish instantly after being created.
510      * GUILaunched is defined and set in nttty.c.
511      */
512 
513 
514     if (!GUILaunched) {
515         windowprocs = *get_safe_procs(1);
516         /* use our custom version which works
517            a little cleaner than the stdio one */
518         windowprocs.win_nhgetch = windows_console_custom_nhgetch;
519     }
520     if (getreturn_enabled)
521         wait_synch();
522     exit(code);
523 }
524 
525 #undef kbhit
526 #include <conio.h>
527 
528 int
windows_console_custom_nhgetch(VOID_ARGS)529 windows_console_custom_nhgetch(VOID_ARGS)
530 {
531     return _getch();
532 }
533 
534 
535 void
getreturn(str)536 getreturn(str)
537 const char *str;
538 {
539     static boolean in_getreturn = FALSE;
540     char buf[BUFSZ];
541 
542     if (in_getreturn || !getreturn_enabled)
543         return;
544     in_getreturn = TRUE;
545     Sprintf(buf,"Hit <Enter> %s.", str);
546     raw_print(buf);
547     wait_synch();
548     in_getreturn = FALSE;
549     return;
550 }
551 
552 /* nethack_enter_winnt() is called from main immediately after
553    initializing the window port */
nethack_enter_winnt()554 void nethack_enter_winnt()
555 {
556 	if (WINDOWPORT("tty"))
557 		nethack_enter_nttty();
558 }
559 
560 /* CP437 to Unicode mapping according to the Unicode Consortium */
561 const WCHAR cp437[256] = {
562     0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
563     0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C,
564     0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8,
565     0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC,
566     0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
567     0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
568     0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
569     0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
570     0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
571     0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
572     0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
573     0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
574     0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
575     0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
576     0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
577     0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
578     0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
579     0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
580     0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
581     0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
582     0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
583     0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
584     0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
585     0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
586     0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
587     0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
588     0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
589     0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
590     0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
591     0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
592     0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
593     0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
594 };
595 
596 WCHAR *
winos_ascii_to_wide_str(const unsigned char * src,WCHAR * dst,size_t dstLength)597 winos_ascii_to_wide_str(const unsigned char * src, WCHAR * dst, size_t dstLength)
598 {
599     size_t i = 0;
600     while(i < dstLength - 1 && src[i] != 0)
601         dst[i++] = cp437[src[i]];
602     dst[i] = 0;
603     return dst;
604 }
605 
606 WCHAR
winos_ascii_to_wide(const unsigned char c)607 winos_ascii_to_wide(const unsigned char c)
608 {
609     return cp437[c];
610 }
611 
winos_font_support_cp437(HFONT hFont)612 BOOL winos_font_support_cp437(HFONT hFont)
613 {
614     BOOL allFound = FALSE;
615     HDC hdc = GetDC(NULL);
616     HFONT oldFont = SelectObject(hdc, hFont);
617 
618     DWORD size = GetFontUnicodeRanges(hdc, NULL);
619     GLYPHSET *glyphSet = (GLYPHSET *) malloc(size);
620 
621     if (glyphSet != NULL) {
622         GetFontUnicodeRanges(hdc, glyphSet);
623 
624         allFound = TRUE;
625         for (int i = 0; i < 256 && allFound; i++) {
626             WCHAR wc = cp437[i];
627             BOOL found = FALSE;
628             for (DWORD j = 0; j < glyphSet->cRanges && !found; j++) {
629                 WCHAR first = glyphSet->ranges[j].wcLow;
630                 WCHAR last = first + glyphSet->ranges[j].cGlyphs - 1;
631 
632                 if (wc >= first && wc <= last)
633                     found = TRUE;
634             }
635             if (!found)
636                 allFound = FALSE;
637         }
638 
639         free(glyphSet);
640     }
641 
642     SelectObject(hdc, oldFont);
643     ReleaseDC(NULL, hdc);
644 
645     return allFound;
646 }
647 
648 int
windows_early_options(window_opt)649 windows_early_options(window_opt)
650 const char *window_opt;
651 {
652     /*
653      * If you return 2, the game will exit before it begins.
654      * Return 1, to say the option parsed okay.
655      * Return 0, to say the option was bad.
656      */
657 
658     if (match_optname(window_opt, "cursorblink", 5, FALSE)) {
659         win32_cursorblink = TRUE;
660         return 1;
661     } else {
662         raw_printf(
663             "-%swindows:cursorblink is the only supported option.\n");
664     }
665     return 0;
666 }
667 
668 /*
669  * Add a backslash to any name not ending in /, \ or :	 There must
670  * be room for the \
671  */
672 void
append_slash(name)673 append_slash(name)
674 char *name;
675 {
676     char *ptr;
677 
678     if (!*name)
679         return;
680     ptr = name + (strlen(name) - 1);
681     if (*ptr != '\\' && *ptr != '/' && *ptr != ':') {
682         *++ptr = '\\';
683         *++ptr = '\0';
684     }
685     return;
686 }
687 
688 #include <bcrypt.h>     /* Windows Crypto Next Gen (CNG) */
689 
690 #ifndef STATUS_SUCCESS
691 #define STATUS_SUCCESS 0
692 #endif
693 #ifndef STATUS_NOT_FOUND
694 #define STATUS_NOT_FOUND 0xC0000225
695 #endif
696 #ifndef STATUS_UNSUCCESSFUL
697 #define STATUS_UNSUCCESSFUL 0xC0000001
698 #endif
699 
700 unsigned long
sys_random_seed(VOID_ARGS)701 sys_random_seed(VOID_ARGS)
702 {
703     unsigned long ourseed = 0UL;
704     BCRYPT_ALG_HANDLE hRa = (BCRYPT_ALG_HANDLE) 0;
705     NTSTATUS status = STATUS_UNSUCCESSFUL;
706     boolean Plan_B = TRUE;
707 
708     status = BCryptOpenAlgorithmProvider(&hRa, BCRYPT_RNG_ALGORITHM,
709                                          (LPCWSTR) 0, 0);
710     if (hRa && status == STATUS_SUCCESS) {
711         status = BCryptGenRandom(hRa, (PUCHAR) &ourseed,
712                                  (ULONG) sizeof ourseed, 0);
713         if (status == STATUS_SUCCESS) {
714             BCryptCloseAlgorithmProvider(hRa,0);
715             has_strong_rngseed = TRUE;
716             Plan_B = FALSE;
717         }
718     }
719 
720     if (Plan_B) {
721         time_t datetime = 0;
722         const char *emsg;
723 
724         if (status == STATUS_NOT_FOUND)
725             emsg = "BCRYPT_RNG_ALGORITHM not avail, falling back";
726         else
727             emsg = "Other failure than algorithm not avail";
728         paniclog("sys_random_seed", emsg); /* leaves clue, doesn't exit */
729         (void) time(&datetime);
730         ourseed = (unsigned long) datetime;
731     }
732     return ourseed;
733 }
734 
735 #endif /* WIN32 */
736 
737 /*winnt.c*/
738