]> git.pond.sub.org Git - empserver/commitdiff
(w32_getpw, w32_socket, w32_connect, w32_recv, w32_send,
authorRon Koenderink <rkoenderink@yahoo.ca>
Tue, 11 Dec 2007 22:00:25 +0000 (22:00 +0000)
committerRon Koenderink <rkoenderink@yahoo.ca>
Tue, 11 Dec 2007 22:00:25 +0000 (22:00 +0000)
w32_writev_socket, w32_close_socket, getpass, w32_openfd,
w32_openhandle, w32_readv_handle, w32_close_handle,
sysdep_init, sysdep_stdin_init, w32_select, w32_signal_handler,
sigaction, stdin_read_thread, w32_ring_from_file_to_bounce_buf)
[_WIN32]: New w32 equivalent functions for POSIX functions.
(recvline, sendcmd, tcp_connect, hostconnect, getpass,
main, intr, play, ring_to_file, ring_from_file, doexecute,
doredir) [_WIN32]: Use new WIN32 equivalent functions.
(main) [_WIN32]: Add sysdep_init() to support system dependent
initialization for equivalence functions.
(play) [_WIN32]: Add sysdef_stdin_init() to support system
dependent initialization for reading stdin.
(recv_input, play) [_WIN32]: Replace the calls to ring_to_file()
and select() with WIN32 specific enhanced versions.

Makefile.in: update dependencies with new files.
Make.mk: Add using of getopt.c and getopt.h
from src/lib/w32 directory.  Add getopt.c and getopt.h
to tar for client.

12 files changed:
Make.mk
src/client/Makefile.in
src/client/expect.c
src/client/host.c
src/client/login.c
src/client/main.c
src/client/misc.h
src/client/play.c
src/client/ringbuf.c
src/client/servcmd.c
src/client/sysdep_w32.c [new file with mode: 0644]
src/client/sysdep_w32.h [new file with mode: 0644]

diff --git a/Make.mk b/Make.mk
index be6130245bdc97c136f75997d67ad199cd053c3e..9b838683f618178955576d7cc7ec37bea68a3e6d 100644 (file)
--- a/Make.mk
+++ b/Make.mk
@@ -261,7 +261,7 @@ info.html/%.html: info/%.t
 $(server): $(filter src/server/% src/lib/as/% src/lib/commands/% src/lib/player/% src/lib/subs/% src/lib/update/%, $(obj)) $(empth_obj) $(libs) $(empth_lib)
        $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
 
-$(client): $(filter src/client/%, $(obj)) src/lib/global/version.o
+$(client): $(filter src/client/%, $(obj)) src/lib/global/version.o src/lib/w32/getopt.o
        $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
 
 $(util): $(libs)
@@ -332,6 +332,7 @@ dist-client: $(cli_distgen)
                $(notdir $(filter src/client/%, $(src)) $(cli_distgen)) \
        -C $(srcdir)/include proto.h version.h                          \
        -C $(srcdir)/src/lib/global version.c                           \
+       -C $(srcdir)/src/lib/w32 getopt.h getopt.c                      \
        -C $(srcdir)/man empire.6                                       \
        -C $(srcdir) COPYING INSTALL install-sh
 
index 6c8b0a0533cad04290a8e3f8fbdb7b6ff7a818b3..0d9d2ca4efa4e68db0d7ba7ab0ac6188f879a178 100644 (file)
@@ -79,15 +79,16 @@ uninstall:
        rm $(mandir)/man6/empire.6
 
 # FIXME generate from .d
-expect.$O: misc.h
-host.$O: misc.h
+expect.$O: misc.h sysdep_w32.h
+host.$O: misc.h sysdep_w32.h
 linebuf.$O: linebuf.h
-login.$O: misc.h proto.h
-main.$O: misc.h version.h
-play.$O: linebuf.h misc.h proto.h ringbuf.h secure.h
+login.$O: misc.h proto.h sysdep_w32.h
+main.$O: misc.h version.h sysdep_w32.h
+play.$O: linebuf.h misc.h proto.h ringbuf.h secure.h sysdep_w32.h
 ringbuf.$O: ringbuf.h
 secure.$O: ringbuf.h secure.h
-servcmd.$O: misc.h proto.h secure.h
-termlib.$O: misc.h
+servcmd.$O: misc.h proto.h secure.h sysdep_w32.h
+sysdep_w32.$O: misc.h sysdep_w32.h
+termlib.$O: misc.h sysdep_w32.h
 version.$O: version.h
 $(obj): config.h
index 1c77707320ca322f7fc5dd3e28faeb392ae724d3..5ea380a057dc801829e2efff74c4baf60e0fb010 100644 (file)
 #endif
 #include "misc.h"
 
+#ifdef _WIN32
+#define recv(sock, buffer, buf_size, flags) \
+       w32_recv((sock), (buffer), (buf_size), (flags))
+#define read(sock, buffer, buf_size) \
+       w32_recv((sock), (buffer), (buf_size), 0)
+#define write(sock, buffer, buf_size) \
+       w32_send((sock), (buffer), (buf_size), 0)
+#endif
+
 int
 recvline(int s, char *buf)
 {
@@ -55,15 +64,10 @@ recvline(int s, char *buf)
     int cc;
 
     size = 1024;
-#ifndef _WIN32
     (void)alarm(30);
-#endif
     ptr = buf;
     n = recv(s, ptr, size, MSG_PEEK);
     if (n <= 0) {
-#ifdef _WIN32
-       errno = WSAGetLastError();
-#endif
        perror("recv");
        return 0;
     }
@@ -71,15 +75,8 @@ recvline(int s, char *buf)
     buf[n] = '\0';
     if ((p = strchr(ptr, '\n')) == NULL) {
        do {
-#ifndef _WIN32
            cc = read(s, ptr, n);
-#else
-           cc = recv(s, ptr, n, 0);
-#endif
            if (cc < 0) {
-#ifdef _WIN32
-               errno = WSAGetLastError();
-#endif
                perror("expect: read");
                return 0;
            }
@@ -89,9 +86,6 @@ recvline(int s, char *buf)
            }
            ptr += n;
            if ((n = recv(s, ptr, size, MSG_PEEK)) <= 0) {
-#ifdef _WIN32
-               errno = WSAGetLastError();
-#endif
                perror("recv");
                return 0;
            }
@@ -102,15 +96,8 @@ recvline(int s, char *buf)
        *p = 0;
     } else
        newline = 1 + p - ptr;
-#ifndef _WIN32
     cc = read(s, buf, newline);
-#else
-    cc = recv(s, buf, newline, 0);
-#endif
     if (cc < 0) {
-#ifdef _WIN32
-       errno = WSAGetLastError();
-#endif
        perror("expect: read #2");
        return 0;
     }
@@ -120,9 +107,7 @@ recvline(int s, char *buf)
        return 0;
     }
     buf[newline] = '\0';
-#ifndef _WIN32
     (void)alarm(0);
-#endif
     if (!isxdigit(buf[0]) || buf[1] != ' ') {
        fprintf(stderr, "Malformed line %s\n", buf);
        return 0;
@@ -146,15 +131,8 @@ sendcmd(int s, char *cmd, char *arg)
 
     (void)sprintf(buf, "%s %s\n", cmd, arg != NULL ? arg : "");
     len = strlen(buf);
-#ifndef _WIN32
     cc = write(s, buf, len);
-#else
-    cc = send(s, buf, len, 0);
-#endif
     if (cc < 0) {
-#ifdef _WIN32
-       errno = WSAGetLastError();
-#endif
        perror("sendcmd: write");
     }
     if (cc != len) {
index cb309721c1ea8aeb3cf8c10bf6690cb3a265714b..7429f45ab2761b44a9c2414f45444c722dd61d64 100644 (file)
@@ -48,8 +48,7 @@
 #include <netdb.h>
 #include <unistd.h>
 #else
-#include <winsock2.h>
-#include <ws2tcpip.h>
+#define close(fd) w32_close_socket((fd))
 #endif
 #include "misc.h"
 
@@ -83,11 +82,7 @@ tcp_connect(char *host, char *serv)
 
        if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)
            break;              /* success */
-#ifdef _WIN32
-       closesocket(sockfd);    /* ignore this one */
-#else
        close(sockfd);          /* ignore this one */
-#endif
     } while ((res = res->ai_next) != NULL);
 
     if (res == NULL) {         /* errno set from final connect() */
@@ -147,19 +142,11 @@ hostconnect(struct sockaddr_in *addr)
 
     s = socket(AF_INET, SOCK_STREAM, 0);
     if (s < 0) {
-#ifdef _WIN32
-       errno = WSAGetLastError();
-#endif
        return -1;
     }
     addr->sin_family = AF_INET;
     if (connect(s, (struct sockaddr *)addr, sizeof(*addr)) < 0) {
-#ifdef _WIN32
-       errno = WSAGetLastError();
-       (void)closesocket(s);
-#else
        (void)close(s);
-#endif
        return -1;
     }
     return s;
index 7fa41bdcee8ddea1a9703b0508f6d163f4d51178..695ac386009091f8d28e6881a299ca8f87bf6347 100644 (file)
@@ -89,21 +89,9 @@ login(int s, char *uname, char *cname, char *cpass,
        return 0;
     }
     if (cpass == NULL) {
-#ifndef _WIN32
        cpass = getpass("Your name? ");
        if (cpass == NULL || *cpass == 0)
            return 0;
-#else
-       printf("Note: This is echoed to the screen\n");
-       printf("Your name? ");
-       fflush(stdout);
-       cpass = fgets(tmp, sizeof(tmp), stdin);
-       if (cpass == NULL || *cpass == 0)
-           return 0;
-       len = strlen(cpass);
-       if (cname[len-1] == '\n')
-           cname[len-1] = 0;
-#endif
     }
     (void)printf("\n");
     (void)sendcmd(s, "pass", cpass);
index cd0f6fc25da333f2faac3908a65ba45ea9fcf46a..62c667ae5389c56714b6d7cd79254fbb56a270c4 100644 (file)
 
 #include <config.h>
 
+#ifndef _WIN32
 #include <pwd.h>
 #include <stdlib.h>
 #include <unistd.h>
+#endif
 #include "misc.h"
 #include "version.h"
 
+#ifdef _WIN32
+#define getuid() 0
+#define getpwuid(uid) ((uid), w32_getpw())
+#else
+#define sysdep_init() ((void)0)
+#endif
+
 static void
 print_usage(char *program_name)
 {
@@ -68,21 +77,6 @@ main(int argc, char **argv)
     char *host;
     char *port;
     int sock;
-#ifdef _WIN32
-    char unamebuf[128];
-#endif
-
-#ifdef _WIN32
-    /*
-     * stdout is unbuffered under Windows if connected to a character
-     * device, and putchar() screws up when printing multibyte strings
-     * bytewise to an unbuffered stream.  Switch stdout to line-
-     * buffered mode.  Unfortunately, ISO C allows implementations to
-     * screw that up, and of course Windows does.  Manual flushing
-     * after each prompt is required.
-     */
-    setvbuf(stdout, NULL, _IOLBF, 4096);
-#endif
 
     while ((opt = getopt(argc, argv, "2:kuhv")) != EOF) {
        switch (opt) {
@@ -124,7 +118,6 @@ main(int argc, char **argv)
        host = empirehost;
     uname = getenv("LOGNAME");
     if (uname == NULL) {
-#ifndef _WIN32
        struct passwd *pwd;
 
        pwd = getpwuid(getuid());
@@ -133,17 +126,6 @@ main(int argc, char **argv)
            exit(1);
        }
        uname = pwd->pw_name;
-#else
-       DWORD unamesize;
-
-       unamesize = sizeof(unamebuf);
-       if (GetUserName(unamebuf, &unamesize)) {
-           uname = unamebuf;
-           if ((unamesize <= 0 ) || (strlen(uname) <= 0))
-               uname = "nobody";
-       } else
-           uname = "nobody";
-#endif
     }
 
     getsose();
@@ -152,13 +134,7 @@ main(int argc, char **argv)
        exit(1);
     }
 
-#ifdef _WIN32
-    err = WSAStartup(MAKEWORD(2, 0), &WsaData);
-    if (err != 0) {
-       printf("WSAStartup Failed, error code %d\n", err);
-       exit(1);
-    }
-#endif
+    sysdep_init();
 
     sock = tcp_connect(host, port);
 
index 8cb8acd39278363f5edb2907638cba300acb5b35..2b6329471188e9b5aee33989df3bdd5e26d87c1e 100644 (file)
 
 #include <stdio.h>
 #ifdef _WIN32
-#include <windows.h>
+#include "sysdep_w32.h"
 #endif
 
 #define MAX(a, b) ((a) >= (b) ? (a) : (b))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
 
 extern char empirehost[];
 extern char empireport[];
@@ -50,13 +51,7 @@ extern FILE *auxfp;
 extern char *SO;
 extern char *SE;
 
-#ifdef _WIN32
-#define getsose() ((void)0)
-#define putso() ((void)0)
-#define putse() ((void)0)
-#define pclose _pclose
-#define popen _popen
-#else
+#ifndef _WIN32
 void getsose(void);
 void putso(void);
 void putse(void);
index 7cd4e5b5fb3267808ebb4c513a7cbad0630c94e0..9435f5079ebf3da04b34f8af77d04aa55055b83d 100644 (file)
@@ -29,6 +29,7 @@
  * 
  *  Known contributors to this file:
  *     Markus Armbruster, 2007
+ *     Ron Koenderink, 2007
  */
 
 #include <config.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
+#ifndef _WIN32
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
+#else
+#include <io.h>
+#endif
 #include "linebuf.h"
 #include "misc.h"
 #include "proto.h"
 #include "ringbuf.h"
 #include "secure.h"
 
+#ifdef _WIN32
+static CRITICAL_SECTION signal_critical_section;
+static LPCRITICAL_SECTION signal_critical_section_ptr = NULL;
+
+static unsigned char bounce_buf[RING_SIZE];
+/*
+ * Set bounce_empty to indicate bounce_buf is available for the stdin thread
+ * to use.
+ */
+static HANDLE bounce_empty;
+/*
+ * Set bounce_full to indicate bounce_buf is contains data from the
+ * stdin thread and is available for recv_input
+ */
+static HANDLE bounce_full;
+ /* Ctrl-C (SIGINT) was detected, generate EINTR for the w32_select() */
+static HANDLE ctrl_c_event;
+static int bounce_status, bounce_error;
+
+#define SIGPIPE -1
+static void (*ctrl_handler)(int sig) = { SIG_DFL };
+
+/*
+ * Ctrl-C handler for emulating the SIGINT in WIN32
+ */
+static BOOL WINAPI
+w32_signal_handler(DWORD ctrl_type)
+{
+    if (ctrl_type == CTRL_C_EVENT) {
+       EnterCriticalSection(signal_critical_section_ptr);
+       if (ctrl_handler != SIG_DFL) {
+           ctrl_handler(SIGINT);
+           LeaveCriticalSection(signal_critical_section_ptr);
+           SetEvent(ctrl_c_event);
+           return TRUE;
+       } else
+           LeaveCriticalSection(signal_critical_section_ptr);
+    }
+    return FALSE;
+}
+
+/*
+ * WIN32 equivalent for sigaction supports the following:
+ * set handler for SIGINT using WIN32 Ctrl-C handler
+ * reset handler SIGINT to SIG_DFL
+ * ignore SIGPIPE
+ */
+static int
+sigaction(int signal, struct sigaction *action, struct sigaction *oaction)
+{
+    assert(!oaction);
+    assert(action);
+    
+    if (signal == SIGPIPE)
+       assert(action->sa_handler == SIG_IGN);
+    else {
+       assert(signal == SIGINT && action->sa_handler != SIG_IGN);
+       if (ctrl_handler == action->sa_handler)
+           return 0;
+       if (signal_critical_section_ptr == NULL) {
+           signal_critical_section_ptr = &signal_critical_section;
+           InitializeCriticalSection(signal_critical_section_ptr);
+       }
+       EnterCriticalSection(signal_critical_section_ptr);
+       if (!SetConsoleCtrlHandler(w32_signal_handler,
+                                  action->sa_handler != SIG_DFL)) {
+           errno = GetLastError();
+           LeaveCriticalSection(signal_critical_section_ptr);
+           return -1;
+       }
+       ctrl_handler = action->sa_handler;
+       LeaveCriticalSection(signal_critical_section_ptr);
+    }
+    return 0;
+}
+
+/*
+ * Read the stdin in WIN32 environment
+ * WIN32 does not support select type function on console input
+ * so the client uses a separate thread to read input
+ */
+static DWORD WINAPI
+stdin_read_thread(LPVOID lpParam)
+{
+    for (;;) {
+       if (WaitForSingleObject(bounce_empty, INFINITE) != WAIT_OBJECT_0)
+           break;
+       bounce_status = _read(0, bounce_buf, sizeof(bounce_buf));
+       bounce_error = errno;
+       if (bounce_status == 0) {
+           if (_isatty(0)) {
+               SetEvent(bounce_empty);
+               continue;
+           } else
+               break;
+       }
+       SetEvent(bounce_full);
+    }
+    SetEvent(bounce_full);
+    return 0;
+}
+
+/*
+ * Initialize and start the stdin reading thread for WIN32
+ */
+static void
+sysdep_stdin_init()
+{
+    bounce_empty = CreateEvent(NULL, FALSE, TRUE, "bounce_empty");
+    bounce_full = CreateEvent(NULL, TRUE, FALSE, "bounce_full");
+    ctrl_c_event = CreateEvent(NULL, FALSE, FALSE, "Ctrl_C");
+    CreateThread(NULL, 0, stdin_read_thread, NULL, 0, NULL);
+}
+
+/*
+ * This function uses to WaitForMultipleObjects to wait for both
+ * stdin and socket reading or writing.
+ * Stdin is treated special in WIN32. Waiting for stdin is done
+ * via a bounce_full event which is set in the stdin thread.
+ * Execute command file reading is done via handle.  Execute
+ * command is read via CreateFile/ReadFile instead open/read
+ * because a file descriptor is not waitable.
+ * WaitForMultipleObjects will only respond with one object
+ * so an additonal select is also done to determine
+ * which individual events are active for the sock.
+ */
+static int
+w32_select(int nfds, fd_set *rdfd, fd_set *wrfd, fd_set *errfd, struct timeval* time)
+{
+    HANDLE handles[3];
+    SOCKET sock;
+    int result, s_result, num_handles = 0;
+    struct timeval tv_time = {0, 0};
+    fd_set rdfd2;
+
+    if (rdfd->fd_count > 1) {
+       sock = rdfd->fd_array[1];
+       if (rdfd->fd_array[0])
+           handles[num_handles++] = (HANDLE)rdfd->fd_array[0];
+       else {
+           handles[num_handles++] = ctrl_c_event;
+           handles[num_handles++] = bounce_full;
+       }
+    } else {
+       assert(rdfd->fd_count == 1);
+       sock = rdfd->fd_array[0];
+    }
+    assert(wrfd->fd_count == 0 ||
+          (wrfd->fd_count == 1 && wrfd->fd_array[0] == sock));
+    /* always wait on the socket */
+    handles[num_handles++] = WSACreateEvent();
+
+    if (wrfd->fd_count > 0)
+       WSAEventSelect(sock, handles[num_handles - 1],
+                      FD_READ | FD_WRITE | FD_CLOSE);
+    else
+       WSAEventSelect(sock, handles[num_handles - 1],
+                      FD_READ | FD_CLOSE);
+
+    result = WaitForMultipleObjects(num_handles, handles, 0, INFINITE);
+    if (result < 0) {
+       errno = GetLastError();
+       WSACloseEvent(handles[num_handles - 1]);
+       return -1;
+    }
+    WSACloseEvent(handles[num_handles - 1]);
+    
+    if (num_handles == 3 && result == WAIT_OBJECT_0) {
+       errno = EINTR;
+       return -1;
+    }
+
+    FD_ZERO(&rdfd2);
+    FD_SET(sock, &rdfd2);
+    s_result = select(sock + 1, &rdfd2, wrfd, NULL, &tv_time);
+
+    if (s_result < 0) {
+       errno = WSAGetLastError();
+       return s_result;
+    }
+
+    *rdfd = rdfd2;
+    if (num_handles == 3 && result == WAIT_OBJECT_0 + 1) {
+       FD_SET((SOCKET)0, rdfd);
+       s_result++;
+    }
+    if (num_handles == 2 && result == WAIT_OBJECT_0) {
+       FD_SET((SOCKET)handles[0], rdfd);
+       s_result++;
+    }
+    return s_result;
+}
+
+/*
+ * Read input from the user either stdin or from file.
+ * For stdin, read from bounce_buf which filled by the stdin thread
+ * otherwise use the regular ring_from_file.
+ */
+static int
+w32_ring_from_file_or_bounce_buf(struct ring *r, int fd)
+{
+    int i, res;
+
+    if (fd)
+        return ring_from_file(r, fd);
+
+    if (bounce_status < 0) {
+        errno = bounce_error;
+        res = bounce_status;
+    } else {
+        for (i = 0; i < bounce_status; i++) {
+            if (ring_putc(r, bounce_buf[i]) == EOF) {
+                /* more work to do, hold on to bounce_buf */
+                memmove(bounce_buf, bounce_buf + i, bounce_status - i);
+                bounce_status -= i;
+                return i;
+            }
+        }
+        res = i;
+    }
+
+    ResetEvent(bounce_full);
+    SetEvent(bounce_empty);
+    return res;
+}
+#define ring_from_file w32_ring_from_file_or_bounce_buf
+#define close(fd) w32_close_handle((fd))
+#define read(sock, buffer, buf_size) \
+       w32_recv((sock), (buffer), (buf_size), 0)
+#define select(nfds, rd, wr, error, time) \
+       w32_select((nfds), (rd), (wr), (error), (time))
+#else
+#define sysdep_stdin_init() ((void)0)
+#endif
+
 #define EOF_COOKIE "ctld\n"
 #define INTR_COOKIE "\naborted\n"
 
@@ -197,9 +437,6 @@ static void
 intr(int sig)
 {
     send_intr = 1;
-#ifdef _WIN32
-    signal(SIGINT, intr);
-#endif
 }
 
 /*
@@ -231,6 +468,7 @@ play(int sock)
     ring_init(&inbuf);
     eof_fd0 = send_eof = send_intr = 0;
     input_fd = 0;
+    sysdep_stdin_init(&eof_fd0, &inbuf);
 
     for (;;) {
        FD_ZERO(&rdfd);
index f8ef4daf665501e4df326d0063c0f4807c0e56d2..95c9c0db14bed1274a98c75da2251f00eba6bd24 100644 (file)
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
+#ifndef _WIN32
 #include <sys/uio.h>
 #include <unistd.h>
+#else
+#define readv(fd, iov, iovcnt) \
+    w32_readv_handle((fd), (iov), (iovcnt))
+#define writev(fd, iov, iovcnt) \
+    w32_writev_socket((fd), (iov), (iovcnt))
+#endif
+#include "misc.h"
 #include "ringbuf.h"
 
 /*
index 18d0956158e8aa788f7223b73a5b92493b692c51..526c934504db9b620bc888c256cfc3aec1e357bc 100644 (file)
 #include "proto.h"
 #include "secure.h"
 
+#ifdef _WIN32
+    #define open(filename, flags, ...) \
+        ((flags & O_CREAT) \
+         ? w32_openfd((filename), (flags), ## __VA_ARGS__) \
+         : w32_openhandle((filename), (flags)))
+#endif
+
 int eight_bit_clean;
 FILE *auxfp;
 
diff --git a/src/client/sysdep_w32.c b/src/client/sysdep_w32.c
new file mode 100644 (file)
index 0000000..9a3bad9
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ *  Empire - A multi-player, client/server Internet based war game.
+ *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *                           Ken Stevens, Steve McClure
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  ---
+ *
+ *  See files README, COPYING and CREDITS in the root of the source
+ *  tree for related information and legal notices.  It is expected
+ *  that future projects/authors will amend these files as needed.
+ *
+ *  ---
+ *
+ *  sysdep_w32.c: system dependent functions for WIN32 environments
+ * 
+ *  Known contributors to this file:
+ *     Ron Koenderink, 2007
+ */
+
+#ifdef _WIN32
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+#include "misc.h"
+#include "linebuf.h"
+#include "ringbuf.h"
+#include "secure.h"
+
+/*
+ * Ignore alarm for WIN32 client
+ */
+int 
+alarm(int time)
+{
+    return 0;
+}
+
+/*
+ * Get user name in the WIN32 environment
+ */
+struct passwd *
+w32_getpw(void)
+{
+    static char unamebuf[128];
+    static struct passwd pwd;
+    long unamesize;
+
+    unamesize = sizeof(unamebuf);
+    if (GetUserName(unamebuf, &unamesize)) {
+       pwd.pw_name = unamebuf;
+       if ((unamesize <= 0 ) || (strlen(unamebuf) <= 0))
+           pwd.pw_name = "nobody";
+    } else
+       pwd.pw_name = "nobody";
+    return &pwd;
+}
+
+/*
+ * Initialize the WIN32 socket library and
+ * set up stdout to work around bugs
+ */
+void
+sysdep_init(void)
+{
+    int err;
+    WSADATA WsaData;
+    /*
+     * stdout is unbuffered under Windows if connected to a character
+     * device, and putchar() screws up when printing multibyte strings
+     * bytewise to an unbuffered stream.  Switch stdout to line-
+     * buffered mode.  Unfortunately, ISO C allows implementations to
+     * screw that up, and of course Windows does.  Manual flushing
+     * after each prompt is required.
+     */
+    setvbuf(stdout, NULL, _IOLBF, 4096);
+    err = WSAStartup(MAKEWORD(2, 0), &WsaData);
+    if (err != 0) {
+       printf("WSAStartup Failed, error code %d\n", err);
+       exit(1);
+    }
+}
+
+/*
+ * POSIX compatible socket() replacement
+ */
+#undef socket
+int
+w32_socket(int family, int sock_type, int protocol)
+{
+    int result;
+    
+    result = socket(family, sock_type, protocol);
+    if (result == INVALID_SOCKET) {
+       errno = WSAGetLastError();
+       return -1;
+    }
+    return result;
+}
+
+/*
+ * POSIX compatible connect() replacement
+ */
+#undef connect
+int
+w32_connect(int sock, struct sockaddr *addr, int addrlen)
+{
+    int result;
+    
+    result = connect(sock,  addr, addrlen);
+    if (result == SOCKET_ERROR) {
+       errno = WSAGetLastError();
+       return -1;
+    }
+    return result;
+}
+
+/*
+ * POSIX compatible recv() replacement
+ */
+#undef recv
+int
+w32_recv(int socket, char *buffer, size_t buf_size, int flags)
+{
+    int result;
+
+    result = recv(socket, buffer, buf_size, flags);
+    if (result == SOCKET_ERROR) {
+       errno = WSAGetLastError();
+       return -1;
+    }
+    return result;
+}
+
+/*
+ * POSIX compatible writev() replacement specialized to sockets
+ * Modelled after the GNU's libc/sysdeps/posix/writev.c
+ */
+ssize_t
+w32_writev_socket(int fd, const struct iovec *iov, int iovcnt)
+{
+    int i;
+    unsigned char *buffer, *buffer_location;
+    size_t total_bytes = 0;
+    int bytes_written;
+
+    for (i = 0; i < iovcnt; i++)
+       total_bytes += iov[i].iov_len;
+
+    buffer = malloc(total_bytes);
+    if (buffer == NULL && total_bytes != 0) {
+       errno = ENOMEM;
+       return -1;
+    }
+
+    buffer_location = buffer;
+    for (i = 0; i < iovcnt; i++) {
+       memcpy(buffer_location, iov[i].iov_base, iov[i].iov_len);
+       buffer_location += iov[i].iov_len;
+    }
+
+    bytes_written = send(fd, buffer, total_bytes, 0);
+
+    free(buffer);
+
+    if (bytes_written == SOCKET_ERROR) {
+       errno = WSAGetLastError();
+       return -1;
+    }
+    return bytes_written;
+}
+
+/*
+ * POSIX compatible send() replacement
+ */
+int
+w32_send(int socket, char *buffer, size_t buf_size, int flags)
+{
+       int result;
+
+       result = send(socket, buffer, buf_size, flags);
+       if (result == SOCKET_ERROR)
+               errno = WSAGetLastError();
+       return result;
+}
+
+/*
+ * POSIX compatible close() replacement specialized to sockets.
+ */
+int
+w32_close_socket(int fd)
+{
+    int result;
+    
+    result = closesocket(fd);
+    if (result == SOCKET_ERROR)
+       errno = WSAGetLastError();
+    return result;
+}
+
+/*
+ * WIN32 equivalent for getpass
+ */
+char *
+getpass(char *prompt)
+{
+    static char tmp[128];
+    int len;
+    char *cpass;
+    DWORD mode;
+    HANDLE input_handle = GetStdHandle(STD_INPUT_HANDLE);
+
+    if (GetConsoleMode(input_handle, &mode))
+       SetConsoleMode(input_handle, mode & ~ENABLE_ECHO_INPUT);
+    else
+       printf("Note: This is echoed to the screen\n");
+    printf("%s", prompt);
+    fflush(stdout);
+    cpass = fgets(tmp, sizeof(tmp), stdin);
+    if (GetConsoleMode(input_handle, &mode))
+       SetConsoleMode(input_handle, mode | ENABLE_ECHO_INPUT);
+    if (cpass == NULL)
+       return NULL;
+    len = strlen(cpass);
+    if (tmp[len - 1] == '\n')
+       tmp[len - 1] = 0;
+    return cpass;
+}
+
+/*
+ * POSIX compatible open() replacement
+ */
+int
+w32_openfd(const char *fname, int oflag, ...)
+{
+    va_list ap;
+    int pmode = 0;
+    int fd;
+    int create_permission = 0;
+
+    if (oflag & O_CREAT) {
+       va_start(ap, oflag);
+       pmode = va_arg(ap, int);
+       va_end(ap);
+
+       if (pmode & 0400)
+           create_permission |= _S_IREAD;
+       if (pmode & 0200)
+           create_permission |= _S_IWRITE;
+    }
+
+    fd = _open(fname, oflag, create_permission);
+    return fd;
+}
+/*
+ * Open a file for reading, return its handle.
+ * This can be used in place of open() when a handle is desired for
+ * waiting on it with WaitForMultipleObjects() or similar.
+ * Ensure the handle is not zero in order to prevent a problem
+ * input_fd.
+ */
+int
+w32_openhandle(const char *fname, int oflag)
+{
+    HANDLE handle;
+
+    handle = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, NULL,
+       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+    if (handle == INVALID_HANDLE_VALUE) {
+       errno = GetLastError();
+       return -1;
+    }
+    if (handle == 0) {
+       HANDLE dup_handle;
+       if (!DuplicateHandle(GetCurrentProcess(), handle,
+                       GetCurrentProcess(), &dup_handle,
+                       0, FALSE, DUPLICATE_SAME_ACCESS)) {
+           errno = GetLastError();
+           return -1;
+       } else {
+           CloseHandle(handle);
+           handle = dup_handle;
+       }
+    }
+    return (int)handle;
+}
+
+/*
+ * POSIX compatible readv() replacement specialized to files.
+ * Modelled after the GNU's libc/sysdeps/posix/readv.c
+ */
+ssize_t
+w32_readv_handle(int fd, const struct iovec *iov, int iovcnt)
+{
+    int i;
+    unsigned char *buffer, *buffer_location;
+    size_t total_bytes = 0;
+    DWORD bytes_read;
+    size_t bytes_left;
+
+    for (i = 0; i < iovcnt; i++) {
+       total_bytes += iov[i].iov_len;
+    }
+
+    buffer = malloc(total_bytes);
+    if (buffer == NULL && total_bytes != 0) {
+       errno = ENOMEM;
+       return -1;
+    }
+
+    if (!ReadFile((HANDLE)fd, buffer, total_bytes, &bytes_read, NULL)) {
+       free(buffer);
+       errno = GetLastError();
+       return -1;
+    }
+
+    bytes_left = bytes_read;
+    buffer_location = buffer;
+    for (i = 0; i < iovcnt; i++) {
+       size_t copy = MIN(iov[i].iov_len, bytes_left);
+
+       memcpy(iov[i].iov_base, buffer_location, copy);
+
+       buffer_location += copy;
+       bytes_left -= copy;
+       if (bytes_left == 0)
+           break;
+    }
+
+    free(buffer);
+
+    return bytes_read;
+}
+
+/*
+ * POSIX compatible close() replacement specialized to files.
+ * Hack: expects a handle, cannot be used with a file descriptor.
+ */
+int
+w32_close_handle(int fd)
+{
+    int result;
+
+    result = CloseHandle((HANDLE)fd);
+
+    if (!result)
+       errno = GetLastError();
+    return result;
+}
+#endif /* _WIN32 */
diff --git a/src/client/sysdep_w32.h b/src/client/sysdep_w32.h
new file mode 100644 (file)
index 0000000..2cb5580
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *  Empire - A multi-player, client/server Internet based war game.
+ *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
+ *                           Ken Stevens, Steve McClure
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  ---
+ *
+ *  See files README, COPYING and CREDITS in the root of the source
+ *  tree for related information and legal notices.  It is expected
+ *  that future projects/authors will amend these files as needed.
+ *
+ *  ---
+ *
+ *  sysdep_w32.h: system dependent support for WIN32 environments
+ * 
+ *  Known contributors to this file:
+ *     Ron Koenderink, 2007
+ */
+
+#ifndef _SYSDEF_W32_H
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+#include <signal.h>
+
+extern int getopt(int, char * const[], const char *);
+extern char *optarg;
+extern int optind, opterr, optopt;
+
+#ifdef _MSC_VER
+typedef int __w64 ssize_t;
+#endif
+
+struct passwd {
+    char *pw_name;
+};
+
+struct iovec {
+    void *iov_base;
+    size_t iov_len;
+};
+
+struct sigaction {
+    int sa_flags;
+    void (*sa_handler)(int sig);
+};
+
+extern int w32_recv(int socket, char *buffer,
+                          size_t buf_size, int flags);
+extern int w32_send(int socket, char *buffer,
+                           size_t buf_size, int flags);
+extern int w32_close_socket(int fd);
+extern int w32_socket(int family, int sock_type, int protocol);
+extern int w32_connect(int sock, struct sockaddr *addr, int addrlen);
+extern int w32_close_handle(int fd);
+extern ssize_t w32_readv_handle(int fd, const struct iovec *iov,
+                               int iovcnt);
+extern ssize_t w32_writev_socket(int fd, const struct iovec *iov,
+                                int iovcnt);
+extern int w32_createfd(const char *fname, int oflag, ...);
+extern int w32_openhandle(const char *fname, int oflag);
+
+extern int alarm(int time);
+extern struct passwd *w32_getpw(void);
+extern char *getpass(char *prompt);
+extern void sysdep_init(void);
+
+#define recv(sock, buffer, buf_size, flags) \
+    w32_recv((sock), (buffer), (buf_size), (flags))
+#define socket(family, sock_type, protocol) \
+    w32_socket((family), (sock_type), (protocol))
+#define connect(sock, addr, addrlen) \
+    w32_connect((sock), (addr), (addrlen))
+                                   
+#define pclose _pclose
+#define popen _popen
+#define snprintf _snprintf
+#define getsose() ((void)0)
+#define putso() ((void)0)
+#define putse() ((void)0)
+#endif /* sysdef_w32.h */