Mercurial > emacs
diff src/w32.c @ 9803:fa698fd10c05
Initial revision
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Tue, 01 Nov 1994 10:27:02 +0000 |
parents | |
children | 1b01db213663 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/w32.c Tue Nov 01 10:27:02 1994 +0000 @@ -0,0 +1,610 @@ +/* Utility and Unix shadow routines for GNU Emacs on Windows NT. + Copyright (C) 1994 Free Software Foundation, Inc. + + This file is part of GNU Emacs. + + GNU Emacs is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 1, or (at your option) any later + version. + + GNU Emacs is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along + with GNU Emacs; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + Geoff Voelker (voelker@cs.washington.edu) 7-29-94 +*/ + +#include <windows.h> +#include <stdlib.h> +#include <stdio.h> +#include <io.h> +#include <fcntl.h> +#include <ctype.h> + +#include "config.h" +#define getwd _getwd +#include "lisp.h" +#undef getwd + +#include <pwd.h> + +#include "ndir.h" +#include "ntheap.h" + +extern int report_file_error (char *, Lisp_Object); + +/* Get the current working directory. */ +int +getwd (char *dir) +{ + return GetCurrentDirectory (MAXPATHLEN, dir); +} + +/* Emulate gethostname. */ +int +gethostname (char *buffer, int size) +{ + /* NT only allows small host names, so the buffer is + certainly large enough. */ + return !GetComputerName (buffer, &size); +} + +/* Emulate getloadavg. */ +int +getloadavg (double loadavg[], int nelem) +{ + int i; + + /* A faithful emulation is going to have to be saved for a rainy day. */ + for (i = 0; i < nelem; i++) + { + loadavg[i] = 0.0; + } + return i; +} + +/* Emulate sleep...we could have done this with a define, but that + would necessitate including windows.h in the files that used it. + This is much easier. */ +void +nt_sleep (int seconds) +{ + Sleep (seconds * 1000); +} + +/* Emulate the Unix directory procedures opendir, closedir, + and readdir. We can't use the procedures supplied in sysdep.c, + so we provide them here. */ + +struct direct dir_static; /* simulated directory contents */ +static int dir_finding; +static HANDLE dir_find_handle; + +DIR * +opendir (char *filename) +{ + DIR *dirp; + + /* Opening is done by FindFirstFile. However, a read is inherent to + this operation, so we have a flag to handle the open at read + time. This flag essentially means "there is a find-handle open and + it needs to be closed." */ + + if (!(dirp = (DIR *) malloc (sizeof (DIR)))) + { + return 0; + } + + dirp->dd_fd = 0; + dirp->dd_loc = 0; + dirp->dd_size = 0; + + /* This is tacky, but we need the directory name for our + implementation of readdir. */ + strncpy (dirp->dd_buf, filename, DIRBLKSIZ); + return dirp; +} + +void +closedir (DIR *dirp) +{ + /* If we have a find-handle open, close it. */ + if (dir_finding) + { + FindClose (dir_find_handle); + dir_finding = 0; + } + xfree ((char *) dirp); +} + +struct direct * +readdir (DIR *dirp) +{ + WIN32_FIND_DATA find_data; + + /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */ + if (!dir_finding) + { + char filename[MAXNAMLEN + 3]; + int ln; + + strncpy (filename, dirp->dd_buf, MAXNAMLEN); + ln = strlen (filename)-1; + if (filename[ln] != '\\' && filename[ln] != ':') + strcat (filename, "\\"); + strcat (filename, "*.*"); + + dir_find_handle = FindFirstFile (filename, &find_data); + + if (dir_find_handle == INVALID_HANDLE_VALUE) + return NULL; + + dir_finding = 1; + } + else + { + if (!FindNextFile (dir_find_handle, &find_data)) + return NULL; + } + + /* Don't return . or .. since it doesn't look like any of the + readdir calling code expects them. */ + while (strcmp (find_data.cFileName, ".") == 0 + || strcmp (find_data.cFileName, "..") == 0) + { + if (!FindNextFile (dir_find_handle, &find_data)) + return 0; + } + + /* NT's unique ID for a file is 64 bits, so we have to fake it here. + This should work as long as we never use 0. */ + dir_static.d_ino = 1; + + dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 + + dir_static.d_namlen - dir_static.d_namlen % 4; + + dir_static.d_namlen = strlen (find_data.cFileName); + strncpy (dir_static.d_name, find_data.cFileName, MAXNAMLEN); + + return &dir_static; +} + +/* Emulate getpwuid and getpwnam. */ + +int getuid (); /* forward declaration */ + +static char the_passwd_name[256]; +static char the_passwd_passwd[256]; +static char the_passwd_gecos[256]; +static char the_passwd_dir[256]; +static char the_passwd_shell[256]; + +static struct passwd the_passwd = +{ + the_passwd_name, + the_passwd_passwd, + 0, + 0, + 0, + the_passwd_gecos, + the_passwd_dir, + the_passwd_shell, +}; + +struct passwd * +getpwuid (int uid) +{ + int size = 256; + + if (!GetUserName (the_passwd.pw_name, &size)) + return NULL; + + the_passwd.pw_passwd[0] = '\0'; + the_passwd.pw_uid = 0; + the_passwd.pw_gid = 0; + strcpy (the_passwd.pw_gecos, the_passwd.pw_name); + the_passwd.pw_dir[0] = '\0'; + the_passwd.pw_shell[0] = '\0'; + + return &the_passwd; +} + +struct passwd * +getpwnam (char *name) +{ + struct passwd *pw; + + pw = getpwuid (getuid ()); + if (!pw) + return pw; + + if (strcmp (name, pw->pw_name)) + return NULL; + + return pw; +} + + +/* We don't have scripts to automatically determine the system configuration + for Emacs before it's compiled, and we don't want to have to make the + user enter it, so we define EMACS_CONFIGURATION to invoke this runtime + routine. */ + +static char configuration_buffer[16]; + +char * +get_emacs_configuration (void) +{ + char *arch, *oem; + + /* Determine the processor type. */ + switch (get_processor_type ()) + { + case PROCESSOR_INTEL_386: + case PROCESSOR_INTEL_486: + case PROCESSOR_INTEL_PENTIUM: + arch = "i386"; + break; + case PROCESSOR_INTEL_860: + arch = "i860"; + break; + case PROCESSOR_MIPS_R2000: + case PROCESSOR_MIPS_R3000: + case PROCESSOR_MIPS_R4000: + arch = "mips"; + break; + case PROCESSOR_ALPHA_21064: + arch = "alpha"; + break; + default: + arch = "unknown"; + break; + } + + /* Let oem be "*" until we figure out how to decode the OEM field. */ + oem = "*"; + + sprintf (configuration_buffer, "%s-%s-nt%d.%d", arch, oem, + get_nt_major_version (), get_nt_minor_version ()); + return configuration_buffer; +} + +/* Conjure up inode and device numbers that will serve the purpose + of Emacs. Return 1 upon success, 0 upon failure. */ +int +get_inode_and_device_vals (Lisp_Object filename, Lisp_Object *p_inode, + Lisp_Object *p_device) +{ + /* File uids on NT are found using a handle to a file, which + implies that it has been opened. Since we want to be able + to stat an arbitrary file, we must open it, get the info, + and then close it. + + Also, NT file uids are 64-bits. This is a problem. */ + + HANDLE handle; + BOOL result; + BY_HANDLE_FILE_INFORMATION info; + + /* FIXME: It shouldn't be opened without READ access, but NT on x86 + doesn't allow GetFileInfo in that case (NT on mips does). */ + + handle = CreateFile (XSTRING (filename)->data, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (handle == INVALID_HANDLE_VALUE) + return 0; + + result = GetFileInformationByHandle (handle, &info); + CloseHandle (handle); + if (!result) + return 0; + + *p_inode = make_number (info.nFileIndexLow); /* use the low value */ + *p_device = make_number (info.dwVolumeSerialNumber); + + return 1; +} + +/* The following pipe routines are used to support our fork emulation. + Since NT's crt dup always creates inherited handles, we + must be careful in setting up pipes. First create + non-inherited pipe handles, then create an inherited handle + to the write end by dup-ing it, and then close the non-inherited + end that was just duped. This gives us one non-inherited handle + on the read end and one inherited handle to the write end. As + the parent, we close the inherited handle to the write end after + spawning the child. */ + +/* From callproc.c */ +extern Lisp_Object Vbinary_process_input; +extern Lisp_Object Vbinary_process_output; + +void +pipe_with_inherited_out (int fds[2]) +{ + int inherit_out; + unsigned int flags = _O_NOINHERIT; + + if (!NILP (Vbinary_process_output)) + flags |= _O_BINARY; + + _pipe (fds, 0, flags); + inherit_out = dup (fds[1]); + close (fds[1]); + fds[1] = inherit_out; +} + +void +pipe_with_inherited_in (int fds[2]) +{ + int inherit_in; + unsigned int flags = _O_NOINHERIT; + + if (!NILP (Vbinary_process_input)) + flags |= _O_BINARY; + + _pipe (fds, 0, flags); + inherit_in = dup (fds[0]); + close (fds[0]); + fds[0] = inherit_in; +} + +/* The following two routines are used to manipulate stdin, stdout, and + stderr of our child processes. + + Assuming that in, out, and err are inherited, we make them stdin, + stdout, and stderr of the child as follows: + + - Save the parent's current standard handles. + - Set the parent's standard handles to the handles being passed in. + (Note that _get_osfhandle is an io.h procedure that + maps crt file descriptors to NT file handles.) + - Spawn the child, which inherits in, out, and err as stdin, + stdout, and stderr. (see Spawnve) + - Reset the parent's standard handles to the saved handles. + (see reset_standard_handles) + We assume that the caller closes in, out, and err after calling us. */ + +void +prepare_standard_handles (int in, int out, int err, HANDLE handles[4]) +{ + HANDLE parent, stdin_save, stdout_save, stderr_save, err_handle; + + parent = GetCurrentProcess (); + if (!DuplicateHandle (parent, + GetStdHandle (STD_INPUT_HANDLE), + parent, + &stdin_save, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)) + report_file_error ("Duplicating parent's input handle", Qnil); + + if (!DuplicateHandle (parent, + GetStdHandle (STD_OUTPUT_HANDLE), + parent, + &stdout_save, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)) + report_file_error ("Duplicating parent's output handle", Qnil); + + if (!DuplicateHandle (parent, + GetStdHandle (STD_ERROR_HANDLE), + parent, + &stderr_save, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)) + report_file_error ("Duplicating parent's error handle", Qnil); + + if (!SetStdHandle (STD_INPUT_HANDLE, (HANDLE) _get_osfhandle (in))) + report_file_error ("Changing stdin handle", Qnil); + + if (!SetStdHandle (STD_OUTPUT_HANDLE, (HANDLE) _get_osfhandle (out))) + report_file_error ("Changing stdout handle", Qnil); + + /* We lose data if we use the same handle to the pipe for stdout and + stderr, so make a duplicate. This took a while to find. */ + if (out == err) + { + if (!DuplicateHandle (parent, + (HANDLE) _get_osfhandle (err), + parent, + &err_handle, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) + report_file_error ("Duplicating out handle to make err handle.", + Qnil); + } + else + { + err_handle = (HANDLE) _get_osfhandle (err); + } + + if (!SetStdHandle (STD_ERROR_HANDLE, err_handle)) + report_file_error ("Changing stderr handle", Qnil); + + handles[0] = stdin_save; + handles[1] = stdout_save; + handles[2] = stderr_save; + handles[3] = err_handle; +} + +void +reset_standard_handles (int in, int out, int err, HANDLE handles[4]) +{ + HANDLE stdin_save = handles[0]; + HANDLE stdout_save = handles[1]; + HANDLE stderr_save = handles[2]; + HANDLE err_handle = handles[3]; + + if (!SetStdHandle (STD_INPUT_HANDLE, stdin_save)) + report_file_error ("Resetting input handle", Qnil); + + if (!SetStdHandle (STD_OUTPUT_HANDLE, stdout_save)) + report_file_error ("Resetting output handle", Qnil); + + if (!SetStdHandle (STD_ERROR_HANDLE, stderr_save)) + report_file_error ("Resetting error handle", Qnil); + + if (out == err) + { + /* If out and err are the same handle, then we duplicated out + and stuck it in err_handle. Close the duplicate to clean up. */ + if (!CloseHandle (err_handle)) + report_file_error ("Closing error handle duplicated from out.", + Qnil); + } +} + +/* Destructively turn backslashes into slashes. */ +void +dostounix_filename (p) + register char *p; +{ + while (*p) + { + if (*p == '\\') + *p = '/'; + p++; + } +} + +/* Routines that are no-ops on NT but are defined to get Emacs to compile. */ + + +int +sigsetmask (int signal_mask) +{ + return 0; +} + +int +sigblock (int sig) +{ + return 0; +} + +int +kill (int pid, int signal) +{ + return 0; +} + +int +setpgrp (int pid, int gid) +{ + return 0; +} + +int +alarm (int seconds) +{ + return 0; +} + +int +unrequest_sigio (void) +{ + return 0; +} + +int +request_sigio (void) +{ + return 0; +} + +int +getuid () +{ + return 0; +} + +int +geteuid () +{ + return 0; +} + +/* Remove all CR's that are followed by a LF. + (From msdos.c...probably should figure out a way to share it, + although this code isn't going to ever change.) */ +int +crlf_to_lf (n, buf) + register int n; + register unsigned char *buf; +{ + unsigned char *np = buf; + unsigned char *startp = buf; + unsigned char *endp = buf + n; + + if (n == 0) + return n; + while (buf < endp - 1) + { + if (*buf == 0x0d) + { + if (*(++buf) != 0x0a) + *np++ = 0x0d; + } + else + *np++ = *buf++; + } + if (buf < endp) + *np++ = *buf++; + return np - startp; +} + + +#ifdef PIGSFLY +Keep this around...we might need it later. +#ifdef WINDOWSNT +{ + /* + * Find the user's real name by opening the process token and looking + * up the name associated with the user-sid in that token. + */ + + char b[256], Name[256], RefD[256]; + DWORD length = 256, rlength = 256, trash; + HANDLE Token; + SID_NAME_USE User; + + if (1) + Vuser_real_name = build_string ("foo"); + else if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &Token)) + { + Vuser_real_name = build_string ("unknown"); + } + else if (!GetTokenInformation (Token, TokenUser, (PVOID)b, 256, + &trash)) + { + CloseHandle (Token); + Vuser_real_name = build_string ("unknown"); + } + else if (!LookupAccountSid ((void *)0, (PSID)b, Name, &length, RefD, + &rlength, &User)) + { + CloseHandle (Token); + Vuser_real_name = build_string ("unknown"); + } + else + Vuser_real_name = build_string (Name); +} +#else /* not WINDOWSNT */ +#endif /* not WINDOWSNT */ +#endif /* PIGSFLY */