]> sjero.net Git - wget/blobdiff - src/mswindows.c
[svn] Remove ws_help; it doesn't make sense to invoke the help browser for
[wget] / src / mswindows.c
index e5ae2f50d7e51c3ee6526dd6b7e9276f45c927d9..c0960ee24a41b2e1e0dc4c9c00b40ddccc2c5d25 100644 (file)
@@ -1,5 +1,5 @@
 /* mswindows.c -- Windows-specific support
-   Copyright (C) 1995, 1996, 1997, 1998  Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1997, 1998, 2004  Free Software Foundation, Inc.
 
 This file is part of GNU Wget.
 
@@ -33,7 +33,6 @@ so, delete this exception statement from your version.  */
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <winsock.h>
 #include <string.h>
 #include <assert.h>
 #include <errno.h>
@@ -75,35 +74,23 @@ static DWORD set_sleep_mode (DWORD mode);
 static DWORD pwr_mode = 0;
 static int windows_nt_p;
 
-#ifndef HAVE_SLEEP
+/* Windows version of xsleep in utils.c.  */
 
-/* Emulation of Unix sleep.  */
-
-unsigned int
-sleep (unsigned seconds)
-{
-  return SleepEx (1000 * seconds, TRUE) ? 0U : 1000 * seconds;
-}
-#endif
-
-#ifndef HAVE_USLEEP
-/* Emulation of Unix usleep().  This has a granularity of
-   milliseconds, but that's ok because:
-
-   a) Wget is only using it with milliseconds [not anymore, but b)
-      still applies];
-
-   b) You can't rely on usleep's granularity anyway.  If a caller
-   expects usleep to respect every microsecond, he's in for a
-   surprise.  */
-
-int
-usleep (unsigned long usec)
+void
+xsleep (double seconds)
 {
-  SleepEx (usec / 1000, TRUE);
-  return 0;
+#ifdef HAVE_USLEEP
+  if (seconds > 1000)
+    {
+      /* Explained in utils.c. */
+      sleep (seconds);
+      seconds -= (long) seconds;
+    }
+  usleep (seconds * 1000000L);
+#else  /* not HAVE_USLEEP */
+  SleepEx (seconds * 1000, FALSE);
+#endif /* not HAVE_USLEEP */
 }
-#endif  /* HAVE_USLEEP */
 
 void
 windows_main_junk (int *argc, char **argv, char **exec_name)
@@ -203,7 +190,7 @@ ws_percenttitle (double percent)
 {
   if (num_urls == 1 && title_buf && curr_url && fabs(percent) <= 100.0)
     {
-      sprintf (title_buf, "Wget [%.1f%%] %s", percent, curr_url);
+      sprintf (title_buf, "Wget [%.0f%%] %s", percent, curr_url);
       SetConsoleTitle (title_buf);
     }
 }
@@ -212,45 +199,26 @@ char *
 ws_mypath (void)
 {
   static char *wspathsave = NULL;
-  char buffer[MAX_PATH];
-  char *ptr;
 
-  if (wspathsave)
+  if (!wspathsave)
     {
-      return wspathsave;
-    }
+      char buf[MAX_PATH + 1];
+      char *p;
+      DWORD len;
 
-  if (GetModuleFileName (NULL, buffer, MAX_PATH) &&
-      (ptr = strrchr (buffer, PATH_SEPARATOR)) != NULL)
-    {
-      *(ptr + 1) = '\0';
-      wspathsave = xstrdup (buffer);
-    }
-  else
-    wspathsave = NULL;
-  return wspathsave;
-}
+      len = GetModuleFileName (GetModuleHandle (NULL), buf, sizeof (buf));
+      if (!len || (len >= sizeof (buf)))
+        return NULL;
 
-void
-ws_help (const char *name)
-{
-  char *mypath = ws_mypath ();
+      p = strrchr (buf, PATH_SEPARATOR);
+      if (!p)
+        return NULL;
 
-  if (mypath)
-    {
-      struct stat sbuf;
-      char *buf = (char *)alloca (strlen (mypath) + strlen (name) + 4 + 1);
-      sprintf (buf, "%s%s.HLP", mypath, name);
-      if (stat (buf, &sbuf) == 0) 
-       {
-          printf (_("Starting WinHelp %s\n"), buf);
-          WinHelp (NULL, buf, HELP_INDEX, NULL);
-        }
-      else
-        {
-          printf ("%s: %s\n", buf, strerror (errno));
-        }
+      *p = '\0';
+      wspathsave = xstrdup (buf);
     }
+
+  return wspathsave;
 }
 
 void
@@ -291,7 +259,8 @@ ws_startup (void)
    (The Borland utime function only works on Windows NT.)  */
 
 #ifdef HACK_BCC_UTIME_BUG
-int borland_utime(const char *path, const struct utimbuf *times)
+int
+borland_utime (const char *path, const struct utimbuf *times)
 {
   int fd;
   int res;
@@ -315,39 +284,40 @@ int borland_utime(const char *path, const struct utimbuf *times)
 #endif
 
 /*
- * Prevent Windows entering sleep/hibernation-mode while wget is doing a lengthy transfer.
- * Windows does by default not consider network activity in console-programs as activity !
- * Works on Win-98/ME/2K and up.
+ * Prevent Windows entering sleep/hibernation-mode while wget is doing
+ * a lengthy transfer.  Windows does by default not consider network
+ * activity in console-programs as activity !  Works on Win-98/ME/2K
+ * and up.
  */
-static
-DWORD set_sleep_mode (DWORD mode)
+static DWORD
+set_sleep_mode (DWORD mode)
 {
   HMODULE mod = LoadLibrary ("kernel32.dll");
-  DWORD (*_SetThreadExecutionState) (DWORD) = NULL;
+  DWORD (WINAPI *_SetThreadExecutionState) (DWORD) = NULL;
   DWORD rc = (DWORD)-1;
 
   if (mod)
-     (void*)_SetThreadExecutionState = GetProcAddress ((HINSTANCE)mod, "SetThreadExecutionState");
+     (void *)_SetThreadExecutionState
+       = GetProcAddress ((HINSTANCE)mod, "SetThreadExecutionState");
 
   if (_SetThreadExecutionState)
     {
       if (mode == 0)  /* first time */
-         mode = (ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
+       mode = (ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
       rc = (*_SetThreadExecutionState) (mode);
     }
   if (mod)
-     FreeLibrary (mod);
+    FreeLibrary (mod);
   DEBUGP (("set_sleep_mode(): mode 0x%08lX, rc 0x%08lX\n", mode, rc));
-  return (rc);
+  return rc;
 }
 \f
 /* run_with_timeout Windows implementation. */
 
-/* Wait for thread completion in 0.1s intervals (a tradeoff between 
* CPU loading and resolution).
+ /* Stack size 0 uses default thread stack-size (reserve+commit).
 * Determined by what's in the PE header.
  */
-#define THREAD_WAIT_INTV   100  
-#define THREAD_STACK_SIZE  4096 
+#define THREAD_STACK_SIZE  0
 
 struct thread_data {
    void (*fun) (void *);
@@ -355,46 +325,49 @@ struct thread_data {
    DWORD ws_error; 
 };
 
+/* The callback that runs FUN(ARG) in a separate thread.  This
+   function exists for two reasons: a) to not require FUN to be
+   declared WINAPI/__stdcall[1], and b) to retrieve Winsock errors,
+   which are per-thread.  The latter is useful when FUN calls Winsock
+   functions, which is how run_with_timeout is used in Wget.
+
+   [1] MSVC can use __fastcall globally (cl /Gr) and on Watcom this is
+   the default (wcc386 -3r).  */
+
 static DWORD WINAPI 
 thread_helper (void *arg)
 {
   struct thread_data *td = (struct thread_data *) arg;
-  
-  WSASetLastError (0);
-  td->ws_error = 0;
-  (*td->fun) (td->arg);
-  
-  /* Since run_with_timeout() is only used for Winsock functions and
-   * Winsock errors are per-thread, we must return this to caller.
-   */
-  td->ws_error = WSAGetLastError();
-  return (0); 
+
+  /* Initialize Winsock error to what it was in the parent.  That way
+     the subsequent call to WSAGetLastError will return the same value
+     if td->fun doesn't change Winsock error state.  */
+  WSASetLastError (td->ws_error);
+
+  td->fun (td->arg);
+
+  /* Return Winsock error to the caller, in case FUN ran Winsock
+     code.  */
+  td->ws_error = WSAGetLastError ();
+  return 0; 
 }
 
-#ifdef GV_DEBUG  /* I'll remove this eventually */
-# define DEBUGN(lvl,x)  do { if (opt.verbose >= (lvl)) DEBUGP (x); } while (0)
-#else
-# define DEBUGN(lvl,x)  ((void)0)
-#endif  
+/* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
+   seconds.  Returns non-zero if the function was interrupted with a
+   timeout, zero otherwise.
 
-/*
- * Run FUN with timeout.  This is done by creating a thread for 'fun'
- * to run in.  Since call-convention of 'fun' is undefined [1], we
- * must call it via thread_helper() which must be __stdcall/WINAPI.
- *
- * [1] MSVC can use __fastcall globally (cl /Gr) and on Watcom this is the
- *     default (wcc386 -3r). 
- */
+   This works by running FUN in a separate thread and terminating the
+   thread if it doesn't finish in the specified time.  */
 
 int
 run_with_timeout (double seconds, void (*fun) (void *), void *arg)
 {
   static HANDLE thread_hnd = NULL;
   struct thread_data thread_arg;
-  struct wget_timer *timer;
-  DWORD  thread_id, exitCode;
+  DWORD  thread_id;
+  int    rc = 0;
 
-  DEBUGN (2, ("seconds %.2f, ", seconds));
+  DEBUGP (("seconds %.2f, ", seconds));
   
   if (seconds == 0)
     {
@@ -405,51 +378,34 @@ run_with_timeout (double seconds, void (*fun) (void *), void *arg)
 
   /* Should never happen, but test for recursivety anyway */
   assert (thread_hnd == NULL);  
-  thread_arg.arg = arg;
+
   thread_arg.fun = fun;
-  thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE,
-                             thread_helper, (void*)&thread_arg, 
-                             0, &thread_id); 
+  thread_arg.arg = arg;
+  thread_arg.ws_error = WSAGetLastError ();
+  thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE, thread_helper,
+                            &thread_arg, 0, &thread_id); 
   if (!thread_hnd)
     {
-      DEBUGP (("CreateThread() failed; %s\n", strerror(GetLastError())));
+      DEBUGP (("CreateThread() failed; %s\n", strerror (GetLastError ())));
       goto blocking_fallback;
     }
 
-  timer = wtimer_new();
-
-  exitCode = 0;
-
-  /* Keep checking for thread's state until the timeout expires. */
-  while (wtimer_elapsed (timer) < 1000 * seconds)
+  if (WaitForSingleObject (thread_hnd, (DWORD)(1000 * seconds))
+      == WAIT_OBJECT_0)
     {
-      GetExitCodeThread (thread_hnd, &exitCode);
-      DEBUGN (2, ("thread exit-code %lu\n", exitCode));
-      if (exitCode != STILL_ACTIVE)
-       break;
-      Sleep (THREAD_WAIT_INTV);
-    }
-
-  DEBUGN (2, ("elapsed %.2f, wtimer_elapsed %.2f, ", elapsed,
-             wtimer_elapsed (timer)));
-
-  wtimer_delete (timer);
-
-  /* If we timed out kill the thread. Normal thread exitCode would be 0.
-   */
-  if (exitCode == STILL_ACTIVE)
-    {
-      DEBUGN (2, ("thread timed out\n"));
-      TerminateThread (thread_hnd, 0);
-    }  
-  else
-    {
-      DEBUGN (2, ("thread exit-code %lu, WS error %lu\n", exitCode, thread_arg.ws_error));
-
       /* Propagate error state (which is per-thread) to this thread,
         so the caller can inspect it.  */
       WSASetLastError (thread_arg.ws_error);
+      DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
+      rc = 0;
+    }
+  else
+    {
+      TerminateThread (thread_hnd, 1);
+      rc = 1;
     }
+
+  CloseHandle (thread_hnd); /* clear-up after TerminateThread() */
   thread_hnd = NULL;
-  return exitCode == STILL_ACTIVE;
+  return rc;
 }