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