]> code.delx.au - gnu-emacs/blob - src/w32.c
(nt_stat): Use alloca instead of xmalloc.
[gnu-emacs] / src / w32.c
1 /* Utility and Unix shadow routines for GNU Emacs on Windows NT.
2 Copyright (C) 1994, 1995 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20
21 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
22 */
23
24
25 /* Define stat before including config.h. */
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <malloc.h>
29
30 static int is_toplevel_share_name (char *);
31 static int stat_toplevel_share (char *, void *);
32
33 int
34 nt_stat (char *filename, struct stat *statbuf)
35 {
36 int l = strlen (filename);
37 char *str = NULL;
38
39 /* stat has a bug when passed a name of a directory with a trailing
40 backslash (but a trailing forward slash works fine). */
41 if (filename[l - 1] == '\\')
42 {
43 str = (char *) alloca (l + 1);
44 strcpy (str, filename);
45 str[l - 1] = '/';
46 return stat (str, statbuf);
47 }
48
49 if (stat (filename, statbuf) == 0)
50 return 0;
51 else if (is_toplevel_share_name (filename))
52 return stat_toplevel_share (filename, statbuf);
53 else
54 return -1;
55 }
56
57 /* Place a wrapper around the NT version of ctime. It returns NULL
58 on network directories, so we handle that case here.
59 Define it before including config.h. (Ulrich Leodolter, 1/11/95). */
60 char *
61 nt_ctime (const time_t *t)
62 {
63 char *str = (char *) ctime (t);
64 return (str ? str : "Sun Jan 01 00:00:00 1970");
65 }
66
67 #include <config.h>
68 #include <windows.h>
69 #include <stdlib.h>
70 #include <stdio.h>
71 #include <io.h>
72 #include <fcntl.h>
73 #include <ctype.h>
74
75 #define getwd _getwd
76 #include "lisp.h"
77 #undef getwd
78
79 #include <pwd.h>
80
81 #include "ndir.h"
82 #include "ntheap.h"
83
84 extern int report_file_error (char *, Lisp_Object);
85
86 /* Routines for extending stat above. */
87 static int
88 get_unassigned_drive_letter ()
89 {
90 int i;
91 unsigned int mask;
92
93 mask = GetLogicalDrives ();
94 for (i = 0; i < 26; i++)
95 {
96 if (mask & (1 << i))
97 continue;
98 break;
99 }
100 return (i == 26 ? -1 : 'A' + i);
101 }
102
103 void dostounix_filename (char *);
104
105 /* Return nonzero if NAME is of the form \\host\share (forward slashes
106 also valid), otherwise return 0. */
107 static int
108 is_toplevel_share_name (char *filename)
109 {
110 int len;
111 char *name;
112 char *host;
113 char *share;
114 char *suffix;
115
116 len = strlen (filename);
117 name = alloca (len + 1);
118 strcpy (name, filename);
119
120 dostounix_filename (name);
121 if (name[0] != '/' || name[1] != '/')
122 return 0;
123
124 host = strtok (&name[2], "/");
125 share = strtok (NULL, "/");
126 suffix = strtok (NULL, "/");
127 if (!host || !share || suffix)
128 return 0;
129
130 return 1;
131 }
132
133
134 /* FILENAME is of the form \\host\share, and stat can't handle names
135 of this form. But stat can handle \\host\share if it's been
136 assigned a drive letter. So we create a network connection to this
137 share, assign it a drive letter, stat the drive letter, and
138 disconnect from the share. Hassle... */
139 static int
140 stat_toplevel_share (char *filename, void *statbuf)
141 {
142 NETRESOURCE net;
143 int drive_letter;
144 char drive[4];
145 int result;
146
147 drive_letter = get_unassigned_drive_letter ();
148 if (drive_letter < 0)
149 return -1;
150
151 drive[0] = drive_letter;
152 drive[1] = ':';
153 drive[2] = '\0';
154 net.dwType = RESOURCETYPE_DISK;
155 net.lpLocalName = drive;
156 net.lpRemoteName = filename;
157 net.lpProvider = NULL;
158
159 switch (WNetAddConnection2 (&net, NULL, NULL, 0))
160 {
161 case NO_ERROR:
162 break;
163 case ERROR_ALREADY_ASSIGNED:
164 default:
165 return -1;
166 }
167
168 /* Name the toplevel directory on the drive letter. */
169 drive[2] = '/';
170 drive[3] = '\0';
171 result = stat (drive, (void *) statbuf);
172
173 /* Strip the slash so we can disconnect. */
174 drive[2] = '\0';
175 if (WNetCancelConnection2 (drive, 0, TRUE) != NO_ERROR)
176 result = -1;
177
178 return result;
179 }
180
181
182 /* Get the current working directory. */
183 int
184 getwd (char *dir)
185 {
186 return GetCurrentDirectory (MAXPATHLEN, dir);
187 }
188
189 /* Emulate gethostname. */
190 int
191 gethostname (char *buffer, int size)
192 {
193 /* NT only allows small host names, so the buffer is
194 certainly large enough. */
195 return !GetComputerName (buffer, &size);
196 }
197
198 /* Emulate getloadavg. */
199 int
200 getloadavg (double loadavg[], int nelem)
201 {
202 int i;
203
204 /* A faithful emulation is going to have to be saved for a rainy day. */
205 for (i = 0; i < nelem; i++)
206 {
207 loadavg[i] = 0.0;
208 }
209 return i;
210 }
211
212 /* Emulate sleep...we could have done this with a define, but that
213 would necessitate including windows.h in the files that used it.
214 This is much easier. */
215 void
216 nt_sleep (int seconds)
217 {
218 Sleep (seconds * 1000);
219 }
220
221 /* Emulate the Unix directory procedures opendir, closedir,
222 and readdir. We can't use the procedures supplied in sysdep.c,
223 so we provide them here. */
224
225 struct direct dir_static; /* simulated directory contents */
226 static int dir_finding;
227 static HANDLE dir_find_handle;
228
229 DIR *
230 opendir (char *filename)
231 {
232 DIR *dirp;
233
234 /* Opening is done by FindFirstFile. However, a read is inherent to
235 this operation, so we have a flag to handle the open at read
236 time. This flag essentially means "there is a find-handle open and
237 it needs to be closed." */
238
239 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
240 {
241 return 0;
242 }
243
244 dirp->dd_fd = 0;
245 dirp->dd_loc = 0;
246 dirp->dd_size = 0;
247
248 /* This is tacky, but we need the directory name for our
249 implementation of readdir. */
250 strncpy (dirp->dd_buf, filename, DIRBLKSIZ);
251 return dirp;
252 }
253
254 void
255 closedir (DIR *dirp)
256 {
257 /* If we have a find-handle open, close it. */
258 if (dir_finding)
259 {
260 FindClose (dir_find_handle);
261 dir_finding = 0;
262 }
263 xfree ((char *) dirp);
264 }
265
266 struct direct *
267 readdir (DIR *dirp)
268 {
269 WIN32_FIND_DATA find_data;
270
271 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
272 if (!dir_finding)
273 {
274 char filename[MAXNAMLEN + 3];
275 int ln;
276
277 strncpy (filename, dirp->dd_buf, MAXNAMLEN);
278 ln = strlen (filename)-1;
279 if (!IS_ANY_SEP (filename[ln]))
280 strcat (filename, "\\");
281 strcat (filename, "*.*");
282
283 dir_find_handle = FindFirstFile (filename, &find_data);
284
285 if (dir_find_handle == INVALID_HANDLE_VALUE)
286 return NULL;
287
288 dir_finding = 1;
289 }
290 else
291 {
292 if (!FindNextFile (dir_find_handle, &find_data))
293 return NULL;
294 }
295
296 /* NT's unique ID for a file is 64 bits, so we have to fake it here.
297 This should work as long as we never use 0. */
298 dir_static.d_ino = 1;
299
300 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
301 dir_static.d_namlen - dir_static.d_namlen % 4;
302
303 dir_static.d_namlen = strlen (find_data.cFileName);
304 strncpy (dir_static.d_name, find_data.cFileName, MAXNAMLEN);
305
306 return &dir_static;
307 }
308
309 /* Emulate getpwuid and getpwnam. */
310
311 int getuid (); /* forward declaration */
312
313 #define PASSWD_FIELD_SIZE 256
314
315 static char the_passwd_name[PASSWD_FIELD_SIZE];
316 static char the_passwd_passwd[PASSWD_FIELD_SIZE];
317 static char the_passwd_gecos[PASSWD_FIELD_SIZE];
318 static char the_passwd_dir[PASSWD_FIELD_SIZE];
319 static char the_passwd_shell[PASSWD_FIELD_SIZE];
320
321 static struct passwd the_passwd =
322 {
323 the_passwd_name,
324 the_passwd_passwd,
325 0,
326 0,
327 0,
328 the_passwd_gecos,
329 the_passwd_dir,
330 the_passwd_shell,
331 };
332
333 struct passwd *
334 getpwuid (int uid)
335 {
336 int size = PASSWD_FIELD_SIZE;
337
338 if (!GetUserName (the_passwd.pw_name, &size))
339 return NULL;
340
341 the_passwd.pw_passwd[0] = '\0';
342 the_passwd.pw_uid = 0;
343 the_passwd.pw_gid = 0;
344 strcpy (the_passwd.pw_gecos, the_passwd.pw_name);
345 the_passwd.pw_dir[0] = '\0';
346 the_passwd.pw_shell[0] = '\0';
347
348 return &the_passwd;
349 }
350
351 struct passwd *
352 getpwnam (char *name)
353 {
354 struct passwd *pw;
355
356 pw = getpwuid (getuid ());
357 if (!pw)
358 return pw;
359
360 if (strcmp (name, pw->pw_name))
361 return NULL;
362
363 return pw;
364 }
365
366
367 /* We don't have scripts to automatically determine the system configuration
368 for Emacs before it's compiled, and we don't want to have to make the
369 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
370 routine. */
371
372 static char configuration_buffer[32];
373
374 char *
375 get_emacs_configuration (void)
376 {
377 char *arch, *oem, *os;
378
379 /* Determine the processor type. */
380 switch (get_processor_type ())
381 {
382
383 #ifdef PROCESSOR_INTEL_386
384 case PROCESSOR_INTEL_386:
385 case PROCESSOR_INTEL_486:
386 case PROCESSOR_INTEL_PENTIUM:
387 arch = "i386";
388 break;
389 #endif
390
391 #ifdef PROCESSOR_INTEL_860
392 case PROCESSOR_INTEL_860:
393 arch = "i860";
394 break;
395 #endif
396
397 #ifdef PROCESSOR_MIPS_R2000
398 case PROCESSOR_MIPS_R2000:
399 case PROCESSOR_MIPS_R3000:
400 case PROCESSOR_MIPS_R4000:
401 arch = "mips";
402 break;
403 #endif
404
405 #ifdef PROCESSOR_ALPHA_21064
406 case PROCESSOR_ALPHA_21064:
407 arch = "alpha";
408 break;
409 #endif
410
411 default:
412 arch = "unknown";
413 break;
414 }
415
416 /* Let oem be "*" until we figure out how to decode the OEM field. */
417 oem = "*";
418
419 #ifdef WINDOWS95
420 os = "win";
421 #else
422 os = "nt";
423 #endif
424
425 sprintf (configuration_buffer, "%s-%s-%s%d.%d", arch, oem, os,
426 get_nt_major_version (), get_nt_minor_version ());
427 return configuration_buffer;
428 }
429
430 /* Conjure up inode and device numbers that will serve the purpose
431 of Emacs. Return 1 upon success, 0 upon failure. */
432 int
433 get_inode_and_device_vals (Lisp_Object filename, Lisp_Object *p_inode,
434 Lisp_Object *p_device)
435 {
436 /* File uids on NT are found using a handle to a file, which
437 implies that it has been opened. Since we want to be able
438 to stat an arbitrary file, we must open it, get the info,
439 and then close it.
440
441 Also, NT file uids are 64-bits. This is a problem. */
442
443 HANDLE handle;
444 BOOL result;
445 DWORD attrs;
446 BY_HANDLE_FILE_INFORMATION info;
447
448 /* We have to stat files and directories differently, so check
449 to see what filename references. */
450 attrs = GetFileAttributes (XSTRING (filename)->data);
451 if (attrs == 0xFFFFFFFF) {
452 return 0;
453 }
454 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
455 /* Conjure up bogus, but unique, values. */
456 attrs = GetTickCount ();
457 *p_inode = make_number (attrs);
458 *p_device = make_number (attrs);
459 return 1;
460 }
461
462 /* FIXME: It shouldn't be opened without READ access, but NT on x86
463 doesn't allow GetFileInfo in that case (NT on mips does). */
464
465 handle = CreateFile (XSTRING (filename)->data,
466 GENERIC_READ,
467 FILE_SHARE_READ | FILE_SHARE_WRITE,
468 NULL,
469 OPEN_EXISTING,
470 FILE_ATTRIBUTE_NORMAL,
471 NULL);
472 if (handle == INVALID_HANDLE_VALUE)
473 return 0;
474
475 result = GetFileInformationByHandle (handle, &info);
476 CloseHandle (handle);
477 if (!result)
478 return 0;
479
480 *p_inode = make_number (info.nFileIndexLow); /* use the low value */
481 *p_device = make_number (info.dwVolumeSerialNumber);
482
483 return 1;
484 }
485
486 /* The following pipe routines are used to support our fork emulation.
487 Since NT's crt dup always creates inherited handles, we
488 must be careful in setting up pipes. First create
489 non-inherited pipe handles, then create an inherited handle
490 to the write end by dup-ing it, and then close the non-inherited
491 end that was just duped. This gives us one non-inherited handle
492 on the read end and one inherited handle to the write end. As
493 the parent, we close the inherited handle to the write end after
494 spawning the child. */
495
496 /* From callproc.c */
497 extern Lisp_Object Vbinary_process_input;
498 extern Lisp_Object Vbinary_process_output;
499
500 void
501 pipe_with_inherited_out (int fds[2])
502 {
503 int inherit_out;
504 unsigned int flags = _O_NOINHERIT;
505
506 if (!NILP (Vbinary_process_output))
507 flags |= _O_BINARY;
508
509 _pipe (fds, 0, flags);
510 inherit_out = dup (fds[1]);
511 close (fds[1]);
512 fds[1] = inherit_out;
513 }
514
515 void
516 pipe_with_inherited_in (int fds[2])
517 {
518 int inherit_in;
519 unsigned int flags = _O_NOINHERIT;
520
521 if (!NILP (Vbinary_process_input))
522 flags |= _O_BINARY;
523
524 _pipe (fds, 0, flags);
525 inherit_in = dup (fds[0]);
526 close (fds[0]);
527 fds[0] = inherit_in;
528 }
529
530 /* The following two routines are used to manipulate stdin, stdout, and
531 stderr of our child processes.
532
533 Assuming that in, out, and err are inherited, we make them stdin,
534 stdout, and stderr of the child as follows:
535
536 - Save the parent's current standard handles.
537 - Set the parent's standard handles to the handles being passed in.
538 (Note that _get_osfhandle is an io.h procedure that
539 maps crt file descriptors to NT file handles.)
540 - Spawn the child, which inherits in, out, and err as stdin,
541 stdout, and stderr. (see Spawnve)
542 - Reset the parent's standard handles to the saved handles.
543 (see reset_standard_handles)
544 We assume that the caller closes in, out, and err after calling us. */
545
546 void
547 prepare_standard_handles (int in, int out, int err, HANDLE handles[4])
548 {
549 HANDLE parent, stdin_save, stdout_save, stderr_save, err_handle;
550
551 #ifdef WINDOWS95
552 /* The Win95 beta doesn't set the standard handles correctly.
553 Handicap subprocesses until we get a version that works correctly.
554 Undefining the subprocesses macro reveals other incompatibilities,
555 so, since we're expecting subprocs to work in the near future,
556 disable them here. */
557 report_file_error ("Subprocesses currently disabled on Win95", Qnil);
558 #endif
559
560 parent = GetCurrentProcess ();
561 stdin_save = GetStdHandle (STD_INPUT_HANDLE);
562 stdout_save = GetStdHandle (STD_OUTPUT_HANDLE);
563 stderr_save = GetStdHandle (STD_ERROR_HANDLE);
564
565 #ifndef HAVE_NTGUI
566 if (!DuplicateHandle (parent,
567 GetStdHandle (STD_INPUT_HANDLE),
568 parent,
569 &stdin_save,
570 0,
571 FALSE,
572 DUPLICATE_SAME_ACCESS))
573 report_file_error ("Duplicating parent's input handle", Qnil);
574
575 if (!DuplicateHandle (parent,
576 GetStdHandle (STD_OUTPUT_HANDLE),
577 parent,
578 &stdout_save,
579 0,
580 FALSE,
581 DUPLICATE_SAME_ACCESS))
582 report_file_error ("Duplicating parent's output handle", Qnil);
583
584 if (!DuplicateHandle (parent,
585 GetStdHandle (STD_ERROR_HANDLE),
586 parent,
587 &stderr_save,
588 0,
589 FALSE,
590 DUPLICATE_SAME_ACCESS))
591 report_file_error ("Duplicating parent's error handle", Qnil);
592 #endif /* !HAVE_NTGUI */
593
594 if (!SetStdHandle (STD_INPUT_HANDLE, (HANDLE) _get_osfhandle (in)))
595 report_file_error ("Changing stdin handle", Qnil);
596
597 if (!SetStdHandle (STD_OUTPUT_HANDLE, (HANDLE) _get_osfhandle (out)))
598 report_file_error ("Changing stdout handle", Qnil);
599
600 /* We lose data if we use the same handle to the pipe for stdout and
601 stderr, so make a duplicate. This took a while to find. */
602 if (out == err)
603 {
604 if (!DuplicateHandle (parent,
605 (HANDLE) _get_osfhandle (err),
606 parent,
607 &err_handle,
608 0,
609 TRUE,
610 DUPLICATE_SAME_ACCESS))
611 report_file_error ("Duplicating out handle to make err handle.",
612 Qnil);
613 }
614 else
615 {
616 err_handle = (HANDLE) _get_osfhandle (err);
617 }
618
619 if (!SetStdHandle (STD_ERROR_HANDLE, err_handle))
620 report_file_error ("Changing stderr handle", Qnil);
621
622 handles[0] = stdin_save;
623 handles[1] = stdout_save;
624 handles[2] = stderr_save;
625 handles[3] = err_handle;
626 }
627
628 void
629 reset_standard_handles (int in, int out, int err, HANDLE handles[4])
630 {
631 HANDLE stdin_save = handles[0];
632 HANDLE stdout_save = handles[1];
633 HANDLE stderr_save = handles[2];
634 HANDLE err_handle = handles[3];
635 int i;
636
637 #ifndef HAVE_NTGUI
638 if (!SetStdHandle (STD_INPUT_HANDLE, stdin_save))
639 report_file_error ("Resetting input handle", Qnil);
640
641 if (!SetStdHandle (STD_OUTPUT_HANDLE, stdout_save))
642 {
643 i = GetLastError ();
644 report_file_error ("Resetting output handle", Qnil);
645 }
646
647 if (!SetStdHandle (STD_ERROR_HANDLE, stderr_save))
648 report_file_error ("Resetting error handle", Qnil);
649 #endif /* !HAVE_NTGUI */
650
651 if (out == err)
652 {
653 /* If out and err are the same handle, then we duplicated out
654 and stuck it in err_handle. Close the duplicate to clean up. */
655 if (!CloseHandle (err_handle))
656 report_file_error ("Closing error handle duplicated from out.",
657 Qnil);
658 }
659 }
660
661 int
662 random ()
663 {
664 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
665 return ((rand () << 15) | rand ());
666 }
667
668 void
669 srandom (int seed)
670 {
671 srand (seed);
672 }
673
674 /* Destructively turn backslashes into slashes. */
675 void
676 dostounix_filename (p)
677 register char *p;
678 {
679 while (*p)
680 {
681 if (*p == '\\')
682 *p = '/';
683 p++;
684 }
685 }
686
687 /* Routines that are no-ops on NT but are defined to get Emacs to compile. */
688
689
690 int
691 sigsetmask (int signal_mask)
692 {
693 return 0;
694 }
695
696 int
697 sigblock (int sig)
698 {
699 return 0;
700 }
701
702 int
703 kill (int pid, int signal)
704 {
705 return 0;
706 }
707
708 int
709 setpgrp (int pid, int gid)
710 {
711 return 0;
712 }
713
714 int
715 alarm (int seconds)
716 {
717 return 0;
718 }
719
720 int
721 unrequest_sigio (void)
722 {
723 return 0;
724 }
725
726 int
727 request_sigio (void)
728 {
729 return 0;
730 }
731
732 int
733 getuid ()
734 {
735 char buffer[256];
736 int size = 256;
737
738 if (!GetUserName (buffer, &size))
739 /* Assume all powers upon failure. */
740 return 0;
741
742 if (!stricmp ("administrator", buffer))
743 return 0;
744 else
745 /* A complete fabrication...is there anything to base it on? */
746 return 123;
747 }
748
749 int
750 geteuid ()
751 {
752 /* I could imagine arguing for checking to see whether the user is
753 in the Administrators group and returning a UID of 0 for that
754 case, but I don't know how wise that would be in the long run. */
755 return getuid ();
756 }
757
758 /* Remove all CR's that are followed by a LF.
759 (From msdos.c...probably should figure out a way to share it,
760 although this code isn't going to ever change.) */
761 int
762 crlf_to_lf (n, buf)
763 register int n;
764 register unsigned char *buf;
765 {
766 unsigned char *np = buf;
767 unsigned char *startp = buf;
768 unsigned char *endp = buf + n;
769
770 if (n == 0)
771 return n;
772 while (buf < endp - 1)
773 {
774 if (*buf == 0x0d)
775 {
776 if (*(++buf) != 0x0a)
777 *np++ = 0x0d;
778 }
779 else
780 *np++ = *buf++;
781 }
782 if (buf < endp)
783 *np++ = *buf++;
784 return np - startp;
785 }
786
787 #define REG_ROOT "SOFTWARE\\GNU\\Emacs\\"
788
789 LPBYTE
790 nt_get_resource (key, lpdwtype)
791 char *key;
792 LPDWORD lpdwtype;
793 {
794 LPBYTE lpvalue;
795 HKEY hrootkey = NULL;
796 DWORD cbData;
797 BOOL ok = FALSE;
798
799 /* Check both the current user and the local machine to see if
800 we have any resources. */
801
802 if (RegOpenKeyEx (HKEY_CURRENT_USER, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
803 {
804 lpvalue = NULL;
805
806 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS
807 && (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL
808 && RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
809 {
810 return (lpvalue);
811 }
812
813 if (lpvalue) xfree (lpvalue);
814
815 RegCloseKey (hrootkey);
816 }
817
818 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_ROOT, 0, KEY_READ, &hrootkey) == ERROR_SUCCESS)
819 {
820 lpvalue = NULL;
821
822 if (RegQueryValueEx (hrootkey, key, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS &&
823 (lpvalue = (LPBYTE) xmalloc (cbData)) != NULL &&
824 RegQueryValueEx (hrootkey, key, NULL, lpdwtype, lpvalue, &cbData) == ERROR_SUCCESS)
825 {
826 return (lpvalue);
827 }
828
829 if (lpvalue) xfree (lpvalue);
830
831 RegCloseKey (hrootkey);
832 }
833
834 return (NULL);
835 }
836
837 void
838 init_environment ()
839 {
840 /* Open a console window to display messages during dumping. */
841 if (!initialized)
842 AllocConsole ();
843
844 /* Check for environment variables and use registry if they don't exist */
845 {
846 int i;
847 LPBYTE lpval;
848 DWORD dwType;
849
850 static char * env_vars[] =
851 {
852 "emacs_path",
853 "EMACSLOADPATH",
854 "SHELL",
855 "EMACSDATA",
856 "EMACSPATH",
857 "EMACSLOCKDIR",
858 "INFOPATH",
859 "EMACSDOC",
860 "TERM",
861 };
862
863 for (i = 0; i < (sizeof (env_vars) / sizeof (env_vars[0])); i++)
864 {
865 if (!getenv (env_vars[i]) &&
866 (lpval = nt_get_resource (env_vars[i], &dwType)) != NULL)
867 {
868 if (dwType == REG_EXPAND_SZ)
869 {
870 char buf1[500], buf2[500];
871
872 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, 500);
873 _snprintf (buf2, 499, "%s=%s", env_vars[i], buf1);
874 putenv (strdup (buf2));
875 }
876 else if (dwType == REG_SZ)
877 {
878 char buf[500];
879
880 _snprintf (buf, 499, "%s=%s", env_vars[i], lpval);
881 putenv (strdup (buf));
882 }
883
884 xfree (lpval);
885 }
886 }
887 }
888 }
889
890 #ifdef HAVE_TIMEVAL
891 #include <sys/timeb.h>
892
893 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
894 void
895 gettimeofday (struct timeval *tv, struct timezone *tz)
896 {
897 struct _timeb tb;
898 _ftime (&tb);
899
900 tv->tv_sec = tb.time;
901 tv->tv_usec = tb.millitm * 1000L;
902 if (tz)
903 {
904 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
905 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
906 }
907 }
908 #endif /* HAVE_TIMEVAL */
909
910
911 #ifdef PIGSFLY
912 Keep this around...we might need it later.
913 #ifdef WINDOWSNT
914 {
915 /*
916 * Find the user's real name by opening the process token and looking
917 * up the name associated with the user-sid in that token.
918 */
919
920 char b[256], Name[256], RefD[256];
921 DWORD length = 256, rlength = 256, trash;
922 HANDLE Token;
923 SID_NAME_USE User;
924
925 if (1)
926 Vuser_real_login_name = build_string ("foo");
927 else if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &Token))
928 {
929 Vuser_real_login_name = build_string ("unknown");
930 }
931 else if (!GetTokenInformation (Token, TokenUser, (PVOID)b, 256,
932 &trash))
933 {
934 CloseHandle (Token);
935 Vuser_real_login_name = build_string ("unknown");
936 }
937 else if (!LookupAccountSid ((void *)0, (PSID)b, Name, &length, RefD,
938 &rlength, &User))
939 {
940 CloseHandle (Token);
941 Vuser_real_login_name = build_string ("unknown");
942 }
943 else
944 Vuser_real_login_name = build_string (Name);
945 }
946 #else /* not WINDOWSNT */
947 #endif /* not WINDOWSNT */
948 #endif /* PIGSFLY */