>From 418da79e46bac7906395f63beb2ebf9f6736667d Mon Sep 17 00:00:00 2001
From: YX Hao <lifenjoiner@163.com>
Date: Wed, 15 Feb 2017 21:58:35 +0800
Subject: Add support for Unicode entries 'wmain' and 'wWinMain' on Windows
 '-run' suported. argvs are converted. But don't use compliled Unicode CLI
 exe-file to get inputs interactively in other codepage! Please add other
 compliling supports than 'build-tcc.bat' (Who is good at them).


diff --git a/tccpe.c b/tccpe.c
index 8d29070..8bb3d85 100644
--- a/tccpe.c
+++ b/tccpe.c
@@ -1759,34 +1759,46 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
 {
     const char *start_symbol;
     int pe_type = 0;
+    int unicode_entry = 0;
 
     if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16")))
         pe_type = PE_GUI;
     else
+    if (find_elf_sym(symtab_section, PE_STDSYM("wWinMain","@16"))) {
+        pe_type = PE_GUI;
+        unicode_entry = PE_GUI;
+    }
+    else
     if (TCC_OUTPUT_DLL == s1->output_type) {
         pe_type = PE_DLL;
         /* need this for 'tccelf.c:relocate_section()' */
         s1->output_type = TCC_OUTPUT_EXE;
     }
-    else
+    else {
         pe_type = PE_EXE;
+        if (find_elf_sym(symtab_section, "wmain"))
+            unicode_entry = PE_EXE;
+    }
 
     start_symbol =
         TCC_OUTPUT_MEMORY == s1->output_type
-        ? PE_GUI == pe_type ? "__runwinmain" : "_main"
+        ? PE_GUI == pe_type ? (unicode_entry ? "__runwwinmain" : "__runwinmain")
+            : (unicode_entry ? "__runwmain" : "__runmain")
         : PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12")
-        : PE_GUI == pe_type ? "__winstart" : "__start"
+            : PE_GUI == pe_type ? (unicode_entry ? "__wwinstart": "__winstart")
+                : (unicode_entry ? "__wstart" : "__start")
         ;
 
     if (!s1->leading_underscore || strchr(start_symbol, '@'))
         ++start_symbol;
 
     /* grab the startup code from libtcc1 */
-    if (TCC_OUTPUT_MEMORY != s1->output_type || PE_GUI == pe_type)
-        set_elf_sym(symtab_section,
-            0, 0,
-            ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
-            SHN_UNDEF, start_symbol);
+    /* only (PE_Dll == pe_type) doesn't need it,
+       (TCC_OUTPUT_MEMORY == s1->output_type && PE_Dll == pe_type) is illegal */
+    set_elf_sym(symtab_section,
+        0, 0,
+        ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
+        SHN_UNDEF, start_symbol);
 
     tcc_add_pragma_libs(s1);
 
diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat
index 09117b4..8da1404 100644
--- a/win32/build-tcc.bat
+++ b/win32/build-tcc.bat
@@ -137,10 +137,12 @@ copy>nul tiny_libmaker.exe tiny_libmaker-m%T%.exe
 %CC% -o tiny_libmaker-m%TX%.exe tools\tiny_libmaker.c %DX%
 
 :libtcc1.a
-@set O1=libtcc1.o crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o bcheck.o
+@set O1=libtcc1.o crt1.o wincrt1.o crt1_w.o wincrt1_w.o dllcrt1.o dllmain.o chkstk.o bcheck.o
 .\tcc -m32 %D32% -c ../lib/libtcc1.c
 .\tcc -m32 %D32% -c lib/crt1.c
+.\tcc -m32 %D32% -c lib/crt1.c -D_UNICODE -DUNICODE -o crt1_w.o
 .\tcc -m32 %D32% -c lib/wincrt1.c
+.\tcc -m32 %D32% -c lib/wincrt1.c -D_UNICODE -DUNICODE -o wincrt1_w.o
 .\tcc -m32 %D32% -c lib/dllcrt1.c
 .\tcc -m32 %D32% -c lib/dllmain.c
 .\tcc -m32 %D32% -c lib/chkstk.S
@@ -151,7 +153,9 @@ tiny_libmaker-m32 lib/32/libtcc1.a %O1% alloca86.o alloca86-bt.o
 @if errorlevel 1 goto :the_end
 .\tcc -m64 %D64% -c ../lib/libtcc1.c
 .\tcc -m64 %D64% -c lib/crt1.c
+.\tcc -m64 %D64% -c lib/crt1.c -D_UNICODE -DUNICODE -o crt1_w.o
 .\tcc -m64 %D64% -c lib/wincrt1.c
+.\tcc -m64 %D64% -c lib/wincrt1.c -D_UNICODE -DUNICODE -o wincrt1_w.o
 .\tcc -m64 %D64% -c lib/dllcrt1.c
 .\tcc -m64 %D64% -c lib/dllmain.c
 .\tcc -m64 %D64% -c lib/chkstk.S
diff --git a/win32/lib/crt1.c b/win32/lib/crt1.c
index 7a2d765..1e2bd17 100644
--- a/win32/lib/crt1.c
+++ b/win32/lib/crt1.c
@@ -1,6 +1,9 @@
 // =============================================
 // crt1.c
 
+// _UNICODE for tchar.h, UNICODE for API
+#include <tchar.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -18,20 +21,32 @@ typedef struct
     int newmode;
 } _startupinfo;
 
-int __cdecl __getmainargs(int *pargc, char ***pargv, char ***penv, int globb, _startupinfo*);
+#ifdef _UNICODE
+#define __tgetmainargs __wgetmainargs
+#define _tstart _wstart
+#define _tmain wmain
+#define _runtmain _runwmain
+#else
+#define __tgetmainargs __getmainargs
+#define _tstart _start
+#define _tmain main
+#define _runtmain _runmain
+#endif
+
+int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*);
 void __cdecl __set_app_type(int apptype);
 unsigned int __cdecl _controlfp(unsigned int new_value, unsigned int mask);
-int main(int argc, char * argv[], char * env[]);
+extern int _tmain(int argc, _TCHAR * argv[], _TCHAR * env[]);
 
 /* Allow command-line globbing with "int _dowildcard = 1;" in the user source */
 int _dowildcard;
 
-void _start(void)
+void _tstart(void)
 {
     __TRY__
     int argc, ret;
-    char **argv;
-    char **env;
+    _TCHAR **argv;
+    _TCHAR **env;
     _startupinfo start_info;
 
     // Sets the current application type
@@ -45,8 +60,28 @@ void _start(void)
 #endif
 
     start_info.newmode = 0;
-    __getmainargs( &argc, &argv, &env, _dowildcard, &start_info);
-    ret = main(argc, argv, env);
+    __tgetmainargs( &argc, &argv, &env, _dowildcard, &start_info);
+    ret = _tmain(argc, argv, env);
+    exit(ret);
+}
+
+void _runtmain(int argc0, /* as tcc passed in */ char **argv0)
+{
+    __TRY__
+    int argc, ret;
+    _TCHAR **argv;
+    _TCHAR **env;
+    _startupinfo start_info;
+
+    __set_app_type(_CONSOLE_APP);
+
+#ifdef __i386
+    _controlfp(_PC_53, _MCW_PC);
+#endif
+
+    start_info.newmode = 0;
+    __tgetmainargs( &argc, &argv, &env, _dowildcard, &start_info);
+    ret = _tmain(argc0, argv + argc - argc0, env);
     exit(ret);
 }
 
diff --git a/win32/lib/wincrt1.c b/win32/lib/wincrt1.c
index 663fd33..06f42f0 100644
--- a/win32/lib/wincrt1.c
+++ b/win32/lib/wincrt1.c
@@ -1,5 +1,8 @@
 //+---------------------------------------------------------------------------
 
+// _UNICODE for tchar.h, UNICODE for API
+#include <tchar.h>
+
 #include <windows.h>
 #include <stdlib.h>
 
@@ -9,10 +12,28 @@
 void __set_app_type(int);
 void _controlfp(unsigned a, unsigned b);
 
-int _winstart(void)
+#ifdef _UNICODE
+#define __tgetmainargs __wgetmainargs
+#define _twinstart _wwinstart
+#define _runtwinmain _runwwinmain
+int APIENTRY wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int);
+#else
+#define __tgetmainargs __getmainargs
+#define _twinstart _winstart
+#define _runtwinmain _runwinmain
+#endif
+
+typedef struct
+{
+    int newmode;
+} _startupinfo; // CLI Vs GUI
+
+int __cdecl __tgetmainargs(int *pargc, _TCHAR ***pargv, _TCHAR ***penv, int globb, _startupinfo*);
+
+int _twinstart(void)
 {
     __TRY__
-    char *szCmd;
+    _TCHAR *szCmd;
     STARTUPINFO startinfo;
     int fShow;
     int ret;
@@ -22,19 +43,19 @@ int _winstart(void)
 
     szCmd = GetCommandLine();
     if (szCmd) {
-        while (' ' == *szCmd)
+        while (__T(' ') == *szCmd)
             szCmd++;
-        if ('\"' == *szCmd) {
+        if (__T('\"') == *szCmd) {
             while (*++szCmd)
-                if ('\"' == *szCmd) {
+                if (__T('\"') == *szCmd) {
                     szCmd++;
                     break;
                 }
         } else {
-            while (*szCmd && ' ' != *szCmd)
+            while (*szCmd && __T(' ') != *szCmd)
                 szCmd++;
         }
-        while (' ' == *szCmd)
+        while (__T(' ') == *szCmd)
             szCmd++;
     }
 
@@ -43,22 +64,30 @@ int _winstart(void)
     if (0 == (startinfo.dwFlags & STARTF_USESHOWWINDOW))
         fShow = SW_SHOWDEFAULT;
 
-    ret = WinMain(GetModuleHandle(NULL), NULL, szCmd, fShow);
+    ret = _tWinMain(GetModuleHandle(NULL), NULL, szCmd, fShow);
     exit(ret);
 }
 
-int _runwinmain(int argc, char **argv)
+int _runtwinmain(int argc0, /* as tcc passed in */ char **argv0)
 {
-    char *szCmd, *p;
+    _TCHAR *szCmd, *p;
+
+    int argc;
+    _TCHAR **argv;
+    _TCHAR **env;
+    _startupinfo start_info;
+
+    start_info.newmode = 0;
+    __tgetmainargs(&argc, &argv, &env, 0, &start_info);
 
     p = GetCommandLine();
     szCmd = NULL;
-    if (argc > 1)
-        szCmd = strstr(p, argv[1]);
+    if (argc0 > 1)
+        szCmd = _tcsstr(p, argv[argc - argc0 + 1]);
     if (NULL == szCmd)
-        szCmd = "";
-    else if (szCmd > p && szCmd[-1] == '\"')
+        szCmd = __T("");
+    else if (szCmd > p && szCmd[-1] == __T('\"'))
         --szCmd;
     _controlfp(0x10000, 0x30000);
-    return WinMain(GetModuleHandle(NULL), NULL, szCmd, SW_SHOWDEFAULT);
+    return _tWinMain(GetModuleHandle(NULL), NULL, szCmd, SW_SHOWDEFAULT);
 }
