1 /* mswindows.c -- Windows-specific support
2 Copyright (C) 1995, 1996, 1997, 1998, 2004
3 Free Software Foundation, Inc.
5 This file is part of GNU Wget.
7 GNU Wget is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GNU Wget is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Wget; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 In addition, as a special exception, the Free Software Foundation
22 gives permission to link the code of its release of Wget with the
23 OpenSSL project's "OpenSSL" library (or with modified versions of it
24 that use the same license as the "OpenSSL" library), and distribute
25 the linked executables. You must obey the GNU General Public License
26 in all respects for all of the code used other than "OpenSSL". If you
27 modify this file, you may extend this exception to your version of the
28 file, but you are not obligated to do so. If you do not wish to do
29 so, delete this exception statement from your version. */
31 /* #### Someone please document what these functions do! */
42 #ifdef HACK_BCC_UTIME_BUG
48 # ifdef HAVE_SYS_UTIME_H
49 # include <sys/utime.h>
61 #ifndef ES_SYSTEM_REQUIRED
62 #define ES_SYSTEM_REQUIRED 0x00000001
66 #define ES_CONTINUOUS 0x80000000
70 /* Defined in log.c. */
71 void log_request_redirect_output PARAMS ((const char *));
73 /* Windows version of xsleep in utils.c. */
76 xsleep (double seconds)
81 /* Explained in utils.c. */
83 seconds -= (long) seconds;
85 usleep (seconds * 1000000L);
86 #else /* not HAVE_USLEEP */
87 SleepEx (seconds * 1000, FALSE);
88 #endif /* not HAVE_USLEEP */
92 windows_main_junk (int *argc, char **argv, char **exec_name)
96 /* Remove .EXE from filename if it has one. */
97 *exec_name = xstrdup (*exec_name);
98 p = strrchr (*exec_name, '.');
110 ws_hangup (const char *reason)
112 /* Whether we arrange our own version of opt.lfilename here. */
117 opt.lfilename = unique_name (DEFAULT_LOGFILE, 0);
120 printf (_("Continuing in background.\n"));
122 printf (_("Output will be written to `%s'.\n"), opt.lfilename);
124 log_request_redirect_output (reason);
126 /* Detach process from the current console. Under Windows 9x, if we
127 were launched from a 16-bit process (which is usually the case;
128 command.com is 16-bit) the parent process should resume right away.
129 Under NT or if launched from a 32-process under 9x, this is a futile
130 gesture as the parent will wait for us to terminate before resuming. */
135 fork_to_background (void)
141 ws_handler (DWORD dwEvent)
147 ws_hangup ("CTRL+C");
150 #ifdef CTRLBREAK_BACKGND
151 case CTRL_BREAK_EVENT:
152 ws_hangup ("CTRL+Break");
160 static char *title_buf = NULL;
161 static char *curr_url = NULL;
162 static int old_percentage = -1;
164 /* Updates the console title with the URL of the current file being
167 ws_changetitle (const char *url)
169 xfree_null (title_buf);
170 xfree_null (curr_url);
171 title_buf = (char *)xmalloc (strlen (url) + 20);
172 curr_url = xstrdup (url);
174 sprintf (title_buf, "Wget %s", curr_url);
175 SetConsoleTitle (title_buf);
178 /* Updates the console title with the percentage of the current file
181 ws_percenttitle (double percentage_float)
185 if (!title_buf || !curr_url)
188 percentage = (int) percentage_float;
190 /* Clamp percentage value. */
193 if (percentage > 100)
196 /* Only update the title when the percentage has changed. */
197 if (percentage == old_percentage)
200 old_percentage = percentage;
202 sprintf (title_buf, "Wget [%d%%] %s", percentage, curr_url);
203 SetConsoleTitle (title_buf);
206 /* Returns a pointer to the fully qualified name of the directory that
207 contains the Wget binary (wget.exe). The returned path does not have a
208 trailing path separator. Returns NULL on failure. */
212 static char *wspathsave = NULL;
216 char buf[MAX_PATH + 1];
220 len = GetModuleFileName (GetModuleHandle (NULL), buf, sizeof (buf));
221 if (!len || (len >= sizeof (buf)))
224 p = strrchr (buf, PATH_SEPARATOR);
229 wspathsave = xstrdup (buf);
235 /* Prevent Windows entering sleep/hibernation-mode while Wget is doing
236 a lengthy transfer. Windows does not, by default, consider network
237 activity in console-programs as activity! Works on Win-98/ME/2K
240 set_sleep_mode (void)
242 typedef DWORD (WINAPI *func_t) (DWORD);
243 func_t set_exec_state;
246 (func_t) GetProcAddress (GetModuleHandle ("KERNEL32.DLL"),
247 "SetThreadExecutionState");
250 set_exec_state (ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
253 /* Perform Windows specific initialization. */
261 requested = MAKEWORD (1, 1);
262 err = WSAStartup (requested, &data);
265 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
270 if (data.wVersion < requested)
272 fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
280 SetConsoleCtrlHandler (ws_handler, TRUE);
283 /* Replacement utime function for buggy Borland C++Builder 5.5 compiler.
284 (The Borland utime function only works on Windows NT.) */
286 #ifdef HACK_BCC_UTIME_BUG
288 borland_utime (const char *path, const struct utimbuf *times)
295 if ((fd = open (path, O_RDWR)) < 0)
298 ptr_tm = localtime (×->modtime);
299 ft.ft_tsec = ptr_tm->tm_sec >> 1;
300 ft.ft_min = ptr_tm->tm_min;
301 ft.ft_hour = ptr_tm->tm_hour;
302 ft.ft_day = ptr_tm->tm_mday;
303 ft.ft_month = ptr_tm->tm_mon + 1;
304 ft.ft_year = ptr_tm->tm_year - 80;
305 res = setftime (fd, &ft);
311 /* run_with_timeout Windows implementation. */
313 /* Stack size 0 uses default thread stack-size (reserve+commit).
314 Determined by what's in the PE header. */
315 #define THREAD_STACK_SIZE 0
319 void (*fun) (void *);
324 /* The callback that runs FUN(ARG) in a separate thread. This
325 function exists for two reasons: a) to not require FUN to be
326 declared WINAPI/__stdcall[1], and b) to retrieve Winsock errors,
327 which are per-thread. The latter is useful when FUN calls Winsock
328 functions, which is how run_with_timeout is used in Wget.
330 [1] MSVC can use __fastcall globally (cl /Gr) and on Watcom this is
331 the default (wcc386 -3r). */
334 thread_helper (void *arg)
336 struct thread_data *td = (struct thread_data *) arg;
338 /* Initialize Winsock error to what it was in the parent. That way
339 the subsequent call to WSAGetLastError will return the same value
340 if td->fun doesn't change Winsock error state. */
341 WSASetLastError (td->ws_error);
345 /* Return Winsock error to the caller, in case FUN ran Winsock
347 td->ws_error = WSAGetLastError ();
351 /* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
352 seconds. Returns non-zero if the function was interrupted with a
353 timeout, zero otherwise.
355 This works by running FUN in a separate thread and terminating the
356 thread if it doesn't finish in the specified time. */
359 run_with_timeout (double seconds, void (*fun) (void *), void *arg)
361 static HANDLE thread_hnd = NULL;
362 struct thread_data thread_arg;
366 DEBUGP (("seconds %.2f, ", seconds));
375 /* Should never happen, but test for recursivety anyway. */
376 assert (thread_hnd == NULL);
378 thread_arg.fun = fun;
379 thread_arg.arg = arg;
380 thread_arg.ws_error = WSAGetLastError ();
381 thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE, thread_helper,
382 &thread_arg, 0, &thread_id);
385 DEBUGP (("CreateThread() failed; %s\n", strerror (GetLastError ())));
386 goto blocking_fallback;
389 if (WaitForSingleObject (thread_hnd, (DWORD)(1000 * seconds))
392 /* Propagate error state (which is per-thread) to this thread,
393 so the caller can inspect it. */
394 WSASetLastError (thread_arg.ws_error);
395 DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
400 TerminateThread (thread_hnd, 1);
404 CloseHandle (thread_hnd); /* Clear-up after TerminateThread(). */