update.
[chise/xemacs-chise.git-] / src / nt.c
index 4b21a11..bf46ba2 100644 (file)
--- a/src/nt.c
+++ b/src/nt.c
@@ -47,21 +47,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #include <stdlib.h>
 #include <stdio.h>
 
-#include <windows.h>
-#ifndef __MINGW32__
-#include <mmsystem.h>
-#else
-typedef void (CALLBACK TIMECALLBACK)(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
-
-typedef TIMECALLBACK FAR *LPTIMECALLBACK;
-DWORD WINAPI timeGetTime(void);
-MMRESULT WINAPI timeSetEvent(UINT uDelay, UINT uResolution,
-    LPTIMECALLBACK fptc, DWORD dwUser, UINT fuEvent);
-MMRESULT WINAPI timeKillEvent(UINT uTimerID);
-MMRESULT WINAPI timeGetDevCaps(TIMECAPS* ptc, UINT cbtc);
-MMRESULT WINAPI timeBeginPeriod(UINT uPeriod);
-MMRESULT WINAPI timeEndPeriod(UINT uPeriod);
-#endif
+#include "syswindows.h"
 
 #include "nt.h"
 #include <sys/dir.h>
@@ -132,25 +118,25 @@ static struct passwd the_passwd =
 };
 
 uid_t
-getuid () 
+getuid (void) 
 {
   return nt_fake_unix_uid;
 }
 
 uid_t 
-geteuid () 
+geteuid (void) 
 { 
   return nt_fake_unix_uid;
 }
 
 gid_t
-getgid () 
+getgid (void) 
 { 
   return the_passwd.pw_gid;
 }
 
 gid_t
-getegid () 
+getegid (void) 
 { 
   return getgid ();
 }
@@ -183,7 +169,7 @@ getpwnam (const char *name)
 }
 
 void
-init_user_info ()
+init_user_info (void)
 {
   /* This code is pretty much of ad hoc nature. There is no unix-like
      UIDs under Windows NT. There is no concept of root user, because
@@ -593,7 +579,7 @@ nt_get_resource (char *key, LPDWORD lpdwtype)
 }
 
 void
-init_environment ()
+init_environment (void)
 {
   /* Check for environment variables and use registry if they don't exist */
   {
@@ -615,7 +601,7 @@ init_environment ()
       "EMACSLOCKDIR",
       "INFOPATH"
     };
-#ifdef HEAP_IN_DATA
+#if defined (HEAP_IN_DATA) && !defined(PDUMP)
     cache_system_info ();
 #endif
     for (i = 0; i < countof (env_vars); i++) 
@@ -1250,6 +1236,11 @@ convert_time (FILETIME ft)
 }
 #else
 
+#if defined(__MINGW32__) && CYGWIN_VERSION_DLL_MAJOR <= 21
+#define LowPart u.LowPart
+#define HighPart u.HighPart
+#endif
+
 static LARGE_INTEGER utc_base_li;
 
 time_t
@@ -1319,6 +1310,10 @@ convert_time (FILETIME uft)
   return ret;
 }
 #endif
+#if defined(__MINGW32__) && CYGWIN_VERSION_DLL_MAJOR <= 21
+#undef LowPart
+#undef HighPart
+#endif
 
 #if 0
 /* in case we ever have need of this */
@@ -1400,6 +1395,12 @@ generate_inode_val (const char * name)
    Oh, and do not encapsulater stat for non-MS compilers, too */
 /* #### popineau@ese-metz.fr says they still might be broken.
    Oh well... Let's add that `1 ||' condition.... --kkm */
+/* #### aichner@ecf.teradyne.com reported that with the library
+   provided stat/fstat, (file-exist "d:\\tmp\\") =>> nil,
+   (file-exist "d:\\tmp") =>> t, when d:\tmp exists. Whenever
+   we opt to use non-encapsulated stat(), this should serve as
+   a compatibility test. --kkm */
+
 #if 1 || defined(_MSC_VER) && _MSC_VER < 1100
 
 /* Since stat is encapsulated on Windows NT, we need to encapsulate
@@ -1667,7 +1668,7 @@ term_ntproc (int unused)
 }
 
 void
-init_ntproc ()
+init_ntproc (void)
 {
   /* Initial preparation for subprocess support: replace our standard
      handles with non-inheritable versions. */
@@ -2002,9 +2003,15 @@ int setitimer (int kind, const struct itimerval* itnew,
     return errno = EINVAL;
 }
 
+\f
+/*--------------------------------------------------------------------*/
+/*                        Memory-mapped files                         */
+/*--------------------------------------------------------------------*/
+
 int
 open_input_file (file_data *p_file, const char *filename)
 {
+  /* Synched with FSF 20.6.  We fixed some warnings. */
   HANDLE file;
   HANDLE file_mapping;
   void  *file_base;
@@ -2034,6 +2041,179 @@ open_input_file (file_data *p_file, const char *filename)
   return TRUE;
 }
 
+int
+open_output_file (file_data *p_file, const char *filename, unsigned long size)
+{
+  /* Synched with FSF 20.6.  We fixed some warnings. */
+  HANDLE file;
+  HANDLE file_mapping;
+  void  *file_base;
+
+  file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+  if (file == INVALID_HANDLE_VALUE) 
+    return FALSE;
+
+  file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE, 
+                                   0, size, NULL);
+  if (!file_mapping) 
+    return FALSE;
+  
+  file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
+  if (file_base == NULL) 
+    return FALSE;
+  
+  p_file->name = filename;
+  p_file->size = size;
+  p_file->file = file;
+  p_file->file_mapping = file_mapping;
+  p_file->file_base = (char*) file_base;
+
+  return TRUE;
+}
+
+#if 1 /* !defined(__MINGW32__) */
+/* Return pointer to section header for section containing the given
+   relative virtual address. */
+static IMAGE_SECTION_HEADER *
+rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
+{
+  /* Synched with FSF 20.6.  We added MINGW32 stuff. */
+  PIMAGE_SECTION_HEADER section;
+  int i;
+
+  section = IMAGE_FIRST_SECTION (nt_header);
+
+  for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
+    {
+      /* Some linkers (eg. the NT SDK linker I believe) swapped the
+        meaning of these two values - or rather, they ignored
+        VirtualSize entirely and always set it to zero.  This affects
+        some very old exes (eg. gzip dated Dec 1993).  Since
+        mswindows_executable_type relies on this function to work reliably,
+        we need to cope with this.  */
+      DWORD real_size = max (section->SizeOfRawData,
+                            section->Misc.VirtualSize);
+      if (rva >= section->VirtualAddress
+         && rva < section->VirtualAddress + real_size)
+       return section;
+      section++;
+    }
+  return NULL;
+}
+#endif
+
+void
+mswindows_executable_type (const char * filename, int * is_dos_app,
+                          int * is_cygnus_app)
+{
+  /* Synched with FSF 20.6.  We added MINGW32 stuff and casts. */
+  file_data executable;
+  char * p;
+
+  /* Default values in case we can't tell for sure.  */
+  *is_dos_app = FALSE;
+  *is_cygnus_app = FALSE;
+
+  if (!open_input_file (&executable, filename))
+    return;
+
+  p = strrchr (filename, '.');
+
+  /* We can only identify DOS .com programs from the extension. */
+  if (p && stricmp (p, ".com") == 0)
+    *is_dos_app = TRUE;
+  else if (p && (stricmp (p, ".bat") == 0 ||
+                stricmp (p, ".cmd") == 0))
+    {
+      /* A DOS shell script - it appears that CreateProcess is happy to
+        accept this (somewhat surprisingly); presumably it looks at
+        COMSPEC to determine what executable to actually invoke.
+        Therefore, we have to do the same here as well. */
+      /* Actually, I think it uses the program association for that
+        extension, which is defined in the registry.  */
+      p = egetenv ("COMSPEC");
+      if (p)
+       mswindows_executable_type (p, is_dos_app, is_cygnus_app);
+    }
+  else
+    {
+      /* Look for DOS .exe signature - if found, we must also check that
+        it isn't really a 16- or 32-bit Windows exe, since both formats
+        start with a DOS program stub.  Note that 16-bit Windows
+        executables use the OS/2 1.x format. */
+
+#if 0 /* defined( __MINGW32__ ) */
+      /* mingw32 doesn't have enough headers to detect cygwin
+        apps, just do what we can. */
+      FILHDR * exe_header;
+
+      exe_header = (FILHDR*) executable.file_base;
+      if (exe_header->e_magic != DOSMAGIC)
+       goto unwind;
+
+      if ((char*) exe_header->e_lfanew > (char*) executable.size)
+       {
+         /* Some dos headers (pkunzip) have bogus e_lfanew fields.  */
+         *is_dos_app = TRUE;
+       } 
+      else if (exe_header->nt_signature != NT_SIGNATURE)
+       {
+         *is_dos_app = TRUE;
+       }
+#else
+      IMAGE_DOS_HEADER * dos_header;
+      IMAGE_NT_HEADERS * nt_header;
+
+      dos_header = (PIMAGE_DOS_HEADER) executable.file_base;
+      if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
+       goto unwind;
+         
+      nt_header = (PIMAGE_NT_HEADERS) ((char*) dos_header + dos_header->e_lfanew);
+         
+      if ((char*) nt_header > (char*) dos_header + executable.size) 
+       {
+         /* Some dos headers (pkunzip) have bogus e_lfanew fields.  */
+         *is_dos_app = TRUE;
+       } 
+      else if (nt_header->Signature != IMAGE_NT_SIGNATURE &&
+              LOWORD (nt_header->Signature) != IMAGE_OS2_SIGNATURE)
+       {
+         *is_dos_app = TRUE;
+       }
+      else if (nt_header->Signature == IMAGE_NT_SIGNATURE)
+       {
+         /* Look for cygwin.dll in DLL import list. */
+         IMAGE_DATA_DIRECTORY import_dir =
+           nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
+         IMAGE_IMPORT_DESCRIPTOR * imports;
+         IMAGE_SECTION_HEADER * section;
+
+         section = rva_to_section (import_dir.VirtualAddress, nt_header);
+         imports = (IMAGE_IMPORT_DESCRIPTOR *) RVA_TO_PTR (import_dir.VirtualAddress,
+                                                           section, executable);
+             
+         for ( ; imports->Name; imports++)
+           {
+             char *dllname = (char*) RVA_TO_PTR (imports->Name, section, executable);
+
+             /* The exact name of the cygwin dll has changed with
+                various releases, but hopefully this will be reasonably
+                future proof.  */
+             if (strncmp (dllname, "cygwin", 6) == 0)
+               {
+                 *is_cygnus_app = TRUE;
+                 break;
+               }
+           }
+       }
+#endif
+    }
+
+ unwind:
+  close_file_data (&executable);
+}
+
 /* Close the system structures associated with the given file.  */
 void
 close_file_data (file_data *p_file)