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;
79 /* Emulation of Unix sleep. */
82 sleep (unsigned seconds)
84 return SleepEx (1000 * seconds, TRUE) ? 0U : 1000 * seconds;
89 /* Emulation of Unix usleep(). This has a granularity of
90 milliseconds, but that's ok because:
92 a) Wget is only using it with milliseconds [not anymore, but b)
95 b) You can't rely on usleep's granularity anyway. If a caller
96 expects usleep to respect every microsecond, he's in for a
100 usleep (unsigned long usec)
102 SleepEx (usec / 1000, TRUE);
105 #endif /* HAVE_USLEEP */
108 windows_main_junk (int *argc, char **argv, char **exec_name)
112 /* Remove .EXE from filename if it has one. */
113 *exec_name = xstrdup (*exec_name);
114 p = strrchr (*exec_name, '.');
126 set_sleep_mode (pwr_mode);
133 log_request_redirect_output ("CTRL+Break");
137 fork_to_background (void)
139 /* Whether we arrange our own version of opt.lfilename here. */
144 opt.lfilename = unique_name (DEFAULT_LOGFILE, 0);
147 printf (_("Continuing in background.\n"));
149 printf (_("Output will be written to `%s'.\n"), opt.lfilename);
157 ws_handler (DWORD dwEvent)
164 #ifdef CTRLBREAK_BACKGND
165 case CTRL_BREAK_EVENT:
167 fork_to_background ();
169 case CTRL_SHUTDOWN_EVENT:
170 case CTRL_CLOSE_EVENT:
171 case CTRL_LOGOFF_EVENT:
179 static char *title_buf = NULL;
180 static char *curr_url = NULL;
181 static int num_urls = 0;
184 ws_changetitle (const char *url, int nurl)
194 title_buf = (char *)xmalloc (strlen (url) + 20);
195 curr_url = xstrdup(url);
196 sprintf(title_buf, "Wget %s%s", url, nurl == 1 ? "" : " ...");
197 SetConsoleTitle(title_buf);
201 ws_percenttitle (double percent)
203 if (num_urls == 1 && title_buf && curr_url && fabs(percent) <= 100.0)
205 sprintf (title_buf, "Wget [%.0f%%] %s", percent, curr_url);
206 SetConsoleTitle (title_buf);
213 static char *wspathsave = NULL;
214 char buffer[MAX_PATH];
222 if (GetModuleFileName (NULL, buffer, MAX_PATH) &&
223 (ptr = strrchr (buffer, PATH_SEPARATOR)) != NULL)
226 wspathsave = xstrdup (buffer);
234 ws_help (const char *name)
236 char *mypath = ws_mypath ();
241 char *buf = (char *)alloca (strlen (mypath) + strlen (name) + 4 + 1);
242 sprintf (buf, "%s%s.HLP", mypath, name);
243 if (stat (buf, &sbuf) == 0)
245 printf (_("Starting WinHelp %s\n"), buf);
246 WinHelp (NULL, buf, HELP_INDEX, 0);
250 printf ("%s: %s\n", buf, strerror (errno));
263 if (GetVersionEx (&os) == TRUE
264 && os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
267 requested = MAKEWORD (1, 1);
268 err = WSAStartup (requested, &data);
272 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
277 if (data.wVersion < requested)
279 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
285 pwr_mode = set_sleep_mode (0);
286 SetConsoleCtrlHandler (ws_handler, TRUE);
289 /* Replacement utime function for buggy Borland C++Builder 5.5 compiler.
290 (The Borland utime function only works on Windows NT.) */
292 #ifdef HACK_BCC_UTIME_BUG
294 borland_utime (const char *path, const struct utimbuf *times)
301 if ((fd = open (path, O_RDWR)) < 0)
304 ptr_tm = localtime (×->modtime);
305 ft.ft_tsec = ptr_tm->tm_sec >> 1;
306 ft.ft_min = ptr_tm->tm_min;
307 ft.ft_hour = ptr_tm->tm_hour;
308 ft.ft_day = ptr_tm->tm_mday;
309 ft.ft_month = ptr_tm->tm_mon + 1;
310 ft.ft_year = ptr_tm->tm_year - 80;
311 res = setftime (fd, &ft);
318 * Prevent Windows entering sleep/hibernation-mode while wget is doing
319 * a lengthy transfer. Windows does by default not consider network
320 * activity in console-programs as activity ! Works on Win-98/ME/2K
324 set_sleep_mode (DWORD mode)
326 HMODULE mod = LoadLibrary ("kernel32.dll");
327 DWORD (WINAPI *_SetThreadExecutionState) (DWORD) = NULL;
328 DWORD rc = (DWORD)-1;
331 (void *)_SetThreadExecutionState
332 = GetProcAddress ((HINSTANCE)mod, "SetThreadExecutionState");
334 if (_SetThreadExecutionState)
336 if (mode == 0) /* first time */
337 mode = (ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
338 rc = (*_SetThreadExecutionState) (mode);
342 DEBUGP (("set_sleep_mode(): mode 0x%08lX, rc 0x%08lX\n", mode, rc));
346 /* run_with_timeout Windows implementation. */
348 /* Stack size 0 uses default thread stack-size (reserve+commit).
349 * Determined by what's in the PE header.
351 #define THREAD_STACK_SIZE 0
354 void (*fun) (void *);
359 /* The callback that runs FUN(ARG) in a separate thread. This
360 function exists for two reasons: a) to not require FUN to be
361 declared WINAPI/__stdcall[1], and b) to retrieve Winsock errors,
362 which are per-thread. The latter is useful when FUN calls Winsock
363 functions, which is how run_with_timeout is used in Wget.
365 [1] MSVC can use __fastcall globally (cl /Gr) and on Watcom this is
366 the default (wcc386 -3r). */
369 thread_helper (void *arg)
371 struct thread_data *td = (struct thread_data *) arg;
373 /* Initialize Winsock error to what it was in the parent. That way
374 the subsequent call to WSAGetLastError will return the same value
375 if td->fun doesn't change Winsock error state. */
376 WSASetLastError (td->ws_error);
380 /* Return Winsock error to the caller, in case FUN ran Winsock
382 td->ws_error = WSAGetLastError ();
386 /* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
387 seconds. Returns non-zero if the function was interrupted with a
388 timeout, zero otherwise.
390 This works by running FUN in a separate thread and terminating the
391 thread if it doesn't finish in the specified time. */
394 run_with_timeout (double seconds, void (*fun) (void *), void *arg)
396 static HANDLE thread_hnd = NULL;
397 struct thread_data thread_arg;
401 DEBUGP (("seconds %.2f, ", seconds));
410 /* Should never happen, but test for recursivety anyway */
411 assert (thread_hnd == NULL);
413 thread_arg.fun = fun;
414 thread_arg.arg = arg;
415 thread_arg.ws_error = WSAGetLastError ();
416 thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE, thread_helper,
417 &thread_arg, 0, &thread_id);
420 DEBUGP (("CreateThread() failed; %s\n", strerror (GetLastError ())));
421 goto blocking_fallback;
424 if (WaitForSingleObject (thread_hnd, (DWORD)(1000 * seconds))
427 /* Propagate error state (which is per-thread) to this thread,
428 so the caller can inspect it. */
429 WSASetLastError (thread_arg.ws_error);
430 DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
435 TerminateThread (thread_hnd, 1);
439 CloseHandle (thread_hnd); /* clear-up after TerminateThread() */