(PTY_ITERATION, PTY_NAME_SPRINTF, PTY_OPEN)
[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
6816efce 59#include <config.h>
95ed0025
RS
60#include <windows.h>
61#include <stdlib.h>
62#include <stdio.h>
63#include <io.h>
64#include <fcntl.h>
65#include <ctype.h>
66
95ed0025
RS
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
bd4a449f 266static char configuration_buffer[32];
95ed0025
RS
267
268char *
269get_emacs_configuration (void)
270{
bd4a449f 271 char *arch, *oem, *os;
95ed0025
RS
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
bd4a449f
GV
300#ifdef WINDOWS95
301 os = "win";
302#else
303 os = "nt";
304#endif
305
306 sprintf (configuration_buffer, "%s-%s-%s%d.%d", arch, oem, os,
95ed0025
RS
307 get_nt_major_version (), get_nt_minor_version ());
308 return configuration_buffer;
309}
310
311/* Conjure up inode and device numbers that will serve the purpose
312 of Emacs. Return 1 upon success, 0 upon failure. */
313int
314get_inode_and_device_vals (Lisp_Object filename, Lisp_Object *p_inode,
315 Lisp_Object *p_device)
316{
317 /* File uids on NT are found using a handle to a file, which
318 implies that it has been opened. Since we want to be able
319 to stat an arbitrary file, we must open it, get the info,
320 and then close it.
321
322 Also, NT file uids are 64-bits. This is a problem. */
323
324 HANDLE handle;
325 BOOL result;
35f0d482 326 DWORD attrs;
95ed0025
RS
327 BY_HANDLE_FILE_INFORMATION info;
328
35f0d482
KH
329 /* We have to stat files and directories differently, so check
330 to see what filename references. */
331 attrs = GetFileAttributes (XSTRING (filename)->data);
332 if (attrs == 0xFFFFFFFF) {
333 return 0;
334 }
335 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
336 /* Conjure up bogus, but unique, values. */
337 attrs = GetTickCount ();
338 *p_inode = make_number (attrs);
339 *p_device = make_number (attrs);
340 return 1;
341 }
342
95ed0025
RS
343 /* FIXME: It shouldn't be opened without READ access, but NT on x86
344 doesn't allow GetFileInfo in that case (NT on mips does). */
345
346 handle = CreateFile (XSTRING (filename)->data,
347 GENERIC_READ,
348 FILE_SHARE_READ | FILE_SHARE_WRITE,
349 NULL,
350 OPEN_EXISTING,
351 FILE_ATTRIBUTE_NORMAL,
352 NULL);
353 if (handle == INVALID_HANDLE_VALUE)
354 return 0;
355
356 result = GetFileInformationByHandle (handle, &info);
357 CloseHandle (handle);
358 if (!result)
359 return 0;
360
361 *p_inode = make_number (info.nFileIndexLow); /* use the low value */
362 *p_device = make_number (info.dwVolumeSerialNumber);
363
364 return 1;
365}
366
367/* The following pipe routines are used to support our fork emulation.
368 Since NT's crt dup always creates inherited handles, we
369 must be careful in setting up pipes. First create
370 non-inherited pipe handles, then create an inherited handle
371 to the write end by dup-ing it, and then close the non-inherited
372 end that was just duped. This gives us one non-inherited handle
373 on the read end and one inherited handle to the write end. As
374 the parent, we close the inherited handle to the write end after
375 spawning the child. */
376
377/* From callproc.c */
378extern Lisp_Object Vbinary_process_input;
379extern Lisp_Object Vbinary_process_output;
380
381void
382pipe_with_inherited_out (int fds[2])
383{
384 int inherit_out;
385 unsigned int flags = _O_NOINHERIT;
386
387 if (!NILP (Vbinary_process_output))
388 flags |= _O_BINARY;
389
390 _pipe (fds, 0, flags);
391 inherit_out = dup (fds[1]);
392 close (fds[1]);
393 fds[1] = inherit_out;
394}
395
396void
397pipe_with_inherited_in (int fds[2])
398{
399 int inherit_in;
400 unsigned int flags = _O_NOINHERIT;
401
402 if (!NILP (Vbinary_process_input))
403 flags |= _O_BINARY;
404
405 _pipe (fds, 0, flags);
406 inherit_in = dup (fds[0]);
407 close (fds[0]);
408 fds[0] = inherit_in;
409}
410
411/* The following two routines are used to manipulate stdin, stdout, and
412 stderr of our child processes.
413
414 Assuming that in, out, and err are inherited, we make them stdin,
415 stdout, and stderr of the child as follows:
416
417 - Save the parent's current standard handles.
418 - Set the parent's standard handles to the handles being passed in.
419 (Note that _get_osfhandle is an io.h procedure that
420 maps crt file descriptors to NT file handles.)
421 - Spawn the child, which inherits in, out, and err as stdin,
422 stdout, and stderr. (see Spawnve)
423 - Reset the parent's standard handles to the saved handles.
424 (see reset_standard_handles)
425 We assume that the caller closes in, out, and err after calling us. */
426
427void
428prepare_standard_handles (int in, int out, int err, HANDLE handles[4])
429{
430 HANDLE parent, stdin_save, stdout_save, stderr_save, err_handle;
bd4a449f
GV
431
432#ifdef WINDOWS95
433 /* The Win95 beta doesn't set the standard handles correctly.
434 Handicap subprocesses until we get a version that works correctly.
435 Undefining the subprocesses macro reveals other incompatibilities,
436 so, since we're expecting subprocs to work in the near future,
437 disable them here. */
438 report_file_error ("Subprocesses currently disabled on Win95", Qnil);
439#endif
440
95ed0025 441 parent = GetCurrentProcess ();
bd4a449f
GV
442 stdin_save = GetStdHandle (STD_INPUT_HANDLE);
443 stdout_save = GetStdHandle (STD_OUTPUT_HANDLE);
444 stderr_save = GetStdHandle (STD_ERROR_HANDLE);
445
95ed0025
RS
446 if (!DuplicateHandle (parent,
447 GetStdHandle (STD_INPUT_HANDLE),
448 parent,
449 &stdin_save,
450 0,
451 FALSE,
452 DUPLICATE_SAME_ACCESS))
453 report_file_error ("Duplicating parent's input handle", Qnil);
454
455 if (!DuplicateHandle (parent,
456 GetStdHandle (STD_OUTPUT_HANDLE),
457 parent,
458 &stdout_save,
459 0,
460 FALSE,
461 DUPLICATE_SAME_ACCESS))
462 report_file_error ("Duplicating parent's output handle", Qnil);
463
464 if (!DuplicateHandle (parent,
465 GetStdHandle (STD_ERROR_HANDLE),
466 parent,
467 &stderr_save,
468 0,
469 FALSE,
470 DUPLICATE_SAME_ACCESS))
471 report_file_error ("Duplicating parent's error handle", Qnil);
472
473 if (!SetStdHandle (STD_INPUT_HANDLE, (HANDLE) _get_osfhandle (in)))
474 report_file_error ("Changing stdin handle", Qnil);
475
476 if (!SetStdHandle (STD_OUTPUT_HANDLE, (HANDLE) _get_osfhandle (out)))
477 report_file_error ("Changing stdout handle", Qnil);
478
479 /* We lose data if we use the same handle to the pipe for stdout and
480 stderr, so make a duplicate. This took a while to find. */
481 if (out == err)
482 {
483 if (!DuplicateHandle (parent,
484 (HANDLE) _get_osfhandle (err),
485 parent,
486 &err_handle,
487 0,
488 TRUE,
489 DUPLICATE_SAME_ACCESS))
490 report_file_error ("Duplicating out handle to make err handle.",
491 Qnil);
492 }
493 else
494 {
495 err_handle = (HANDLE) _get_osfhandle (err);
496 }
497
498 if (!SetStdHandle (STD_ERROR_HANDLE, err_handle))
499 report_file_error ("Changing stderr handle", Qnil);
500
501 handles[0] = stdin_save;
502 handles[1] = stdout_save;
503 handles[2] = stderr_save;
504 handles[3] = err_handle;
505}
506
507void
508reset_standard_handles (int in, int out, int err, HANDLE handles[4])
509{
510 HANDLE stdin_save = handles[0];
511 HANDLE stdout_save = handles[1];
512 HANDLE stderr_save = handles[2];
513 HANDLE err_handle = handles[3];
bd4a449f
GV
514 int i;
515
95ed0025
RS
516 if (!SetStdHandle (STD_INPUT_HANDLE, stdin_save))
517 report_file_error ("Resetting input handle", Qnil);
518
519 if (!SetStdHandle (STD_OUTPUT_HANDLE, stdout_save))
bd4a449f
GV
520 {
521 i = GetLastError ();
522 report_file_error ("Resetting output handle", Qnil);
523 }
95ed0025
RS
524
525 if (!SetStdHandle (STD_ERROR_HANDLE, stderr_save))
526 report_file_error ("Resetting error handle", Qnil);
527
528 if (out == err)
529 {
530 /* If out and err are the same handle, then we duplicated out
531 and stuck it in err_handle. Close the duplicate to clean up. */
532 if (!CloseHandle (err_handle))
533 report_file_error ("Closing error handle duplicated from out.",
534 Qnil);
535 }
536}
537
35f0d482
KH
538int
539random ()
540{
541 /* rand () on NT gives us 15 random bits...hack together 30 bits. */
542 return ((rand () << 15) | rand ());
543}
544
545void
546srandom (int seed)
547{
548 srand (seed);
549}
550
95ed0025
RS
551/* Destructively turn backslashes into slashes. */
552void
553dostounix_filename (p)
554 register char *p;
555{
556 while (*p)
557 {
558 if (*p == '\\')
559 *p = '/';
560 p++;
561 }
562}
563
564/* Routines that are no-ops on NT but are defined to get Emacs to compile. */
565
566
567int
568sigsetmask (int signal_mask)
569{
570 return 0;
571}
572
573int
574sigblock (int sig)
575{
576 return 0;
577}
578
579int
580kill (int pid, int signal)
581{
582 return 0;
583}
584
585int
586setpgrp (int pid, int gid)
587{
588 return 0;
589}
590
591int
592alarm (int seconds)
593{
594 return 0;
595}
596
597int
598unrequest_sigio (void)
599{
600 return 0;
601}
602
603int
604request_sigio (void)
605{
606 return 0;
607}
608
609int
610getuid ()
611{
612 return 0;
613}
614
615int
616geteuid ()
617{
618 return 0;
619}
620
621/* Remove all CR's that are followed by a LF.
622 (From msdos.c...probably should figure out a way to share it,
623 although this code isn't going to ever change.) */
624int
625crlf_to_lf (n, buf)
626 register int n;
627 register unsigned char *buf;
628{
629 unsigned char *np = buf;
630 unsigned char *startp = buf;
631 unsigned char *endp = buf + n;
632
633 if (n == 0)
634 return n;
635 while (buf < endp - 1)
636 {
637 if (*buf == 0x0d)
638 {
639 if (*(++buf) != 0x0a)
640 *np++ = 0x0d;
641 }
642 else
643 *np++ = *buf++;
644 }
645 if (buf < endp)
646 *np++ = *buf++;
647 return np - startp;
648}
649
35f0d482
KH
650#ifdef HAVE_TIMEVAL
651#include <sys/timeb.h>
652
653/* Emulate gettimeofday (Ulrich Leodolter, 1/11/95). */
654void
655gettimeofday (struct timeval *tv, struct timezone *tz)
656{
657 struct _timeb tb;
658 _ftime (&tb);
659
660 tv->tv_sec = tb.time;
661 tv->tv_usec = tb.millitm * 1000L;
662 if (tz)
663 {
664 tz->tz_minuteswest = tb.timezone; /* minutes west of Greenwich */
665 tz->tz_dsttime = tb.dstflag; /* type of dst correction */
666 }
667}
668#endif /* HAVE_TIMEVAL */
669
95ed0025
RS
670
671#ifdef PIGSFLY
672Keep this around...we might need it later.
673#ifdef WINDOWSNT
674{
675 /*
676 * Find the user's real name by opening the process token and looking
677 * up the name associated with the user-sid in that token.
678 */
679
680 char b[256], Name[256], RefD[256];
681 DWORD length = 256, rlength = 256, trash;
682 HANDLE Token;
683 SID_NAME_USE User;
684
685 if (1)
7cca72e3 686 Vuser_real_login_name = build_string ("foo");
95ed0025
RS
687 else if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &Token))
688 {
7cca72e3 689 Vuser_real_login_name = build_string ("unknown");
95ed0025
RS
690 }
691 else if (!GetTokenInformation (Token, TokenUser, (PVOID)b, 256,
692 &trash))
693 {
694 CloseHandle (Token);
7cca72e3 695 Vuser_real_login_name = build_string ("unknown");
95ed0025
RS
696 }
697 else if (!LookupAccountSid ((void *)0, (PSID)b, Name, &length, RefD,
698 &rlength, &User))
699 {
700 CloseHandle (Token);
7cca72e3 701 Vuser_real_login_name = build_string ("unknown");
95ed0025
RS
702 }
703 else
7cca72e3 704 Vuser_real_login_name = build_string (Name);
95ed0025
RS
705}
706#else /* not WINDOWSNT */
707#endif /* not WINDOWSNT */
708#endif /* PIGSFLY */