1 /* mswindows.c -- Windows-specific support
2 Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
4 This file is part of GNU Wget.
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables. You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL". If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so. If you do not wish to do
28 so, delete this exception statement from your version. */
30 /* #### Someone please document what these functions do! */
41 #ifdef HACK_BCC_UTIME_BUG
47 # ifdef HAVE_SYS_UTIME_H
48 # include <sys/utime.h>
60 #ifndef ES_SYSTEM_REQUIRED
61 #define ES_SYSTEM_REQUIRED 0x00000001
65 #define ES_CONTINUOUS 0x80000000
69 /* Defined in log.c. */
70 void log_request_redirect_output PARAMS ((const char *));
72 static DWORD set_sleep_mode (DWORD mode);
74 static DWORD pwr_mode = 0;
75 static int windows_nt_p;
77 /* Windows version of xsleep in utils.c. */
80 xsleep (double seconds)
85 /* Explained in utils.c. */
87 seconds -= (long) seconds;
89 usleep (seconds * 1000000L);
90 #else /* not HAVE_USLEEP */
91 SleepEx (seconds * 1000, FALSE);
92 #endif /* not HAVE_USLEEP */
96 windows_main_junk (int *argc, char **argv, char **exec_name)
100 /* Remove .EXE from filename if it has one. */
101 *exec_name = xstrdup (*exec_name);
102 p = strrchr (*exec_name, '.');
114 set_sleep_mode (pwr_mode);
121 log_request_redirect_output ("CTRL+Break");
125 fork_to_background (void)
127 /* Whether we arrange our own version of opt.lfilename here. */
132 opt.lfilename = unique_name (DEFAULT_LOGFILE, 0);
135 printf (_("Continuing in background.\n"));
137 printf (_("Output will be written to `%s'.\n"), opt.lfilename);
145 ws_handler (DWORD dwEvent)
152 #ifdef CTRLBREAK_BACKGND
153 case CTRL_BREAK_EVENT:
155 fork_to_background ();
157 case CTRL_SHUTDOWN_EVENT:
158 case CTRL_CLOSE_EVENT:
159 case CTRL_LOGOFF_EVENT:
167 static char *title_buf = NULL;
168 static char *curr_url = NULL;
169 static int num_urls = 0;
172 ws_changetitle (const char *url, int nurl)
182 title_buf = (char *)xmalloc (strlen (url) + 20);
183 curr_url = xstrdup(url);
184 sprintf(title_buf, "Wget %s%s", url, nurl == 1 ? "" : " ...");
185 SetConsoleTitle(title_buf);
189 ws_percenttitle (double percent)
191 if (num_urls == 1 && title_buf && curr_url && fabs(percent) <= 100.0)
193 sprintf (title_buf, "Wget [%.0f%%] %s", percent, curr_url);
194 SetConsoleTitle (title_buf);
201 static char *wspathsave = NULL;
202 char buffer[MAX_PATH];
210 if (GetModuleFileName (NULL, buffer, MAX_PATH) &&
211 (ptr = strrchr (buffer, PATH_SEPARATOR)) != NULL)
214 wspathsave = xstrdup (buffer);
222 ws_help (const char *name)
224 char *mypath = ws_mypath ();
229 char *buf = (char *)alloca (strlen (mypath) + strlen (name) + 4 + 1);
230 sprintf (buf, "%s%s.HLP", mypath, name);
231 if (stat (buf, &sbuf) == 0)
233 printf (_("Starting WinHelp %s\n"), buf);
234 WinHelp (NULL, buf, HELP_INDEX, 0);
238 printf ("%s: %s\n", buf, strerror (errno));
251 if (GetVersionEx (&os) == TRUE
252 && os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
255 requested = MAKEWORD (1, 1);
256 err = WSAStartup (requested, &data);
260 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
265 if (data.wVersion < requested)
267 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
273 pwr_mode = set_sleep_mode (0);
274 SetConsoleCtrlHandler (ws_handler, TRUE);
277 /* Replacement utime function for buggy Borland C++Builder 5.5 compiler.
278 (The Borland utime function only works on Windows NT.) */
280 #ifdef HACK_BCC_UTIME_BUG
282 borland_utime (const char *path, const struct utimbuf *times)
289 if ((fd = open (path, O_RDWR)) < 0)
292 ptr_tm = localtime (×->modtime);
293 ft.ft_tsec = ptr_tm->tm_sec >> 1;
294 ft.ft_min = ptr_tm->tm_min;
295 ft.ft_hour = ptr_tm->tm_hour;
296 ft.ft_day = ptr_tm->tm_mday;
297 ft.ft_month = ptr_tm->tm_mon + 1;
298 ft.ft_year = ptr_tm->tm_year - 80;
299 res = setftime (fd, &ft);
306 * Prevent Windows entering sleep/hibernation-mode while wget is doing
307 * a lengthy transfer. Windows does by default not consider network
308 * activity in console-programs as activity ! Works on Win-98/ME/2K
312 set_sleep_mode (DWORD mode)
314 HMODULE mod = LoadLibrary ("kernel32.dll");
315 DWORD (WINAPI *_SetThreadExecutionState) (DWORD) = NULL;
316 DWORD rc = (DWORD)-1;
319 (void *)_SetThreadExecutionState
320 = GetProcAddress ((HINSTANCE)mod, "SetThreadExecutionState");
322 if (_SetThreadExecutionState)
324 if (mode == 0) /* first time */
325 mode = (ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
326 rc = (*_SetThreadExecutionState) (mode);
330 DEBUGP (("set_sleep_mode(): mode 0x%08lX, rc 0x%08lX\n", mode, rc));
334 /* run_with_timeout Windows implementation. */
336 /* Stack size 0 uses default thread stack-size (reserve+commit).
337 * Determined by what's in the PE header.
339 #define THREAD_STACK_SIZE 0
342 void (*fun) (void *);
347 /* The callback that runs FUN(ARG) in a separate thread. This
348 function exists for two reasons: a) to not require FUN to be
349 declared WINAPI/__stdcall[1], and b) to retrieve Winsock errors,
350 which are per-thread. The latter is useful when FUN calls Winsock
351 functions, which is how run_with_timeout is used in Wget.
353 [1] MSVC can use __fastcall globally (cl /Gr) and on Watcom this is
354 the default (wcc386 -3r). */
357 thread_helper (void *arg)
359 struct thread_data *td = (struct thread_data *) arg;
361 /* Initialize Winsock error to what it was in the parent. That way
362 the subsequent call to WSAGetLastError will return the same value
363 if td->fun doesn't change Winsock error state. */
364 WSASetLastError (td->ws_error);
368 /* Return Winsock error to the caller, in case FUN ran Winsock
370 td->ws_error = WSAGetLastError ();
374 /* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
375 seconds. Returns non-zero if the function was interrupted with a
376 timeout, zero otherwise.
378 This works by running FUN in a separate thread and terminating the
379 thread if it doesn't finish in the specified time. */
382 run_with_timeout (double seconds, void (*fun) (void *), void *arg)
384 static HANDLE thread_hnd = NULL;
385 struct thread_data thread_arg;
389 DEBUGP (("seconds %.2f, ", seconds));
398 /* Should never happen, but test for recursivety anyway */
399 assert (thread_hnd == NULL);
401 thread_arg.fun = fun;
402 thread_arg.arg = arg;
403 thread_arg.ws_error = WSAGetLastError ();
404 thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE, thread_helper,
405 &thread_arg, 0, &thread_id);
408 DEBUGP (("CreateThread() failed; %s\n", strerror (GetLastError ())));
409 goto blocking_fallback;
412 if (WaitForSingleObject (thread_hnd, (DWORD)(1000 * seconds))
415 /* Propagate error state (which is per-thread) to this thread,
416 so the caller can inspect it. */
417 WSASetLastError (thread_arg.ws_error);
418 DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
423 TerminateThread (thread_hnd, 1);
427 CloseHandle (thread_hnd); /* clear-up after TerminateThread() */