(LIBS): Use BASE_LIBS and ADVAPI32.
[bpt/emacs.git] / src / w32.c
CommitLineData
95ed0025 1/* Utility and Unix shadow routines for GNU Emacs on Windows NT.
35f0d482 2 Copyright (C) 1994, 1995 Free Software Foundation, Inc.
95ed0025
RS
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
35f0d482 8 Free Software Foundation; either version 2, or (at your option) any later
95ed0025
RS
9 version.
10
11 GNU Emacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
15
16 You should have received a copy of the GNU General Public License along
17 with GNU Emacs; see the file COPYING. If not, write to the Free Software
18 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 Geoff Voelker (voelker@cs.washington.edu) 7-29-94
21*/
22
35f0d482
KH
23/* Define stat before including config.h. */
24#include <string.h>
25#include <sys/stat.h>
26int
27nt_stat (char *filename, struct stat *statbuf)
28{
29 int r, l = strlen (filename);
30 char *str = NULL;
31 extern long *xmalloc ();
32 extern void xfree ();
33
34 /* stat has a bug when passed a name of a directory with a trailing
35 backslash (but a trailing forward slash works fine). */
36 if (filename[l - 1] == '\\')
37 {
38 str = (char *) xmalloc (l + 1);
39 strcpy (str, filename);
40 str[l - 1] = '/';
41 r = stat (str, statbuf);
42 xfree (str);
43 return r;
44 }
45 else
46 return stat (filename, statbuf);
47}
48
49/* Place a wrapper around the NT version of ctime. It returns NULL
50 on network directories, so we handle that case here.
51 Define it before including config.h. (Ulrich Leodolter, 1/11/95). */
52char *
53nt_ctime (const time_t *t)
54{
55 char *str = (char *) ctime (t);
56 return (str ? str : "Sun Jan 01 00:00:00 1970");
57}
58
95ed0025
RS
59#include <windows.h>
60#include <stdlib.h>
61#include <stdio.h>
62#include <io.h>
63#include <fcntl.h>
64#include <ctype.h>
65
66#include "config.h"
67#define getwd _getwd
68#include "lisp.h"
69#undef getwd
70
71#include <pwd.h>
72
73#include "ndir.h"
74#include "ntheap.h"
75
76extern int report_file_error (char *, Lisp_Object);
77
78/* Get the current working directory. */
79int
80getwd (char *dir)
81{
82 return GetCurrentDirectory (MAXPATHLEN, dir);
83}
84
85/* Emulate gethostname. */
86int
87gethostname (char *buffer, int size)
88{
89 /* NT only allows small host names, so the buffer is
90 certainly large enough. */
91 return !GetComputerName (buffer, &size);
92}
93
94/* Emulate getloadavg. */
95int
96getloadavg (double loadavg[], int nelem)
97{
98 int i;
99
100 /* A faithful emulation is going to have to be saved for a rainy day. */
101 for (i = 0; i < nelem; i++)
102 {
103 loadavg[i] = 0.0;
104 }
105 return i;
106}
107
108/* Emulate sleep...we could have done this with a define, but that
109 would necessitate including windows.h in the files that used it.
110 This is much easier. */
111void
112nt_sleep (int seconds)
113{
114 Sleep (seconds * 1000);
115}
116
117/* Emulate the Unix directory procedures opendir, closedir,
118 and readdir. We can't use the procedures supplied in sysdep.c,
119 so we provide them here. */
120
121struct direct dir_static; /* simulated directory contents */
122static int dir_finding;
123static HANDLE dir_find_handle;
124
125DIR *
126opendir (char *filename)
127{
128 DIR *dirp;
129
130 /* Opening is done by FindFirstFile. However, a read is inherent to
131 this operation, so we have a flag to handle the open at read
132 time. This flag essentially means "there is a find-handle open and
133 it needs to be closed." */
134
135 if (!(dirp = (DIR *) malloc (sizeof (DIR))))
136 {
137 return 0;
138 }
139
140 dirp->dd_fd = 0;
141 dirp->dd_loc = 0;
142 dirp->dd_size = 0;
143
144 /* This is tacky, but we need the directory name for our
145 implementation of readdir. */
146 strncpy (dirp->dd_buf, filename, DIRBLKSIZ);
147 return dirp;
148}
149
150void
151closedir (DIR *dirp)
152{
153 /* If we have a find-handle open, close it. */
154 if (dir_finding)
155 {
156 FindClose (dir_find_handle);
157 dir_finding = 0;
158 }
159 xfree ((char *) dirp);
160}
161
162struct direct *
163readdir (DIR *dirp)
164{
165 WIN32_FIND_DATA find_data;
166
167 /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
168 if (!dir_finding)
169 {
170 char filename[MAXNAMLEN + 3];
171 int ln;
172
173 strncpy (filename, dirp->dd_buf, MAXNAMLEN);
174 ln = strlen (filename)-1;
175 if (filename[ln] != '\\' && filename[ln] != ':')
176 strcat (filename, "\\");
177 strcat (filename, "*.*");
178
179 dir_find_handle = FindFirstFile (filename, &find_data);
180
181 if (dir_find_handle == INVALID_HANDLE_VALUE)
182 return NULL;
183
184 dir_finding = 1;
185 }
186 else
187 {
188 if (!FindNextFile (dir_find_handle, &find_data))
189 return NULL;
190 }
191
95ed0025
RS
192 /* NT's unique ID for a file is 64 bits, so we have to fake it here.
193 This should work as long as we never use 0. */
194 dir_static.d_ino = 1;
195
196 dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
197 dir_static.d_namlen - dir_static.d_namlen % 4;
198
199 dir_static.d_namlen = strlen (find_data.cFileName);
200 strncpy (dir_static.d_name, find_data.cFileName, MAXNAMLEN);
201
202 return &dir_static;
203}
204
205/* Emulate getpwuid and getpwnam. */
206
207int getuid (); /* forward declaration */
208
209static char the_passwd_name[256];
210static char the_passwd_passwd[256];
211static char the_passwd_gecos[256];
212static char the_passwd_dir[256];
213static char the_passwd_shell[256];
214
215static struct passwd the_passwd =
216{
217 the_passwd_name,
218 the_passwd_passwd,
219 0,
220 0,
221 0,
222 the_passwd_gecos,
223 the_passwd_dir,
224 the_passwd_shell,
225};
226
227struct passwd *
228getpwuid (int uid)
229{
230 int size = 256;
231
232 if (!GetUserName (the_passwd.pw_name, &size))
233 return NULL;
234
235 the_passwd.pw_passwd[0] = '\0';
236 the_passwd.pw_uid = 0;
237 the_passwd.pw_gid = 0;
238 strcpy (the_passwd.pw_gecos, the_passwd.pw_name);
239 the_passwd.pw_dir[0] = '\0';
240 the_passwd.pw_shell[0] = '\0';
241
242 return &the_passwd;
243}
244
245struct passwd *
246getpwnam (char *name)
247{
248 struct passwd *pw;
249
250 pw = getpwuid (getuid ());
251 if (!pw)
252 return pw;
253
254 if (strcmp (name, pw->pw_name))
255 return NULL;
256
257 return pw;
258}
259
260
261/* We don't have scripts to automatically determine the system configuration
262 for Emacs before it's compiled, and we don't want to have to make the
263 user enter it, so we define EMACS_CONFIGURATION to invoke this runtime
264 routine. */
265
266static char configuration_buffer[16];
267
268char *
269get_emacs_configuration (void)
270{
271 char *arch, *oem;
272
273 /* Determine the processor type. */
274 switch (get_processor_type ())
275 {
276 case PROCESSOR_INTEL_386:
277 case PROCESSOR_INTEL_486:
278 case PROCESSOR_INTEL_PENTIUM:
279 arch = "i386";
280 break;
281 case PROCESSOR_INTEL_860:
282 arch = "i860";
283 break;
284 case PROCESSOR_MIPS_R2000:
285 case PROCESSOR_MIPS_R3000:
286 case PROCESSOR_MIPS_R4000:
287 arch = "mips";
288 break;
289 case PROCESSOR_ALPHA_21064:
290 arch = "alpha";
291 break;
292 default:
293 arch = "unknown";
294 break;
295 }
296
297 /* Let oem be "*" until we figure out how to decode the OEM field. */
298 oem = "*";
299
300 sprintf (configuration_buffer, "%s-%s-nt%d.%d", arch, oem,
301 get_nt_major_version (), get_nt_minor_version ());
302 return configuration_buffer;
303}
304
305/* Conjure up inode and device numbers that will serve the purpose
306 of Emacs. Return 1 upon success, 0 upon failure. */
307int
308get_inode_and_device_vals (Lisp_Object filename, Lisp_Object *p_inode,
309 Lisp_Object *p_device)
310{
311 /* File uids on NT are found using a handle to a file, which
312 implies that it has been opened. Since we want to be able
313 to stat an arbitrary file, we must open it, get the info,
314 and then close it.
315
316 Also, NT file uids are 64-bits. This is a problem. */
317
318 HANDLE handle;
319 BOOL result;
35f0d482 320 DWORD attrs;
95ed0025
RS
321 BY_HANDLE_FILE_INFORMATION info;
322
35f0d482
KH
323 /* We have to stat files and directories differently, so check
324 to see what filename references. */
325 attrs = GetFileAttributes (XSTRING (filename)->data);
326 if (attrs == 0xFFFFFFFF) {
327 return 0;
328 }
329 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
330 /* Conjure up bogus, but unique, values. */
331 attrs = GetTickCount ();
332 *p_inode = make_number (attrs);
333 *p_device = make_number (attrs);
334 return 1;
335 }
336
95ed0025
RS
337 /* FIXME: It shouldn't be opened without READ access, but NT on x86
338 doesn't allow GetFileInfo in that case (NT on mips does). */
339
340 handle = CreateFile (XSTRING (filename)->data,
341 GENERIC_READ,
342 FILE_SHARE_READ | FILE_SHARE_WRITE,
343 NULL,
344 OPEN_EXISTING,
345 FILE_ATTRIBUTE_NORMAL,
346 NULL);
347 if (handle == INVALID_HANDLE_VALUE)
348 return 0;
349
350 result = GetFileInformationByHandle (handle, &info);
351 CloseHandle (handle);
352 if (!result)
353 return 0;
354
355 *p_inode = make_number (info.nFileIndexLow); /* use the low value */
356 *p_device = make_number (info.dwVolumeSerialNumber);
357
358 return 1;
359}
360
361/* The following pipe routines are used to support our fork emulation.
362 Since NT's crt dup always creates inherited handles, we
363 must be careful in setting up pipes. First create
364 non-inherited pipe handles, then create an inherited handle
365 to the write end by dup-ing it, and then close the non-inherited
366 end that was just duped. This gives us one non-inherited handle
367 on the read end and one inherited handle to the write end. As
368 the parent, we close the inherited handle to the write end after
369 spawning the child. */
370
371/* From callproc.c */
372extern Lisp_Object Vbinary_process_input;
373extern Lisp_Object Vbinary_process_output;
374
375void
376pipe_with_inherited_out (int fds[2])
377{
378 int inherit_out;
379 unsigned int flags = _O_NOINHERIT;
380
381 if (!NILP (Vbinary_process_output))
382 flags |= _O_BINARY;
383
384 _pipe (fds, 0, flags);
385 inherit_out = dup (fds[1]);
386 close (fds[1]);
387 fds[1] = inherit_out;
388}
389
390void
391pipe_with_inherited_in (int fds[2])
392{
393 int inherit_in;
394 unsigned int flags = _O_NOINHERIT;
395
396 if (!NILP (Vbinary_process_input))
397 flags |= _O_BINARY;
398
399 _pipe (fds, 0, flags);
400 inherit_in = dup (fds[0]);
401 close (fds[0]);
402 fds[0] = inherit_in;
403}
404
405/* The following two routines are used to manipulate stdin, stdout, and
406 stderr of our child processes.
407
408 Assuming that in, out, and err are inherited, we make them stdin,
409 stdout, and stderr of the child as follows:
410
411 - Save the parent's current standard handles.
412 - Set the parent's standard handles to the handles being passed in.
413 (Note that _get_osfhandle is an io.h procedure that
414 maps crt file descriptors to NT file handles.)
415 - Spawn the child, which inherits in, out, and err as stdin,
416 stdout, and stderr. (see Spawnve)
417 - Reset the parent's standard handles to the saved handles.
418 (see reset_standard_handles)
419 We assume that the caller closes in, out, and err after calling us. */
420
421void
422prepare_standard_handles (int in, int out, int err, HANDLE handles[4])
423{
424 HANDLE parent, stdin_save, stdout_save, stderr_save, err_handle;
425
426 parent = GetCurrentProcess ();
427 if (!DuplicateHandle (parent,
428 GetStdHandle (STD_INPUT_HANDLE),
429 parent,
430 &stdin_save,
431 0,
432 FALSE,
433 DUPLICATE_SAME_ACCESS))
434 report_file_error ("Duplicating parent's input handle", Qnil);
435
436 if (!DuplicateHandle (parent,
437 GetStdHandle (STD_OUTPUT_HANDLE),
438 parent,
439 &stdout_save,
440 0,
441 FALSE,
442 DUPLICATE_SAME_ACCESS))
443 report_file_error ("Duplicating parent's output handle", Qnil);
444
445 if (!DuplicateHandle (parent,
446 GetStdHandle (STD_ERROR_HANDLE),
447 parent,
448 &stderr_save,
449 0,
450 FALSE,
451 DUPLICATE_SAME_ACCESS))
452 report_file_error ("Duplicating parent's error handle", Qnil);
453
454 if (!SetStdHandle (STD_INPUT_HANDLE, (HANDLE) _get_osfhandle (in)))
455 report_file_error ("Changing stdin handle", Qnil);
456
457 if (!SetStdHandle (STD_OUTPUT_HANDLE, (HANDLE) _get_osfhandle (out)))
458 report_file_error ("Changing stdout handle", Qnil);
459
460 /* We lose data if we use the same handle to the pipe for stdout and
461 stderr, so make a duplicate. This took a while to find. */
462 if (out == err)
463 {
464 if (!DuplicateHandle (parent,
465 (HANDLE) _get_osfhandle (err),
466 parent,
467 &err_handle,
468 0,
469 TRUE,
470 DUPLICATE_SAME_ACCESS))
471 report_file_error ("Duplicating out handle to make err handle.",
472 Qnil);
473 }
474 else
475 {
476 err_handle = (HANDLE) _get_osfhandle (err);
477 }
478
479 if (!SetStdHandle (STD_ERROR_HANDLE, err_handle))
480 report_file_error ("Changing stderr handle", Qnil);
481
482 handles[0] = stdin_save;
483 handles[1] = stdout_save;
484 handles[2] = stderr_save;
485 handles[3] = err_handle;
486}
487
488void
489reset_standard_handles (int in, int out, int err, HANDLE handles[4])
490{
491 HANDLE stdin_save = handles[0];
492 HANDLE stdout_save = handles[1];
493 HANDLE stderr_save = handles[2];
494 HANDLE err_handle = handles[3];
495
496 if (!SetStdHandle (STD_INPUT_HANDLE, stdin_save))
497 report_file_error ("Resetting input handle", Qnil);
498
499 if (!SetStdHandle (STD_OUTPUT_HANDLE, stdout_save))
500 report_file_error ("Resetting output handle", Qnil);
501
502 if (!SetStdHandle (STD_ERROR_HANDLE, stderr_save))
503 report_file_error ("Resetting error handle", Qnil);
504
505 if (out == err)
506 {
507 /* If out and err are the same handle, then we duplicated out
508 and stuck it in err_handle. Close the duplicate to clean up. */
509 if (!CloseHandle (err_handle))
510 report_file_error ("Closing error handle duplicated from out.",
511 Qnil);
512 }
513}
514
35f0d482
KH
515int
516random ()
517{
518 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
519 return ((rand () << 15) | rand ());
520}
521
522void
523srandom (int seed)
524{
525 srand (seed);
526}
527
95ed0025
RS
528/* Destructively turn backslashes into slashes. */
529void
530dostounix_filename (p)
531 register char *p;
532{
533 while (*p)
534 {
535 if (*p == '\\')
536 *p = '/';
537 p++;
538 }
539}
540
541/* Routines that are no-ops on NT but are defined to get Emacs to compile. */
542
543
544int
545sigsetmask (int signal_mask)
546{
547 return 0;
548}
549
550int
551sigblock (int sig)
552{
553 return 0;
554}
555
556int
557kill (int pid, int signal)
558{
559 return 0;
560}
561
562int
563setpgrp (int pid, int gid)
564{
565 return 0;
566}
567
568int
569alarm (int seconds)
570{
571 return 0;
572}
573
574int
575unrequest_sigio (void)
576{
577 return 0;
578}
579
580int
581request_sigio (void)
582{
583 return 0;
584}
585
586int
587getuid ()
588{
589 return 0;
590}
591
592int
593geteuid ()
594{
595 return 0;
596}
597
598/* Remove all CR's that are followed by a LF.
599 (From msdos.c...probably should figure out a way to share it,
600 although this code isn't going to ever change.) */
601int
602crlf_to_lf (n, buf)
603 register int n;
604 register unsigned char *buf;
605{
606 unsigned char *np = buf;
607 unsigned char *startp = buf;
608 unsigned char *endp = buf + n;
609
610 if (n == 0)
611 return n;
612 while (buf < endp - 1)
613 {
614 if (*buf == 0x0d)
615 {
616 if (*(++buf) != 0x0a)
617 *np++ = 0x0d;
618 }
619 else
620 *np++ = *buf++;
621 }
622 if (buf < endp)
623 *np++ = *buf++;
624 return np - startp;
625}
626
35f0d482
KH
627#ifdef HAVE_TIMEVAL
628#include <sys/timeb.h>
629
630/* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
631void
632gettimeofday (struct timeval *tv, struct timezone *tz)
633{
634 struct _timeb tb;
635 _ftime (&tb);
636
637 tv->tv_sec = tb.time;
638 tv->tv_usec = tb.millitm * 1000L;
639 if (tz)
640 {
641 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
642 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
643 }
644}
645#endif /* HAVE_TIMEVAL */
646
95ed0025
RS
647
648#ifdef PIGSFLY
649Keep this around...we might need it later.
650#ifdef WINDOWSNT
651{
652 /*
653 * Find the user's real name by opening the process token and looking
654 * up the name associated with the user-sid in that token.
655 */
656
657 char b[256], Name[256], RefD[256];
658 DWORD length = 256, rlength = 256, trash;
659 HANDLE Token;
660 SID_NAME_USE User;
661
662 if (1)
663 Vuser_real_name = build_string ("foo");
664 else if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &Token))
665 {
666 Vuser_real_name = build_string ("unknown");
667 }
668 else if (!GetTokenInformation (Token, TokenUser, (PVOID)b, 256,
669 &trash))
670 {
671 CloseHandle (Token);
672 Vuser_real_name = build_string ("unknown");
673 }
674 else if (!LookupAccountSid ((void *)0, (PSID)b, Name, &length, RefD,
675 &rlength, &User))
676 {
677 CloseHandle (Token);
678 Vuser_real_name = build_string ("unknown");
679 }
680 else
681 Vuser_real_name = build_string (Name);
682}
683#else /* not WINDOWSNT */
684#endif /* not WINDOWSNT */
685#endif /* PIGSFLY */