msvc: support building Git using MS Visual C++
[gitweb.git] / compat / mingw.c
index a2f74aca6a156a203ba6dd7b435622060b6870df..c063ae62be125f33418684039bd3fbc21433b83b 100644 (file)
@@ -1553,7 +1553,10 @@ static int try_shell_exec(const char *cmd, char *const *argv)
        if (prog) {
                int exec_id;
                int argc = 0;
-               const char **argv2;
+#ifndef _MSC_VER
+               const
+#endif
+               char **argv2;
                while (argv[argc]) argc++;
                ALLOC_ARRAY(argv2, argc + 1);
                argv2[0] = (char *)cmd; /* full path to the script file */
@@ -1714,142 +1717,10 @@ int mingw_putenv(const char *namevalue)
        return result ? 0 : -1;
 }
 
-/*
- * Note, this isn't a complete replacement for getaddrinfo. It assumes
- * that service contains a numerical port, or that it is null. It
- * does a simple search using gethostbyname, and returns one IPv4 host
- * if one was found.
- */
-static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
-                                  const struct addrinfo *hints,
-                                  struct addrinfo **res)
-{
-       struct hostent *h = NULL;
-       struct addrinfo *ai;
-       struct sockaddr_in *sin;
-
-       if (node) {
-               h = gethostbyname(node);
-               if (!h)
-                       return WSAGetLastError();
-       }
-
-       ai = xmalloc(sizeof(struct addrinfo));
-       *res = ai;
-       ai->ai_flags = 0;
-       ai->ai_family = AF_INET;
-       ai->ai_socktype = hints ? hints->ai_socktype : 0;
-       switch (ai->ai_socktype) {
-       case SOCK_STREAM:
-               ai->ai_protocol = IPPROTO_TCP;
-               break;
-       case SOCK_DGRAM:
-               ai->ai_protocol = IPPROTO_UDP;
-               break;
-       default:
-               ai->ai_protocol = 0;
-               break;
-       }
-       ai->ai_addrlen = sizeof(struct sockaddr_in);
-       if (hints && (hints->ai_flags & AI_CANONNAME))
-               ai->ai_canonname = h ? xstrdup(h->h_name) : NULL;
-       else
-               ai->ai_canonname = NULL;
-
-       sin = xcalloc(1, ai->ai_addrlen);
-       sin->sin_family = AF_INET;
-       /* Note: getaddrinfo is supposed to allow service to be a string,
-        * which should be looked up using getservbyname. This is
-        * currently not implemented */
-       if (service)
-               sin->sin_port = htons(atoi(service));
-       if (h)
-               sin->sin_addr = *(struct in_addr *)h->h_addr;
-       else if (hints && (hints->ai_flags & AI_PASSIVE))
-               sin->sin_addr.s_addr = INADDR_ANY;
-       else
-               sin->sin_addr.s_addr = INADDR_LOOPBACK;
-       ai->ai_addr = (struct sockaddr *)sin;
-       ai->ai_next = NULL;
-       return 0;
-}
-
-static void WSAAPI freeaddrinfo_stub(struct addrinfo *res)
-{
-       free(res->ai_canonname);
-       free(res->ai_addr);
-       free(res);
-}
-
-static int WSAAPI getnameinfo_stub(const struct sockaddr *sa, socklen_t salen,
-                                  char *host, DWORD hostlen,
-                                  char *serv, DWORD servlen, int flags)
-{
-       const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
-       if (sa->sa_family != AF_INET)
-               return EAI_FAMILY;
-       if (!host && !serv)
-               return EAI_NONAME;
-
-       if (host && hostlen > 0) {
-               struct hostent *ent = NULL;
-               if (!(flags & NI_NUMERICHOST))
-                       ent = gethostbyaddr((const char *)&sin->sin_addr,
-                                           sizeof(sin->sin_addr), AF_INET);
-
-               if (ent)
-                       snprintf(host, hostlen, "%s", ent->h_name);
-               else if (flags & NI_NAMEREQD)
-                       return EAI_NONAME;
-               else
-                       snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
-       }
-
-       if (serv && servlen > 0) {
-               struct servent *ent = NULL;
-               if (!(flags & NI_NUMERICSERV))
-                       ent = getservbyport(sin->sin_port,
-                                           flags & NI_DGRAM ? "udp" : "tcp");
-
-               if (ent)
-                       snprintf(serv, servlen, "%s", ent->s_name);
-               else
-                       snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
-       }
-
-       return 0;
-}
-
-static HMODULE ipv6_dll = NULL;
-static void (WSAAPI *ipv6_freeaddrinfo)(struct addrinfo *res);
-static int (WSAAPI *ipv6_getaddrinfo)(const char *node, const char *service,
-                                     const struct addrinfo *hints,
-                                     struct addrinfo **res);
-static int (WSAAPI *ipv6_getnameinfo)(const struct sockaddr *sa, socklen_t salen,
-                                     char *host, DWORD hostlen,
-                                     char *serv, DWORD servlen, int flags);
-/*
- * gai_strerror is an inline function in the ws2tcpip.h header, so we
- * don't need to try to load that one dynamically.
- */
-
-static void socket_cleanup(void)
-{
-       WSACleanup();
-       if (ipv6_dll)
-               FreeLibrary(ipv6_dll);
-       ipv6_dll = NULL;
-       ipv6_freeaddrinfo = freeaddrinfo_stub;
-       ipv6_getaddrinfo = getaddrinfo_stub;
-       ipv6_getnameinfo = getnameinfo_stub;
-}
-
 static void ensure_socket_initialization(void)
 {
        WSADATA wsa;
        static int initialized = 0;
-       const char *libraries[] = { "ws2_32.dll", "wship6.dll", NULL };
-       const char **name;
 
        if (initialized)
                return;
@@ -1858,35 +1729,7 @@ static void ensure_socket_initialization(void)
                die("unable to initialize winsock subsystem, error %d",
                        WSAGetLastError());
 
-       for (name = libraries; *name; name++) {
-               ipv6_dll = LoadLibraryExA(*name, NULL,
-                                         LOAD_LIBRARY_SEARCH_SYSTEM32);
-               if (!ipv6_dll)
-                       continue;
-
-               ipv6_freeaddrinfo = (void (WSAAPI *)(struct addrinfo *))
-                       GetProcAddress(ipv6_dll, "freeaddrinfo");
-               ipv6_getaddrinfo = (int (WSAAPI *)(const char *, const char *,
-                                                  const struct addrinfo *,
-                                                  struct addrinfo **))
-                       GetProcAddress(ipv6_dll, "getaddrinfo");
-               ipv6_getnameinfo = (int (WSAAPI *)(const struct sockaddr *,
-                                                  socklen_t, char *, DWORD,
-                                                  char *, DWORD, int))
-                       GetProcAddress(ipv6_dll, "getnameinfo");
-               if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) {
-                       FreeLibrary(ipv6_dll);
-                       ipv6_dll = NULL;
-               } else
-                       break;
-       }
-       if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) {
-               ipv6_freeaddrinfo = freeaddrinfo_stub;
-               ipv6_getaddrinfo = getaddrinfo_stub;
-               ipv6_getnameinfo = getnameinfo_stub;
-       }
-
-       atexit(socket_cleanup);
+       atexit((void(*)(void)) WSACleanup);
        initialized = 1;
 }
 
@@ -1904,24 +1747,12 @@ struct hostent *mingw_gethostbyname(const char *host)
        return gethostbyname(host);
 }
 
-void mingw_freeaddrinfo(struct addrinfo *res)
-{
-       ipv6_freeaddrinfo(res);
-}
-
+#undef getaddrinfo
 int mingw_getaddrinfo(const char *node, const char *service,
                      const struct addrinfo *hints, struct addrinfo **res)
 {
        ensure_socket_initialization();
-       return ipv6_getaddrinfo(node, service, hints, res);
-}
-
-int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen,
-                     char *host, DWORD hostlen, char *serv, DWORD servlen,
-                     int flags)
-{
-       ensure_socket_initialization();
-       return ipv6_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
+       return getaddrinfo(node, service, hints, res);
 }
 
 int mingw_socket(int domain, int type, int protocol)
@@ -2473,18 +2304,13 @@ static void setup_windows_environment(void)
                setenv("TERM", "cygwin", 1);
 }
 
+#if !defined(_MSC_VER)
 /*
  * Disable MSVCRT command line wildcard expansion (__getmainargs called from
  * mingw startup code, see init.c in mingw runtime).
  */
 int _CRT_glob = 0;
-
-typedef struct {
-       int newmode;
-} _startupinfo;
-
-extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
-               _startupinfo *si);
+#endif
 
 static NORETURN void die_startup(void)
 {
@@ -2562,22 +2388,31 @@ static void maybe_redirect_std_handles(void)
                                  GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
 }
 
-void mingw_startup(void)
+#ifdef _MSC_VER
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+#endif
+
+/*
+ * We implement wmain() and compile with -municode, which would
+ * normally ignore main(), but we call the latter from the former
+ * so that we can handle non-ASCII command-line parameters
+ * appropriately.
+ *
+ * To be more compatible with the core git code, we convert
+ * argv into UTF8 and pass them directly to main().
+ */
+int wmain(int argc, const wchar_t **wargv)
 {
-       int i, maxlen, argc;
-       char *buffer;
-       wchar_t **wenv, **wargv;
-       _startupinfo si;
+       int i, maxlen, exit_status;
+       char *buffer, **save;
+       const char **argv;
 
        trace2_initialize_clock();
 
        maybe_redirect_std_handles();
 
-       /* get wide char arguments and environment */
-       si.newmode = 0;
-       if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
-               die_startup();
-
        /* determine size of argv and environ conversion buffer */
        maxlen = wcslen(wargv[0]);
        for (i = 1; i < argc; i++)
@@ -2587,9 +2422,16 @@ void mingw_startup(void)
        maxlen = 3 * maxlen + 1;
        buffer = malloc_startup(maxlen);
 
-       /* convert command line arguments and environment to UTF-8 */
+       /*
+        * Create a UTF-8 version of w_argv. Also create a "save" copy
+        * to remember all the string pointers because parse_options()
+        * will remove claimed items from the argv that we pass down.
+        */
+       ALLOC_ARRAY(argv, argc + 1);
+       ALLOC_ARRAY(save, argc + 1);
        for (i = 0; i < argc; i++)
-               __argv[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
+               argv[i] = save[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
+       argv[i] = save[i] = NULL;
        free(buffer);
 
        /* fix Windows specific environment settings */
@@ -2608,6 +2450,16 @@ void mingw_startup(void)
 
        /* initialize Unicode console */
        winansi_init();
+
+       /* invoke the real main() using our utf8 version of argv. */
+       exit_status = main(argc, argv);
+
+       for (i = 0; i < argc; i++)
+               free(save[i]);
+       free(save);
+       free(argv);
+
+       return exit_status;
 }
 
 int uname(struct utsname *buf)