11#include <Windows.h>
2+ #include <wchar.h>
23#include <process.h>
34#include <stdint.h>
45#include <stdio.h>
56#include <stdlib.h>
67#include <string.h>
78#include <strsafe.h>
9+ #include <locale.h>
810
911#include "argparse.h"
1012
@@ -16,15 +18,15 @@ static const char* const usages[] = {
1618typedef struct {
1719 enum { PWT_STDIN , PWT_FILE , PWT_FD , PWT_PASS } pwtype ;
1820 union {
19- const char * filename ;
21+ const wchar_t * filename ;
2022 int64_t fd ;
2123 const char * password ;
2224 } pwsrc ;
2325
2426 const char * passPrompt ;
2527 int verbose ;
2628
27- char * cmd ;
29+ wchar_t * cmd ;
2830} Args ;
2931
3032typedef struct {
@@ -38,19 +40,87 @@ typedef struct {
3840 HANDLE events [2 ];
3941} Context ;
4042
41- static void ParseArgs (int argc , const char * argv [] , Context * ctx );
43+ static void ParseArgs (int argc , const wchar_t * * wargv , char * * argv , Context * ctx );
4244static void WritePass (Context * ctx );
4345static HRESULT CreatePseudoConsoleAndPipes (HPCON * hpcon , Context * ctx );
44- static HRESULT InitializeStartupInfoAttachedToPseudoConsole (STARTUPINFOEXA * startupInfo ,
46+ static HRESULT InitializeStartupInfoAttachedToPseudoConsole (STARTUPINFOEXW * startupInfo ,
4547 HPCON hpcon );
4648static void __cdecl PipeListener (LPVOID );
4749static void __cdecl InputHandlerThread (LPVOID );
4850
49- int main (int argc , const char * argv []) {
51+ static wchar_t * ToUtf16 (const char * utf8 ) {
52+ if (utf8 == NULL ) {
53+ return NULL ;
54+ }
55+ wchar_t * utf16 = NULL ;
56+ int buf_size = MultiByteToWideChar (CP_UTF8 , 0 , utf8 , -1 , NULL , 0 );
57+ if (buf_size == 0 ) {
58+ return NULL ;
59+ }
60+ utf16 = malloc (sizeof (wchar_t ) * (buf_size + 1 )); // free when process exit
61+ buf_size = MultiByteToWideChar (CP_UTF8 , 0 , utf8 , -1 , utf16 , buf_size );
62+ if (buf_size == 0 ) {
63+ free (utf16 );
64+ return NULL ;
65+ }
66+ utf16 [buf_size ] = L'\0' ;
67+ return utf16 ;
68+ }
69+
70+ static char * ToUtf8 (const wchar_t * wstr ) {
71+ if (wstr == NULL ) {
72+ return NULL ;
73+ }
74+
75+ int len = WideCharToMultiByte (CP_UTF8 , 0 , wstr , -1 , NULL , 0 , NULL , NULL );
76+ if (len == 0 ) {
77+ return NULL ;
78+ }
79+
80+ char * utf8 = (char * )malloc (len ); // free when the process exit
81+ if (utf8 == NULL ) {
82+ return NULL ;
83+ }
84+
85+ if (WideCharToMultiByte (CP_UTF8 , 0 , wstr , -1 , utf8 , len , NULL , NULL ) == 0 ) {
86+ free (utf8 );
87+ return NULL ;
88+ }
89+
90+ return utf8 ;
91+ }
92+
93+ static char * * ConvertArgcToMultiByte (int argc , const wchar_t * argv [])
94+ {
95+ char * * ret = malloc (argc * sizeof (char * )); // free when the process exit
96+ if (ret == NULL ) {
97+ return NULL ;
98+ }
99+ for (int i = 0 ; i < argc ; i ++ ) {
100+ ret [i ] = ToUtf8 (argv [i ]);
101+ }
102+ return ret ;
103+ }
104+
105+ static void SetupConsole (void ) {
106+ SetConsoleOutputCP (CP_UTF8 );
107+ SetConsoleCP (CP_UTF8 );
108+ setlocale (LC_ALL , ".UTF-8" );
109+ }
110+
111+
112+ int wmain (int argc , const wchar_t * argv []) {
50113 Context ctx ;
51- uint32_t childExitCode = 0 ;
114+ DWORD childExitCode = 0 ;
115+
116+ SetupConsole ();
52117
53- ParseArgs (argc , argv , & ctx );
118+ char * * argvUtf8 = ConvertArgcToMultiByte (argc , argv );
119+ if (argvUtf8 == NULL ) {
120+ return EXIT_FAILURE ;
121+ }
122+
123+ ParseArgs (argc , argv , argvUtf8 , & ctx );
54124
55125 HRESULT hr = E_UNEXPECTED ;
56126
@@ -72,10 +142,10 @@ int main(int argc, const char* argv[]) {
72142 if (S_OK == hr ) {
73143 HANDLE pipeListener = (HANDLE ) _beginthread (PipeListener , 0 , & ctx );
74144
75- STARTUPINFOEXA startupInfo = {0 };
145+ STARTUPINFOEXW startupInfo = {0 };
76146 if (S_OK == InitializeStartupInfoAttachedToPseudoConsole (& startupInfo , hpcon )) {
77147 PROCESS_INFORMATION cmdProc ;
78- hr = CreateProcessA (NULL , ( char * ) ctx .args .cmd , NULL , NULL , FALSE,
148+ hr = CreateProcessW (NULL , ctx .args .cmd , NULL , NULL , FALSE,
79149 EXTENDED_STARTUPINFO_PRESENT , NULL , NULL ,
80150 & startupInfo .StartupInfo , & cmdProc )
81151 ? S_OK
@@ -109,18 +179,19 @@ int main(int argc, const char* argv[]) {
109179 }
110180
111181 CloseHandle (ctx .events [0 ]);
112- }
182+ }
113183 return S_OK == hr ? childExitCode : EXIT_FAILURE ;
114184}
115185
116- static void ParseArgs (int argc , const char * argv [] , Context * ctx ) {
186+ static void ParseArgs (int argc , const wchar_t * wargv [], char * * argv , Context * ctx ) {
117187 const char * filename = NULL ;
118188 int64_t number = 0 ;
119189 const char * strpass = NULL ;
120190 int envPass = 0 ;
121191
122192 const char * passPrompt = NULL ;
123193 int verbose = 0 ;
194+ int totalArgc = argc ;
124195
125196 struct argparse_option options [] = {
126197 OPT_HELP (),
@@ -142,7 +213,7 @@ static void ParseArgs(int argc, const char* argv[], Context* ctx) {
142213
143214 struct argparse argparse ;
144215 argparse_init (& argparse , options , usages , ARGPARSE_STOP_AT_NON_OPTION );
145- argc = argparse_parse (& argparse , argc , argv );
216+ argc = argparse_parse (& argparse , argc , ( const char * * ) argv );
146217 if (argc == 0 ) {
147218 argparse_usage (& argparse );
148219 exit (EXIT_FAILURE );
@@ -151,7 +222,7 @@ static void ParseArgs(int argc, const char* argv[], Context* ctx) {
151222 ctx -> args .verbose = verbose ;
152223 if (filename != NULL ) {
153224 ctx -> args .pwtype = PWT_FILE ;
154- ctx -> args .pwsrc .filename = filename ;
225+ ctx -> args .pwsrc .filename = ToUtf16 ( filename ) ;
155226 } else if (number != 0 ) {
156227 ctx -> args .pwtype = PWT_FD ;
157228 ctx -> args .pwsrc .fd = number ;
@@ -172,19 +243,22 @@ static void ParseArgs(int argc, const char* argv[], Context* ctx) {
172243 }
173244
174245 int cmdLen = 0 ;
246+ int parsedArgc = totalArgc - argc ;
175247 for (int i = 0 ; i < argc ; i ++ ) {
176- cmdLen += strlen ( argv [ i ]) + 2 ;
248+ cmdLen += wcslen ( wargv [ i + parsedArgc ]) + 2 ;
177249 }
178250
179- ctx -> args .cmd = malloc (sizeof (char ) * cmdLen );
180- memset (ctx -> args .cmd , 0 , sizeof (char ) * cmdLen );
251+ ctx -> args .cmd = malloc (sizeof (wchar_t ) * cmdLen );
252+ memset (ctx -> args .cmd , 0 , sizeof (wchar_t ) * cmdLen );
181253 for (int i = 0 ; i < argc ; i ++ ) {
182- StringCchCatA (ctx -> args .cmd , sizeof (char ) * cmdLen , argv [ i ]);
183- StringCchCatA (ctx -> args .cmd , sizeof (char ) * cmdLen , " " );
254+ StringCchCatW (ctx -> args .cmd , sizeof (wchar_t ) * cmdLen , wargv [ i + parsedArgc ]);
255+ StringCchCatW (ctx -> args .cmd , sizeof (wchar_t ) * cmdLen , L " " );
184256 }
185257
186258 if (ctx -> args .verbose ) {
187- fprintf (stdout , "cmd: %s\n" , ctx -> args .cmd );
259+ char * cmd = ToUtf8 (ctx -> args .cmd );
260+ fprintf (stdout , "cmd: %s\n" , cmd );
261+ free (cmd );
188262 }
189263}
190264
@@ -219,15 +293,15 @@ static HRESULT CreatePseudoConsoleAndPipes(HPCON* hpcon, Context* ctx) {
219293 return hr ;
220294}
221295
222- static HRESULT InitializeStartupInfoAttachedToPseudoConsole (STARTUPINFOEXA * startupInfo ,
296+ static HRESULT InitializeStartupInfoAttachedToPseudoConsole (STARTUPINFOEXW * startupInfo ,
223297 HPCON hpcon ) {
224298 HRESULT hr = E_UNEXPECTED ;
225299 if (startupInfo == NULL ) {
226300 return hr ;
227301 }
228302
229303 size_t attrListSize ;
230- startupInfo -> StartupInfo .cb = sizeof (STARTUPINFOEXA );
304+ startupInfo -> StartupInfo .cb = sizeof (STARTUPINFOEXW );
231305
232306 InitializeProcThreadAttributeList (NULL , 1 , 0 , & attrListSize );
233307
@@ -290,7 +364,7 @@ static State ProcessOutput(Context* ctx, const char* buffer, DWORD len, State st
290364 return nextState ;
291365}
292366
293- #define BUFFER_SIZE 1024
367+ #define BUFFER_SIZE 8192
294368
295369static void __cdecl PipeListener (LPVOID arg ) {
296370 Context * ctx = arg ;
@@ -347,7 +421,7 @@ static void WritePass(Context* ctx) {
347421 WritePassHandle (ctx , (HANDLE ) ctx -> args .pwsrc .fd );
348422 break ;
349423 case PWT_FILE : {
350- HANDLE file = CreateFileA (ctx -> args .pwsrc .filename , GENERIC_READ , FILE_SHARE_READ , NULL ,
424+ HANDLE file = CreateFileW (ctx -> args .pwsrc .filename , GENERIC_READ , FILE_SHARE_READ , NULL ,
351425 OPEN_EXISTING , FILE_ATTRIBUTE_READONLY , NULL );
352426 if (file != INVALID_HANDLE_VALUE ) {
353427 WritePassHandle (ctx , file );
@@ -385,4 +459,4 @@ static void __cdecl InputHandlerThread(LPVOID arg) {
385459 }
386460
387461 SetConsoleMode (hStdin , mode );
388- }
462+ }
0 commit comments