update changelog
[alioth/cvs.git] / windows-NT / woe32.c
1 /*
2  * Copyright (C) 2003-2005 The Free Software Foundation, Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14
15 /*
16  * woe32.c
17  * - utility functions for cvs under win32
18  *
19  */
20
21 #include "config.h"
22
23 #include "woe32.h"
24
25 #include <stdio.h>
26 #include <assert.h>
27 #include <errno.h>
28
29 #include <sys/socket.h>  /* This does: #include <windows.h> */
30
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <xalloc.h>
34
35
36
37 /* #define SYSTEM_CLEANUP woe32_cleanup */
38 void
39 woe32_cleanup (void)
40 {
41     if (WSACleanup ())
42     {
43 #ifdef SERVER_ACTIVE
44         if (server_active || error_use_protocol)
45             /* FIXME: how are we supposed to report errors?  As of now
46                (Sep 98), error() can in turn call us (if it is out of
47                memory) and in general is built on top of lots of
48                stuff.  */
49             ;
50         else
51 #endif
52             fprintf (stderr, "cvs: cannot WSACleanup: %s\n",
53                      sock_strerror (WSAGetLastError ()));
54     }
55 }
56
57
58
59 /*============================================================================*/
60 /*
61 How Microsoft does fd_set in Windows 2000 and Visual C++ 6.0:
62
63         * Select uses arrays of SOCKETs.  These macros manipulate such
64         * arrays.  FD_SETSIZE may be defined by the user before including
65         * this file, but the default here should be >= 64.
66         *
67         * CAVEAT IMPLEMENTOR and USER: THESE MACROS AND TYPES MUST BE
68         * INCLUDED IN WINSOCK2.H EXACTLY AS SHOWN HERE.
69
70         #ifndef FD_SETSIZE
71         #define FD_SETSIZE      64
72         #endif
73
74         typedef struct fd_set {
75                 u_int   fd_count;
76                 SOCKET  fd_array[FD_SETSIZE];
77         } fd_set;
78
79 Microsoft packs all handles between fd_array[0] and fd_array[fd_count-1]
80 */
81
82 typedef struct
83 {
84         int     is_ready;
85         SOCKET  crt;
86         DWORD   type;
87         union
88         {
89                 long    osf;
90                 HANDLE  w32;
91         };
92 } woe32_handle_set;
93
94 typedef struct
95 {
96         u_int ready_count, used_count;
97         woe32_handle_set handle[ FD_SETSIZE ];
98 } woe32_select_set;
99
100 static int woe32_select_set_fini (woe32_select_set * w32_set, fd_set * crt_set)
101 {
102         FD_ZERO (crt_set);
103
104         if (w32_set->ready_count) 
105         {
106                 u_int index;
107                 woe32_handle_set * handle;
108
109                 index = 0;
110                 handle = w32_set->handle;
111                 while (index < w32_set->used_count)
112                 {
113                         if (handle->is_ready)
114                         {
115                                 FD_SET (handle->crt, crt_set);
116                         }
117
118                         ++index;
119                         ++handle;
120                 }
121         }
122
123         return w32_set->ready_count;
124 }
125
126 static int woe32_select_set_init (woe32_select_set * w32_set, fd_set * crt_set)
127 {
128         u_int index;
129         DWORD dwBytesAvail;
130         woe32_handle_set * handle;
131                 
132         w32_set->ready_count = w32_set->used_count = index = 0;
133         handle = w32_set->handle;
134
135         if (crt_set) while (index < crt_set->fd_count)
136         {
137                 handle->crt = crt_set->fd_array[index];
138
139                 handle->osf = _get_osfhandle (handle->crt);
140                 if (handle->w32 == INVALID_HANDLE_VALUE)
141                 {
142                         errno = EBADF;
143                         return -1;
144                 }
145
146                 handle->type = GetFileType (handle->w32);
147                 switch (handle->type)
148                 {
149                 case FILE_TYPE_DISK:
150                         w32_set->ready_count += handle->is_ready = 1;
151                         break;
152
153                 case FILE_TYPE_PIPE:
154                         if ( PeekNamedPipe (handle->w32, NULL, 0, NULL, &dwBytesAvail, NULL) )
155                         {
156                                 w32_set->ready_count += handle->is_ready = dwBytesAvail > 0;
157                         }
158                         else
159                         {
160                                 errno = EBADF;
161                                 return -1;
162                         }
163                         break;
164
165                 case FILE_TYPE_CHAR:
166                 case FILE_TYPE_REMOTE:
167                 case FILE_TYPE_UNKNOWN:
168                 default:
169                         errno = EBADF;
170                         return -1;
171                 }
172
173                 ++index;
174                 ++handle;
175         }
176         w32_set->used_count = index;
177
178         while (index < FD_SETSIZE)
179         {
180                 handle->crt = -1;
181
182                 handle->w32 = INVALID_HANDLE_VALUE;
183
184                 handle->type = FILE_TYPE_UNKNOWN;
185
186                 handle->is_ready = 0;
187
188                 ++index;
189                 ++handle;
190         }
191
192         return w32_set->ready_count;
193 }
194
195 static int woe32_select_set_wait (woe32_select_set * w32_set)
196 {
197         char buffer[ 8 ];
198         DWORD dwBytesRead;
199
200         /* set contains only non-ready pipes */
201         if (w32_set->used_count != 1)
202         {
203                 errno = EINVAL;
204                 return -1;
205         }
206
207         if (! ReadFile (w32_set->handle[0].w32, buffer, 0, &dwBytesRead, NULL))
208         {
209                 errno = EBADF;
210                 return -1;
211         }
212
213         return w32_set->handle[0].is_ready = 1;
214 }
215
216 /* #define fd_select woe32_fd_select */
217 #undef fd_select
218 int woe32_fd_select (   int nfds,
219                                                 struct fd_set * readfds,
220                                                 struct fd_set * writefds,
221                                                 struct fd_set * errorfds,
222                                                 struct timeval * timeout)
223 {
224         int ready_fds;
225         woe32_select_set woe32_rset;
226
227         /* we don't support these for now */
228         assert(writefds != NULL);
229         assert(errorfds != NULL);
230         assert(timeout != NULL);
231
232         /* Windows doesn't care but POSIX says it does */
233         if (nfds < 0 || nfds > FD_SETSIZE)
234         {
235                 errno = EINVAL;
236                 return -1;
237         }
238
239         ready_fds = woe32_select_set_init (&woe32_rset, readfds);
240         if (! ready_fds)
241         {
242                 ready_fds = woe32_select_set_wait (&woe32_rset);
243         }
244
245         if (ready_fds >= 0)
246         {
247                 woe32_select_set_fini (&woe32_rset, readfds);
248         }
249
250         return ready_fds;
251 }
252 /*============================================================================*/
253
254
255
256 char *
257 woe32_getlogin (void)
258 {
259     static char name[256];
260     DWORD dw = sizeof (name);
261     GetUserName (name, &dw);
262     if (name[0] == '\0')
263         return NULL;
264     else
265         return name;
266 }
267
268
269
270 /* #define SYSTEM_INITIALIZE(pargc,pargv) woe32_init_winsock() */
271 void
272 woe32_init_winsock (void)
273 {
274     WSADATA data;
275
276     if (WSAStartup (MAKEWORD (1, 1), &data))
277     {
278         fprintf (stderr, "cvs: unable to initialize winsock\n");
279         exit (1);
280     }
281 }
282
283
284
285 char *
286 woe32_home_dir (void)
287 {
288     static char *home_dir = NULL;
289     char *home_drive, *home_path;
290
291     if (home_dir)
292         return home_dir;
293     
294     if ((home_drive = getenv ("HOMEDRIVE")) && (home_path = getenv ("HOMEPATH")))
295     {
296         const char NUL = '\0';
297         size_t home_drive_len, home_path_len;
298
299         home_drive_len = strlen (home_drive);
300         home_path_len  = strlen (home_path);
301
302         home_dir = xmalloc (home_drive_len + home_path_len + sizeof NUL);
303
304         memcpy (home_dir,                  home_drive, home_drive_len );
305         memcpy (home_dir + home_drive_len, home_path,  home_path_len  );
306         home_dir[ home_drive_len + home_path_len ] = NUL;
307
308         return home_dir;
309     }
310
311     return NULL;
312 }
313
314
315
316 /* #define nanosleep woe32_nanosleep */
317 int
318 woe32_nanosleep (const struct timespec *requested_delay,
319                        struct timespec *remaining_delay)
320 {
321     const useconds_t one_second = 1000000;
322     const useconds_t nano_per_micro = 1000;
323     useconds_t micro_delay;
324
325     micro_delay = requested_delay->tv_sec * one_second
326                 + ( requested_delay->tv_nsec + nano_per_micro - 1 ) / nano_per_micro
327                 ;
328
329     return usleep (micro_delay);
330 }
331
332
333
334 char *
335 woe32_shell (void)
336 {
337     char *shell;
338
339     shell = getenv ("ComSpec");
340
341     if (shell == NULL)
342     {
343         /* Windows always sets ComSpec, the user is messing with us */
344         const char *os;
345
346         if ((os = getenv ("OS")) && strcmp (os, "Windows_NT"))
347             /* Windows NT, Windows 2000, Windows XP, Windows 2003 */
348             shell = "cmd.exe";
349         else
350             /* Windows 95, Windows 98, Windows Me */
351             shell = "command.com";
352     }
353
354     return shell;
355 }