StdOut Unicode support, controlled by /OUTPUTCHARSET and/or existing BOM if redirected.
git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6350 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
parent
c6f149764d
commit
0653f46c07
19 changed files with 684 additions and 425 deletions
|
@ -27,12 +27,6 @@ int GetTLBVersion(tstring& filepath, DWORD& high, DWORD & low)
|
|||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifdef _countof
|
||||
#define COUNTOF _countof
|
||||
#else
|
||||
#define COUNTOF(a) (sizeof(a)/sizeof(a[0]))
|
||||
#endif
|
||||
|
||||
int found = 0;
|
||||
|
||||
TCHAR fullpath[1024];
|
||||
|
|
|
@ -413,6 +413,14 @@ BOOL CALLBACK DialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
|
|||
DragAcceptFiles(g_sdata.hwnd,TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
case MakensisAPI::QUERYHOST: {
|
||||
if (MakensisAPI::QH_OUTPUTCHARSET) {
|
||||
const UINT reqcp = CP_UTF8; // TODO: UTF16LE will be faster for makensis
|
||||
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)(1+reqcp));
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
case WM_NOTIFY:
|
||||
switch (((NMHDR*)lParam)->code ) {
|
||||
case EN_SELCHANGE:
|
||||
|
@ -712,12 +720,12 @@ BOOL CALLBACK DialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
|
|||
|
||||
DWORD WINAPI MakeNSISProc(LPVOID p) {
|
||||
TCHAR eventnamebuf[100];
|
||||
wsprintf(eventnamebuf,MakensisAPI::SigintEventNameFmt,g_sdata.hwnd);
|
||||
wsprintf(eventnamebuf, MakensisAPI::SigintEventNameFmt, g_sdata.hwnd);
|
||||
if (g_sdata.sigint_event) CloseHandle(g_sdata.sigint_event);
|
||||
g_sdata.sigint_event = CreateEvent(NULL,FALSE,FALSE,eventnamebuf);
|
||||
g_sdata.sigint_event = CreateEvent(NULL, FALSE, FALSE, eventnamebuf);
|
||||
if (!g_sdata.sigint_event) {
|
||||
ErrorMessage(g_sdata.hwnd,_T("There was an error creating the abort event."));
|
||||
PostMessage(g_sdata.hwnd,WM_MAKENSIS_PROCESSCOMPLETE,0,0);
|
||||
ErrorMessage(g_sdata.hwnd, _T("There was an error creating the abort event."));
|
||||
PostMessage(g_sdata.hwnd, WM_MAKENSIS_PROCESSCOMPLETE, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -725,44 +733,21 @@ DWORD WINAPI MakeNSISProc(LPVOID p) {
|
|||
TCHAR buf[1024];
|
||||
#endif
|
||||
char iobuf[1024]; //i/o buffer
|
||||
STARTUPINFO si={sizeof(si),};
|
||||
SECURITY_ATTRIBUTES sa={sizeof(sa),};
|
||||
SECURITY_DESCRIPTOR sd={0,};
|
||||
PROCESS_INFORMATION pi={0,};
|
||||
HANDLE newstdout=0,read_stdout=0;
|
||||
HANDLE newstdin=0,read_stdin=0;
|
||||
OSVERSIONINFO osv={sizeof(osv)};
|
||||
GetVersionEx(&osv);
|
||||
if (osv.dwPlatformId == VER_PLATFORM_WIN32_NT) {
|
||||
InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
|
||||
SetSecurityDescriptorDacl(&sd,true,NULL,false);
|
||||
sa.lpSecurityDescriptor = &sd;
|
||||
}
|
||||
else sa.lpSecurityDescriptor = NULL;
|
||||
sa.bInheritHandle = true;
|
||||
if (!CreatePipe(&read_stdout,&newstdout,&sa,0)) {
|
||||
ErrorMessage(g_sdata.hwnd,_T("There was an error creating the output pipe."));
|
||||
PostMessage(g_sdata.hwnd,WM_MAKENSIS_PROCESSCOMPLETE,0,0);
|
||||
STARTUPINFO si;
|
||||
HANDLE newstdout,read_stdout;
|
||||
|
||||
if (!InitSpawn(si, read_stdout, newstdout)) {
|
||||
ErrorMessage(g_sdata.hwnd, _T("There was an error creating the pipe."));
|
||||
PostMessage(g_sdata.hwnd, WM_MAKENSIS_PROCESSCOMPLETE, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
if (!CreatePipe(&read_stdin,&newstdin,&sa,0)) {
|
||||
ErrorMessage(g_sdata.hwnd,_T("There was an error creating the input pipe."));
|
||||
PostMessage(g_sdata.hwnd,WM_MAKENSIS_PROCESSCOMPLETE,0,0);
|
||||
return 1;
|
||||
}
|
||||
GetStartupInfo(&si);
|
||||
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
si.hStdOutput = newstdout;
|
||||
si.hStdError = newstdout;
|
||||
si.hStdInput = newstdin;
|
||||
if (!CreateProcess(NULL,g_sdata.compile_command,NULL,NULL,TRUE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi)) {
|
||||
TCHAR buf[MAX_STRING];
|
||||
wsprintf(buf,_T("Could not execute:\r\n %s."),g_sdata.compile_command);
|
||||
ErrorMessage(g_sdata.hwnd,buf);
|
||||
CloseHandle(newstdout);
|
||||
CloseHandle(read_stdout);
|
||||
PostMessage(g_sdata.hwnd,WM_MAKENSIS_PROCESSCOMPLETE,0,0);
|
||||
PROCESS_INFORMATION pi;
|
||||
if (!CreateProcess(0, g_sdata.compile_command, 0, 0, TRUE, CREATE_NEW_CONSOLE, 0, 0, &si, &pi)) {
|
||||
TCHAR buf[MAX_STRING]; // BUGBUG: TODO: Too small?
|
||||
wsprintf(buf,_T("Could not execute:\r\n %s."), g_sdata.compile_command);
|
||||
ErrorMessage(g_sdata.hwnd, buf);
|
||||
FreeSpawn(0, read_stdout, newstdout);
|
||||
PostMessage(g_sdata.hwnd, WM_MAKENSIS_PROCESSCOMPLETE, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
CloseHandle(newstdout); // close this handle (duplicated in subprocess) now so we get ERROR_BROKEN_PIPE
|
||||
|
@ -774,8 +759,9 @@ DWORD WINAPI MakeNSISProc(LPVOID p) {
|
|||
#ifdef _UNICODE
|
||||
// this tweak is to prevent LogMessage from cutting in the middle of an UTF-8 sequence
|
||||
// we print only up to the latest \n of the buffer, and keep the remaining for the next loop
|
||||
// BUGBUG: What if the line is longer than sizeof(iobuf)?
|
||||
char* lastLF = strrchr(iobuf,'\n');
|
||||
if (lastLF == NULL) lastLF = iobuf+dwRead-1;
|
||||
if (!lastLF) lastLF = iobuf+dwRead-1;
|
||||
char ch = *++lastLF;
|
||||
*lastLF = '\0';
|
||||
MultiByteToWideChar(CP_UTF8,0,iobuf,lastLF+1-iobuf,buf,COUNTOF(buf));
|
||||
|
@ -794,15 +780,9 @@ DWORD WINAPI MakeNSISProc(LPVOID p) {
|
|||
MultiByteToWideChar(CP_UTF8,0,iobuf,dwRead+1,buf,COUNTOF(buf));
|
||||
LogMessage(g_sdata.hwnd, buf);
|
||||
#endif
|
||||
DWORD dwExit;
|
||||
GetExitCodeProcess(pi.hProcess, &dwExit);
|
||||
g_sdata.retcode = dwExit;
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(read_stdout);
|
||||
CloseHandle(newstdin);
|
||||
CloseHandle(read_stdin);
|
||||
PostMessage(g_sdata.hwnd,WM_MAKENSIS_PROCESSCOMPLETE,0,0);
|
||||
FreeSpawn(&pi, read_stdout, 0);
|
||||
g_sdata.retcode = pi.dwProcessId;
|
||||
PostMessage(g_sdata.hwnd, WM_MAKENSIS_PROCESSCOMPLETE, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,6 +85,12 @@ namespace MakensisAPI {
|
|||
NOTIFY_ERROR,
|
||||
NOTIFY_OUTPUT
|
||||
};
|
||||
enum sndmsg_e {
|
||||
QUERYHOST = WM_APP
|
||||
};
|
||||
enum QUERYHOST_e {
|
||||
QH_OUTPUTCHARSET = 1
|
||||
};
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
|
|
|
@ -568,57 +568,73 @@ void ResetSymbols() {
|
|||
}
|
||||
}
|
||||
|
||||
int InitBranding() {
|
||||
TCHAR *s;
|
||||
TCHAR opt[] = _T(" /version");
|
||||
s = (TCHAR *)GlobalAlloc(GPTR,(lstrlen(EXENAME)+lstrlen(opt)+1)*sizeof(TCHAR));
|
||||
lstrcpy(s, EXENAME);
|
||||
lstrcat(s, opt);
|
||||
{
|
||||
STARTUPINFO si={sizeof(si),};
|
||||
SECURITY_ATTRIBUTES sa={sizeof(sa),};
|
||||
SECURITY_DESCRIPTOR sd={0,};
|
||||
PROCESS_INFORMATION pi={0,};
|
||||
HANDLE newstdout=0,read_stdout=0;
|
||||
void FreeSpawn(PROCESS_INFORMATION *pPI, HANDLE hRd, HANDLE hWr) {
|
||||
if (pPI) {
|
||||
GetExitCodeProcess(pPI->hProcess, &pPI->dwProcessId);
|
||||
CloseHandle(pPI->hProcess);
|
||||
CloseHandle(pPI->hThread);
|
||||
}
|
||||
CloseHandle(hRd);
|
||||
CloseHandle(hWr);
|
||||
}
|
||||
BOOL InitSpawn(STARTUPINFO &si, HANDLE &hRd, HANDLE &hWr) {
|
||||
OSVERSIONINFO osv = {sizeof(osv)};
|
||||
GetVersionEx(&osv);
|
||||
const bool winnt = VER_PLATFORM_WIN32_NT == osv.dwPlatformId;
|
||||
|
||||
OSVERSIONINFO osv={sizeof(osv)};
|
||||
GetVersionEx(&osv);
|
||||
if (osv.dwPlatformId == VER_PLATFORM_WIN32_NT) {
|
||||
InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
|
||||
SetSecurityDescriptorDacl(&sd,true,NULL,false);
|
||||
sa.lpSecurityDescriptor = &sd;
|
||||
}
|
||||
else sa.lpSecurityDescriptor = NULL;
|
||||
sa.bInheritHandle = true;
|
||||
if (!CreatePipe(&read_stdout,&newstdout,&sa,0)) {
|
||||
memset(&si, 0, sizeof(STARTUPINFO));
|
||||
si.cb = sizeof(STARTUPINFO);
|
||||
GetStartupInfo(&si);
|
||||
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
|
||||
SECURITY_ATTRIBUTES sa={sizeof(sa)};
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
if (winnt) {
|
||||
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
|
||||
SetSecurityDescriptorDacl(&sd, true, NULL, false);
|
||||
sa.lpSecurityDescriptor = &sd;
|
||||
}
|
||||
sa.bInheritHandle = true;
|
||||
BOOL okp = CreatePipe(&hRd, &hWr, &sa, 0);
|
||||
si.hStdOutput = hWr, si.hStdError = hWr;
|
||||
si.hStdInput = INVALID_HANDLE_VALUE;
|
||||
return okp;
|
||||
}
|
||||
|
||||
int InitBranding() {
|
||||
const TCHAR *opt = _T(" /version");
|
||||
UINT cch = lstrlen(EXENAME) + lstrlen(opt) + 1;
|
||||
TCHAR *s = (TCHAR *)GlobalAlloc(GPTR, cch*sizeof(TCHAR));
|
||||
if (s) {
|
||||
lstrcpy(s, EXENAME);
|
||||
lstrcat(s, opt);
|
||||
STARTUPINFO si;
|
||||
HANDLE newstdout, read_stdout;
|
||||
if (!InitSpawn(si, read_stdout, newstdout)) return 0;
|
||||
PROCESS_INFORMATION pi;
|
||||
if (!CreateProcess(0, s, 0, 0, TRUE, CREATE_NEW_CONSOLE, 0, 0, &si, &pi)) {
|
||||
FreeSpawn(0, read_stdout, newstdout);
|
||||
return 0;
|
||||
}
|
||||
GetStartupInfo(&si);
|
||||
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
si.hStdOutput = newstdout;
|
||||
si.hStdError = newstdout;
|
||||
if (!CreateProcess(NULL,s,NULL,NULL,TRUE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi)) {
|
||||
CloseHandle(newstdout);
|
||||
CloseHandle(read_stdout);
|
||||
return 0;
|
||||
char szBuf[1024], retval = 0;
|
||||
DWORD dwRead = 0;
|
||||
if (WAIT_OBJECT_0 == WaitForSingleObject(pi.hProcess, 10000)) {
|
||||
ReadFile(read_stdout, szBuf, sizeof(szBuf)-1, &dwRead, NULL);
|
||||
retval = 1;
|
||||
}
|
||||
char szBuf[1024];
|
||||
DWORD dwRead = 1;
|
||||
if (WaitForSingleObject(pi.hProcess,10000)!=WAIT_OBJECT_0) {
|
||||
return 0;
|
||||
}
|
||||
ReadFile(read_stdout, szBuf, sizeof(szBuf)-1, &dwRead, NULL);
|
||||
FreeSpawn(&pi, read_stdout, newstdout);
|
||||
szBuf[dwRead] = 0;
|
||||
int len = lstrlenA(szBuf);
|
||||
if (len==0) return 0;
|
||||
g_sdata.branding = (TCHAR *)GlobalAlloc(GPTR,(len+6)*sizeof(TCHAR));
|
||||
wsprintf(g_sdata.branding,_T("NSIS %hs"),szBuf);
|
||||
g_sdata.brandingv = (char *)GlobalAlloc(GPTR,len+1);
|
||||
lstrcpyA(g_sdata.brandingv,szBuf);
|
||||
if (len==0) retval = 0;
|
||||
g_sdata.branding = (TCHAR *)GlobalAlloc(GPTR, (len+6)*sizeof(TCHAR)); // LEAKED
|
||||
wsprintf(g_sdata.branding, _T("NSIS %hs"), szBuf);
|
||||
g_sdata.brandingv = (char *)GlobalAlloc(GPTR, len+1); // LEAKED
|
||||
lstrcpyA(g_sdata.brandingv, szBuf);
|
||||
GlobalFree(s);
|
||||
return retval;
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -627,7 +643,7 @@ void InitTooltips(HWND h) {
|
|||
memset(&g_tip,0,sizeof(NTOOLTIP));
|
||||
g_tip.tip_p = h;
|
||||
INITCOMMONCONTROLSEX icx;
|
||||
icx.dwSize = sizeof(icx);
|
||||
icx.dwSize = sizeof(icx);
|
||||
icx.dwICC = ICC_BAR_CLASSES;
|
||||
InitCommonControlsEx(&icx);
|
||||
DWORD dwStyle = WS_POPUP | WS_BORDER | TTS_ALWAYSTIP;
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
#define MRU_LIST_SIZE 5
|
||||
#define MRU_DISPLAY_LENGTH 40
|
||||
|
||||
void FreeSpawn(PROCESS_INFORMATION *pPI, HANDLE hRd, HANDLE hWr);
|
||||
BOOL InitSpawn(STARTUPINFO &si, HANDLE &hRd, HANDLE &hWr);
|
||||
|
||||
int SetArgv(const TCHAR *cmdLine, TCHAR ***argv);
|
||||
void SetTitle(HWND hwnd,const TCHAR *substr);
|
||||
void SetBranding(HWND hwnd);
|
||||
|
|
|
@ -87,7 +87,7 @@ int main( int argc, char *argv[] )
|
|||
WARNING: The subprocess can't parse GetCommandLine()
|
||||
to find its own path since we pass the wrong path! */
|
||||
if ( CreateProcess( szPath, GetCommandLine(), NULL, NULL,
|
||||
FALSE, 0, NULL, NULL, &si, &pi ) )
|
||||
TRUE, 0, NULL, NULL, &si, &pi ) )
|
||||
{
|
||||
WaitForSingleObject( pi.hProcess, INFINITE );
|
||||
GetExitCodeProcess( pi.hProcess, (DWORD*) &err );
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
|
||||
\define{NsisACPcp} system default ANSI codepage (ACP)
|
||||
|
||||
\define{NsisInputCharset} ACP|OEM|CP#|UTF8|UTF16LE|UTF16BE
|
||||
\define{NsisInputCharset} ACP|OEM|CP#|UTF8|UTF16<LE|BE>
|
||||
|
||||
\define{NsisOutputCharset} ACP|OEM|CP#|UTF8[SIG]|UTF16<LE|BE>[BOM]
|
||||
|
||||
\define{NsisWarnBlockContainerBegin} \\<div class=\\"wb\\"\\>
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ If you want to use MakeNSIS on the command line, the syntax of the makensis comm
|
|||
|
||||
\b /INPUTCHARSET allows you to specify a specific codepage for files without a BOM. (\NsisInputCharset)
|
||||
|
||||
\b /OUTPUTCHARSET allows you to specify the codepage used by stdout when the output is redirected. (\NsisOutputCharset)
|
||||
|
||||
\b Using the /D switch one or more times will add to symbols to the globally defined list (See !define).
|
||||
|
||||
\b Using the /X switch one or more times will execute the code you specify following it. Example: "/XAutoCloseWindow false"
|
||||
|
|
|
@ -26,7 +26,6 @@ makensis_files = Split("""
|
|||
tstring.cpp
|
||||
utf.cpp
|
||||
util.cpp
|
||||
validateunicode.cpp
|
||||
winchar.cpp
|
||||
writer.cpp
|
||||
""")
|
||||
|
@ -71,6 +70,7 @@ AddZLib(env, env['PLATFORM'], 'install-compiler')
|
|||
|
||||
##### Defines
|
||||
|
||||
env.Append(CPPDEFINES = ['MAKENSIS'])
|
||||
env.Append(CPPDEFINES = ['_WIN32_IE=0x0500'])
|
||||
|
||||
##### Set PCH
|
||||
|
|
|
@ -474,8 +474,7 @@ int CEXEBuild::add_string(const TCHAR *string, int process/*=1*/, UINT codepage/
|
|||
init_shellconstantvalues();
|
||||
if ((unsigned)-2 == codepage)
|
||||
{
|
||||
assert(curlinereader);
|
||||
codepage = curlinereader->StreamEncoding().GetCodepage();
|
||||
codepage = curlinereader ? curlinereader->StreamEncoding().GetCodepage() : CP_UTF8;
|
||||
// If the current source file is Unicode we have to pick a real codepage for ANSI!
|
||||
// It might not be the correct codepage but its the best we can do.
|
||||
// Not using CP_ACP to avoid heisenbugs when compiled on a different system.
|
||||
|
|
|
@ -80,6 +80,14 @@ namespace MakensisAPI {
|
|||
NOTIFY_ERROR,
|
||||
NOTIFY_OUTPUT // generated .exe file
|
||||
};
|
||||
#ifdef _WIN32
|
||||
enum sndmsg_e {
|
||||
QUERYHOST = WM_APP // QUERYHOST_e in wParam
|
||||
};
|
||||
enum QUERYHOST_e {
|
||||
QH_OUTPUTCHARSET = 1 // return (wincodepage+1) or 0 for default
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
#define PAGE_CUSTOM 0
|
||||
|
|
|
@ -36,12 +36,24 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
int g_noconfig=0;
|
||||
bool g_dopause=false;
|
||||
int g_display_errors=1;
|
||||
FILE *g_output=stdout;
|
||||
FILE *g_output;
|
||||
#ifdef _WIN32
|
||||
UINT g_wincon_orgoutcp;
|
||||
#ifdef _UNICODE
|
||||
UINT g_initialCodepage;
|
||||
WINSIO_OSDATA g_osdata_stdout;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void dopause(void)
|
||||
{
|
||||
if (!g_dopause) return;
|
||||
if (g_display_errors) _ftprintf(g_output,_T("MakeNSIS done - hit enter to close..."));
|
||||
fflush(stdout);
|
||||
int a;
|
||||
while ((a=_gettchar()) != _T('\r') && a != _T('\n') && a != 27/*esc*/);
|
||||
}
|
||||
|
||||
void quit()
|
||||
{
|
||||
|
@ -59,9 +71,7 @@ static void myatexit()
|
|||
ResetPrintColor();
|
||||
if (g_output != stdout && g_output) fclose(g_output);
|
||||
#ifdef _WIN32
|
||||
#ifdef _UNICODE
|
||||
SetConsoleOutputCP(g_initialCodepage);
|
||||
#endif
|
||||
SetConsoleOutputCP(g_wincon_orgoutcp);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -160,6 +170,7 @@ static void print_usage()
|
|||
_T(" ") OPT_STR _T("NOCONFIG disables inclusion of <path to makensis.exe>") PLATFORM_PATH_SEPARATOR_STR _T("nsisconf.nsh\n")
|
||||
_T(" ") OPT_STR _T("NOCD disabled the current directory change to that of the .nsi file\n")
|
||||
_T(" ") OPT_STR _T("INPUTCHARSET <") TSTR_INPUTCHARSET _T(">\n")
|
||||
_T(" ") OPT_STR _T("OUTPUTCHARSET <") TSTR_OUTPUTCHARSET _T(">\n")
|
||||
_T(" ") OPT_STR _T("Ddefine[=value] defines the symbol \"define\" for the script [to value]\n")
|
||||
_T(" ") OPT_STR _T("Xscriptcmd executes scriptcmd in script (i.e. \"") OPT_STR _T("XOutFile poop.exe\")\n")
|
||||
_T(" ") _T(" parameters are processed by order (") OPT_STR _T("Ddef ins.nsi != ins.nsi ") OPT_STR _T("Ddef)\n")
|
||||
|
@ -242,11 +253,11 @@ static int change_to_script_dir(CEXEBuild& build, tstring& script)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline bool HasReqParam(TCHAR**argv,int argi,int argc)
|
||||
static inline bool HasReqParam(TCHAR**argv,int argi,int argc,bool silent=false)
|
||||
{
|
||||
if (argi>=argc || !*argv[argi])
|
||||
{
|
||||
PrintColorFmtMsg_ERR(_T("Error: Missing required parameter!\n"));
|
||||
if (!silent) PrintColorFmtMsg_ERR(_T("Error: Missing required parameter!\n"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -263,29 +274,111 @@ int _tmain(int argc, TCHAR **argv)
|
|||
#ifdef NSIS_HPUX_ALLOW_UNALIGNED_DATA_ACCESS
|
||||
allow_unaligned_data_access();
|
||||
#endif
|
||||
assert(sizeof(wchar_t) > 1 && sizeof(wchar_t) <= 4 && sizeof(WORD) == 2);
|
||||
|
||||
HWND hostnotifyhandle=0;
|
||||
const TCHAR*stdoutredirname=0;
|
||||
NStreamEncoding inputenc, outputenc;
|
||||
int argpos=0;
|
||||
bool in_files=false;
|
||||
bool do_cd=true;
|
||||
bool no_logo=false;
|
||||
bool initialparsefail=false;
|
||||
bool noconfig=false;
|
||||
#ifdef _WIN32
|
||||
signed char outputbom=1;
|
||||
#endif
|
||||
|
||||
// Some parameters have to be parsed early so we can initialize stdout and the "host API".
|
||||
while (++argpos < argc && !initialparsefail)
|
||||
{
|
||||
if (!IS_OPT(argv[argpos])) break; // must be a filename, stop parsing
|
||||
if (!_tcscmp(argv[argpos], _T("--"))) break; // stop parsing
|
||||
if (_T('-') == argv[argpos][0] && !argv[argpos][1]) continue; // stdin
|
||||
|
||||
const TCHAR *swname = &argv[argpos][1];
|
||||
if (!_tcsicmp(swname,_T("VERSION"))) argc=0;
|
||||
else if (!_tcsicmp(swname,_T("NOTIFYHWND")))
|
||||
{
|
||||
initialparsefail=!HasReqParam(argv,++argpos,argc,true);
|
||||
if (initialparsefail) break;
|
||||
hostnotifyhandle=(HWND)_ttol(argv[argpos]);
|
||||
#ifdef _WIN32
|
||||
if (!IsWindow(hostnotifyhandle)) hostnotifyhandle=0;
|
||||
#endif
|
||||
}
|
||||
else if (!_tcsicmp(swname,_T("OUTPUTCHARSET")) || !_tcsicmp(swname,_T("OCS")))
|
||||
{
|
||||
initialparsefail=!HasReqParam(argv,++argpos,argc,true);
|
||||
if (initialparsefail) break;
|
||||
#ifdef _WIN32
|
||||
bool bom;
|
||||
WORD cp=GetEncodingFromString(argv[argpos],bom);
|
||||
if (NStreamEncoding::UNKNOWN == cp)
|
||||
{
|
||||
++initialparsefail;
|
||||
}
|
||||
else
|
||||
{
|
||||
outputbom=bom ? 1 : -1;
|
||||
outputenc.SetCodepage(cp);
|
||||
}
|
||||
#else
|
||||
outputenc.SetCodepage(NStreamEncoding::UNKNOWN);
|
||||
#endif
|
||||
}
|
||||
#ifdef _WIN32
|
||||
else if (!_tcsicmp(swname,_T("RAW")))
|
||||
{
|
||||
// Emulate the scratchpaper.com fork and its /RAW switch.
|
||||
// NOTE: Unlike the fork, we print \r\n and not just \n.
|
||||
outputbom=0;
|
||||
outputenc.SetCodepage(NStreamEncoding::UTF16LE);
|
||||
}
|
||||
#endif
|
||||
else if (S7IsChEqualI('v',swname[0]) && swname[1] && !swname[2])
|
||||
{
|
||||
no_logo=swname[1] >= _T('0') && swname[1] <= _T('2');
|
||||
}
|
||||
// This must be parsed last because it will eat other switches
|
||||
else if (S7IsChEqualI('o',swname[0]) && swname[1]) stdoutredirname=swname+1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
g_wincon_orgoutcp = GetConsoleOutputCP();
|
||||
#endif
|
||||
|
||||
init_signals(hostnotifyhandle);
|
||||
|
||||
|
||||
FILE*stdoutredir=stdout;
|
||||
if (stdoutredirname) stdoutredir=my_fopen(stdoutredirname,"w");
|
||||
g_output=stdoutredir;
|
||||
if (!g_output) g_output=stdout;
|
||||
#if defined(_WIN32) && defined(_UNICODE)
|
||||
if (hostnotifyhandle)
|
||||
{
|
||||
// The host can override the output format if they want to
|
||||
LPARAM lp=MAKELONG(outputenc.GetCodepage(),outputbom);
|
||||
LRESULT mr=SendMessage(hostnotifyhandle,MakensisAPI::QUERYHOST,MakensisAPI::QH_OUTPUTCHARSET,lp);
|
||||
if (mr) outputenc.SetCodepage((WORD)--mr), outputbom = -1;
|
||||
}
|
||||
|
||||
if (!WinStdIO_OStreamInit(g_osdata_stdout,g_output,outputenc.GetCodepage(),outputbom))
|
||||
{
|
||||
assert(!"StdIO init failed");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
// g_output is now initialized and Print*/_[f]tprintf can be used
|
||||
if (!stdoutredir) PrintColorFmtMsg_WARN(_T("Error opening output log for writing! Using stdout.\n"));
|
||||
|
||||
unsigned int nousage=0;
|
||||
unsigned int files_processed=0;
|
||||
unsigned int cmds_processed=0;
|
||||
|
||||
CEXEBuild build;
|
||||
NStreamEncoding inputenc;
|
||||
bool outputtried=0;
|
||||
bool in_files=0;
|
||||
bool do_cd=1;
|
||||
bool no_logo=0;
|
||||
int nousage=0;
|
||||
int argpos=1;
|
||||
int tmpargpos=1;
|
||||
int files_processed=0;
|
||||
int cmds_processed=0;
|
||||
|
||||
#ifdef _UNICODE
|
||||
#ifndef _O_U8TEXT
|
||||
const int _O_U8TEXT=0x40000; // BUGBUG: This is bogus (Makensis will ONLY work on NT6)
|
||||
#endif
|
||||
_setmode(_fileno(stdout), _O_U8TEXT); // set stdout to UTF-8
|
||||
#ifdef _WIN32
|
||||
g_initialCodepage = GetConsoleOutputCP();
|
||||
SetConsoleOutputCP(CP_UTF8); // set console output to UTF-8 (especially useful for subprocesses like !system)
|
||||
#endif
|
||||
#endif
|
||||
try
|
||||
{
|
||||
build.initialize(argv[0]);
|
||||
|
@ -296,66 +389,107 @@ int _tmain(int argc, TCHAR **argv)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (argc > 1 && IS_OPT(argv[tmpargpos]) && !_tcsicmp(&argv[tmpargpos][1],_T("VERSION")))
|
||||
#ifdef _WIN32
|
||||
build.notify_hwnd=hostnotifyhandle;
|
||||
#else
|
||||
const TCHAR*const badnonwinswitchfmt=OPT_STR _T("%s is disabled for non Win32 platforms.");
|
||||
if (hostnotifyhandle)
|
||||
build.warning(badnonwinswitchfmt,_T("NOTIFYHWND"));
|
||||
if (NStreamEncoding::UNKNOWN==outputenc.GetCodepage())
|
||||
build.warning(badnonwinswitchfmt,_T("OUTPUTCHARSET"));
|
||||
#endif // ~_WIN32
|
||||
|
||||
if (!argc)
|
||||
{
|
||||
_ftprintf(g_output,NSIS_VERSION);
|
||||
fflush(g_output);
|
||||
return 0;
|
||||
}
|
||||
if (argc > 1 && IS_OPT(argv[tmpargpos]) && S7IsChEqualI('v',argv[tmpargpos][1]))
|
||||
{
|
||||
if (argv[tmpargpos][2] <= _T('2') && argv[tmpargpos][2] >= _T('0'))
|
||||
{
|
||||
no_logo=1;
|
||||
}
|
||||
tmpargpos++;
|
||||
}
|
||||
|
||||
if (!no_logo)
|
||||
{
|
||||
if (argc > tmpargpos && IS_OPT(argv[tmpargpos]) && S7IsChEqualI('o',argv[tmpargpos][1]) && argv[tmpargpos][2])
|
||||
{
|
||||
g_output=FOPENTEXT(argv[tmpargpos]+2,"w");
|
||||
if (!g_output)
|
||||
{
|
||||
g_output=stdout; // Needs to be set before calling PrintColorFmtMsg*
|
||||
PrintColorFmtMsg_WARN(_T("Error opening output log for writing. Using stdout.\n"));
|
||||
}
|
||||
outputtried=1;
|
||||
}
|
||||
print_logo();
|
||||
}
|
||||
if (!g_output) g_output=stdout;
|
||||
|
||||
// Look for /NOTIFYHWND so we can init_signals()
|
||||
const int orgargpos=argpos;
|
||||
while (argpos < argc)
|
||||
{
|
||||
if (!_tcscmp(argv[argpos], _T("--"))) break;
|
||||
if (!IS_OPT(argv[argpos]) || !_tcscmp(argv[argpos], _T("-"))) break;
|
||||
if (!_tcsicmp(&argv[argpos][1],_T("NOTIFYHWND")))
|
||||
{
|
||||
if (!HasReqParam(argv, ++argpos, argc)) break;
|
||||
#ifdef _WIN32
|
||||
build.notify_hwnd=(HWND)_ttol(argv[argpos]);
|
||||
if (!IsWindow(build.notify_hwnd)) build.notify_hwnd=0;
|
||||
#else
|
||||
build.warning(OPT_STR _T("NOTIFYHWND is disabled for non Win32 platforms."));
|
||||
#endif
|
||||
}
|
||||
argpos++;
|
||||
}
|
||||
argpos=orgargpos;
|
||||
if (!no_logo) print_logo();
|
||||
|
||||
init_signals(build.notify_hwnd);
|
||||
|
||||
argpos=initialparsefail ? argc : 1;
|
||||
while (argpos < argc)
|
||||
{
|
||||
if (!_tcscmp(argv[argpos], _T("--")))
|
||||
in_files=1;
|
||||
else if (IS_OPT(argv[argpos]) && _tcscmp(argv[argpos], _T("-")) && !in_files)
|
||||
{
|
||||
if (S7IsChEqualI('d',argv[argpos][1]) && argv[argpos][2])
|
||||
if (!_tcsicmp(&argv[argpos][1],_T("NOCD"))) do_cd=false;
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("NOCONFIG"))) noconfig=true;
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("PAUSE"))) g_dopause=true;
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("LICENSE")))
|
||||
{
|
||||
if (build.display_info) print_license();
|
||||
nousage++;
|
||||
}
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("CMDHELP")))
|
||||
{
|
||||
if (argpos < argc-1)
|
||||
build.print_help(argv[++argpos]);
|
||||
else
|
||||
build.print_help(NULL);
|
||||
nousage++;
|
||||
}
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("HDRINFO")))
|
||||
{
|
||||
print_stub_info(build);
|
||||
nousage++;
|
||||
}
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("INPUTCHARSET")) || !_tcsicmp(&argv[argpos][1],_T("ICS")))
|
||||
{
|
||||
if (!HasReqParam(argv, ++argpos, argc)) break;
|
||||
WORD cp = GetEncodingFromString(argv[argpos]);
|
||||
if (NStreamEncoding::UNKNOWN == cp)
|
||||
{
|
||||
if (_tcsicmp(argv[argpos], _T("AUTO")))
|
||||
build.warning(OPT_STR _T("INPUTCHARSET: Ignoring invalid charset %s"), argv[argpos]);
|
||||
cp = NStreamEncoding::AUTO;
|
||||
}
|
||||
inputenc.SafeSetCodepage(cp);
|
||||
}
|
||||
else if (S7IsChEqualI('v',argv[argpos][1]) &&
|
||||
argv[argpos][2] >= _T('0') && argv[argpos][2] <= _T('4') && !argv[argpos][3])
|
||||
{
|
||||
int v=argv[argpos][2]-_T('0');
|
||||
build.display_script=v>3;
|
||||
build.display_info=v>2;
|
||||
build.display_warnings=v>1;
|
||||
build.display_errors=v>0;
|
||||
g_display_errors=build.display_errors;
|
||||
}
|
||||
else if (S7IsChEqualI('p',argv[argpos][1]) &&
|
||||
argv[argpos][2] >= _T('0') && argv[argpos][2] <= _T('5') && !argv[argpos][3])
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// priority setting added 01-2007 by Comm@nder21
|
||||
int p=argv[argpos][2]-_T('0');
|
||||
HANDLE hProc = GetCurrentProcess();
|
||||
struct
|
||||
{
|
||||
DWORD priority, fallback;
|
||||
} static const classes[] = {
|
||||
{IDLE_PRIORITY_CLASS, IDLE_PRIORITY_CLASS},
|
||||
{BELOW_NORMAL_PRIORITY_CLASS, IDLE_PRIORITY_CLASS},
|
||||
{NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS},
|
||||
{ABOVE_NORMAL_PRIORITY_CLASS, HIGH_PRIORITY_CLASS},
|
||||
{HIGH_PRIORITY_CLASS, HIGH_PRIORITY_CLASS},
|
||||
{REALTIME_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS}
|
||||
};
|
||||
if (SetPriorityClass(hProc, classes[p].priority) == FALSE)
|
||||
{
|
||||
SetPriorityClass(hProc, classes[p].fallback);
|
||||
}
|
||||
if (p == 5) build.warning(_T("makensis is running in REALTIME priority mode!"));
|
||||
#else
|
||||
build.warning(badnonwinswitchfmt,_T("Px"));
|
||||
#endif
|
||||
}
|
||||
// Already parsed these (must adjust argpos)
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("NOTIFYHWND"))) ++argpos;
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("OUTPUTCHARSET")) || !_tcsicmp(&argv[argpos][1],_T("OCS"))) ++argpos;
|
||||
// These must be parsed last because they will eat other switches
|
||||
else if (S7IsChEqualI('d',argv[argpos][1]) && argv[argpos][2])
|
||||
{
|
||||
TCHAR *p=argv[argpos]+2;
|
||||
TCHAR *s=_tcsdup(p),*v;
|
||||
|
@ -373,102 +507,12 @@ int _tmain(int argc, TCHAR **argv)
|
|||
}
|
||||
cmds_processed++;
|
||||
}
|
||||
else if (S7IsChEqualI('o',argv[argpos][1]) && argv[argpos][2])
|
||||
{
|
||||
if (!outputtried)
|
||||
{
|
||||
g_output=FOPENTEXT(argv[argpos]+2,"w");
|
||||
if (!g_output)
|
||||
{
|
||||
g_output=stdout; // Needs to be set before calling PrintColorFmtMsg*
|
||||
if (build.display_errors) PrintColorFmtMsg_WARN(_T("Error opening output log for writing. Using stdout.\n"));
|
||||
}
|
||||
outputtried=1;
|
||||
}
|
||||
}
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("NOCD"))) do_cd=0;
|
||||
else if (S7IsChEqualI('v',argv[argpos][1]) &&
|
||||
argv[argpos][2] >= _T('0') && argv[argpos][2] <= _T('4') && !argv[argpos][3])
|
||||
{
|
||||
int v=argv[argpos][2]-_T('0');
|
||||
build.display_script=v>3;
|
||||
build.display_info=v>2;
|
||||
build.display_warnings=v>1;
|
||||
build.display_errors=v>0;
|
||||
g_display_errors=build.display_errors;
|
||||
}
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("NOCONFIG"))) g_noconfig=1;
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("PAUSE"))) g_dopause=1;
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("LICENSE")))
|
||||
{
|
||||
if (build.display_info)
|
||||
{
|
||||
print_license();
|
||||
}
|
||||
nousage++;
|
||||
}
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("CMDHELP")))
|
||||
{
|
||||
if (argpos < argc-1)
|
||||
build.print_help(argv[++argpos]);
|
||||
else
|
||||
build.print_help(NULL);
|
||||
nousage++;
|
||||
}
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("NOTIFYHWND")))
|
||||
{
|
||||
++argpos; // already parsed this
|
||||
}
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("HDRINFO")))
|
||||
{
|
||||
print_stub_info(build);
|
||||
nousage++;
|
||||
}
|
||||
else if (S7IsChEqualI('p',argv[argpos][1]) &&
|
||||
argv[argpos][2] >= _T('0') && argv[argpos][2] <= _T('5') && !argv[argpos][3])
|
||||
{
|
||||
// Already parsed these
|
||||
#ifdef _WIN32
|
||||
// priority setting added 01-2007 by Comm@nder21
|
||||
int p=argv[argpos][2]-_T('0');
|
||||
HANDLE hProc = GetCurrentProcess();
|
||||
|
||||
struct
|
||||
{
|
||||
DWORD priority;
|
||||
DWORD fallback;
|
||||
} classes[] = {
|
||||
{IDLE_PRIORITY_CLASS, IDLE_PRIORITY_CLASS},
|
||||
{BELOW_NORMAL_PRIORITY_CLASS, IDLE_PRIORITY_CLASS},
|
||||
{NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS},
|
||||
{ABOVE_NORMAL_PRIORITY_CLASS, HIGH_PRIORITY_CLASS},
|
||||
{HIGH_PRIORITY_CLASS, HIGH_PRIORITY_CLASS},
|
||||
{REALTIME_PRIORITY_CLASS, REALTIME_PRIORITY_CLASS}
|
||||
};
|
||||
|
||||
if (SetPriorityClass(hProc, classes[p].priority) == FALSE)
|
||||
{
|
||||
SetPriorityClass(hProc, classes[p].fallback);
|
||||
}
|
||||
|
||||
if (p == 5)
|
||||
build.warning(_T("makensis is running in REALTIME priority mode!"));
|
||||
|
||||
#else
|
||||
build.warning(OPT_STR _T("Px is disabled for non Win32 platforms."));
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("RAW"))) {}
|
||||
#endif
|
||||
}
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("INPUTCHARSET")) || !_tcsicmp(&argv[argpos][1],_T("ICS")))
|
||||
{
|
||||
if (!HasReqParam(argv, ++argpos, argc)) break;
|
||||
WORD cp = GetEncodingFromString(argv[argpos]);
|
||||
if (NStreamEncoding::UNKNOWN == cp)
|
||||
{
|
||||
if (_tcsicmp(argv[argpos], _T("AUTO")))
|
||||
build.warning(OPT_STR _T("INPUTCHARSET: Ignoring invalid charset %s"), argv[argpos]);
|
||||
cp = NStreamEncoding::AUTO;
|
||||
}
|
||||
inputenc.SafeSetCodepage(cp);
|
||||
}
|
||||
else if (!_tcsicmp(&argv[argpos][1],_T("VERSION"))) {}
|
||||
else if (S7IsChEqualI('o',argv[argpos][1]) && argv[argpos][2]) {}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
@ -476,10 +520,10 @@ int _tmain(int argc, TCHAR **argv)
|
|||
{
|
||||
files_processed++;
|
||||
if (!_tcscmp(argv[argpos],_T("-")) && !in_files)
|
||||
g_dopause=0;
|
||||
if (!g_noconfig)
|
||||
g_dopause=false;
|
||||
if (!noconfig)
|
||||
{
|
||||
g_noconfig=1;
|
||||
noconfig=true;
|
||||
tstring main_conf;
|
||||
TCHAR* env_var = _tgetenv(_T("NSISCONFDIR"));
|
||||
if(env_var == NULL)
|
||||
|
|
|
@ -3241,6 +3241,9 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
|
|||
TCHAR *exec=line.gettoken_str(1);
|
||||
SCRIPT_MSG(_T("!execute: \"%s\"\n"),exec);
|
||||
#ifdef _WIN32
|
||||
#ifdef _UNICODE
|
||||
RunChildProcessRedirected(0,exec);
|
||||
#else
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFO si={sizeof(STARTUPINFO),};
|
||||
if (CreateProcess(NULL,exec,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi))
|
||||
|
@ -3249,6 +3252,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
|
|||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
TCHAR *execfixed = my_convert(exec);
|
||||
system(execfixed);
|
||||
|
|
|
@ -15,91 +15,10 @@
|
|||
#ifdef _UNICODE
|
||||
|
||||
#include "tstring.h"
|
||||
#include "validateunicode.h"
|
||||
#include "util.h"
|
||||
#include <vector>
|
||||
#include <stdio.h>
|
||||
|
||||
FILE* FileOpenUnicodeText(const TCHAR* file, const TCHAR* mode, BOOL* unicode)
|
||||
{
|
||||
extern FILE *g_output;
|
||||
CValidateUnicode::FILE_TYPE ftype = CValidateUnicode::UTF_8; // default file format is UTF-8
|
||||
if (unicode) *unicode = TRUE;
|
||||
|
||||
// If we are reading an existing file, check to see what type of file it
|
||||
// is first.
|
||||
if (_tcsstr(mode, _T("w+")) ||
|
||||
_tcsstr(mode, _T("r")))
|
||||
{
|
||||
FILE* fp = _tfopen(file, _T("rb"));
|
||||
|
||||
if (fp)
|
||||
{
|
||||
MANAGE_WITH(fp, fclose);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size_t fileSize = ftell(fp);
|
||||
if (fileSize == 0)
|
||||
{
|
||||
// Empty files are treated as UTF-8.
|
||||
ftype = CValidateUnicode::UTF_8;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<unsigned char> buffer(fileSize);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
fread(&buffer[0], sizeof(unsigned char), fileSize, fp);
|
||||
|
||||
ftype = CValidateUnicode::CheckBOM(&buffer[0], buffer.size());
|
||||
|
||||
switch (ftype)
|
||||
{
|
||||
case CValidateUnicode::UTF_8:
|
||||
case CValidateUnicode::UTF_16LE:
|
||||
case CValidateUnicode::UTF_16BE:
|
||||
break;
|
||||
case CValidateUnicode::UTF_32LE:
|
||||
case CValidateUnicode::UTF_32BE:
|
||||
PrintColorFmtMsg_ERR(_T("File '%s' has a BOM marked as %s which is not supported at this time.\n"),
|
||||
file, CValidateUnicode::TypeToName(ftype));
|
||||
exit(-1);
|
||||
break;
|
||||
case CValidateUnicode::UNKNOWN:
|
||||
// If unknown, let's see if it's not just UTF_8 without a BOM.
|
||||
if (CValidateUnicode::ValidateUTF8(&buffer[0], buffer.size()) == 2)
|
||||
{
|
||||
// contains UTF-8 characters sequences
|
||||
_ftprintf(g_output, _T("File '%s' has no BOM but seems to be UTF-8.\n"), file);
|
||||
ftype = CValidateUnicode::UTF_8;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PrintColorFmtMsg_ERR(_T("CValidateUnicode::CheckBOM() for file '%s' returned an unknown return value: %d\n"),
|
||||
file, ftype);
|
||||
exit(-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tstring strMode(mode);
|
||||
|
||||
switch (ftype)
|
||||
{
|
||||
case CValidateUnicode::UTF_8:
|
||||
strMode.append(_T(", ccs=UTF-8"));
|
||||
break;
|
||||
case CValidateUnicode::UTF_16LE:
|
||||
strMode.append(_T(", ccs=UTF-16LE"));
|
||||
break;
|
||||
default:
|
||||
// Looks like fopen() doesn't support other encodings of Unicode.
|
||||
if (unicode) *unicode = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return _tfopen(file, strMode.c_str());
|
||||
}
|
||||
|
||||
CtoTString::CtoTString(const char* str)
|
||||
{
|
||||
|
|
|
@ -28,17 +28,10 @@
|
|||
typedef std::wstring tstring;
|
||||
typedef std::wofstream tofstream;
|
||||
typedef std::wifstream tifstream;
|
||||
// Use the following macros to open text files.
|
||||
FILE* FileOpenUnicodeText(const TCHAR* file, const TCHAR* mode, BOOL* unicode);
|
||||
#define FOPENTEXT(file, mode) FileOpenUnicodeText(file, _T(mode), NULL)
|
||||
#define FOPENTEXT2(file, mode, unicode) FileOpenUnicodeText(file, _T(mode), unicode)
|
||||
#else
|
||||
typedef std::string tstring;
|
||||
typedef std::ofstream tofstream;
|
||||
typedef std::ifstream tifstream;
|
||||
// Use the following macros to open text files.
|
||||
#define FOPENTEXT(file, mode) fopen(file, mode)
|
||||
#define FOPENTEXT2(file, mode, unicode) (*(unicode)=FALSE, fopen(file, mode))
|
||||
#endif
|
||||
|
||||
#ifndef _UNICODE
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include "utf.h"
|
||||
#include "util.h"
|
||||
|
||||
#define FIX_ENDIAN_INT16LETOHOST_INPLACE FIX_ENDIAN_INT16_INPLACE
|
||||
|
||||
|
@ -259,10 +260,27 @@ bool WCToUTF16LEHlpr::Create(const TCHAR*in)
|
|||
}
|
||||
#endif
|
||||
|
||||
UINT DetectUTFBOM(void*Buffer, UINT cb)
|
||||
{
|
||||
unsigned char *b = (unsigned char*) Buffer;
|
||||
if (cb >= 3 && 0xef == b[0] && 0xbb == b[1] && 0xbf == b[2])
|
||||
return NStreamEncoding::UTF8;
|
||||
if (cb >= 2)
|
||||
{
|
||||
if (cb >= 4 && !b[0] && !b[1] && 0xfe == b[2] && 0xff == b[3])
|
||||
return NStreamEncoding::UTF32BE;
|
||||
if (0xff == b[0] && 0xfe == b[1])
|
||||
return (cb >= 4 && !b[2] && !b[3]) ? NStreamEncoding::UTF32LE : NStreamEncoding::UTF16LE;
|
||||
if (0xfe == b[0] && 0xff == b[1])
|
||||
return NStreamEncoding::UTF16BE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
UINT DetectUTFBOM(FILE*strm)
|
||||
{
|
||||
/*\
|
||||
Tries to detect a BOM at the start of a stream. If a BOM is found it is eaten.
|
||||
Tries to detect a BOM at the current position in a stream.
|
||||
If a BOM is found it is eaten.
|
||||
NOTE: ungetc is only guaranteed to support 1 pushback,
|
||||
lets hope no MBCS file starts with parts of a BOM.
|
||||
\*/
|
||||
|
@ -358,7 +376,8 @@ bool NBaseStream::Attach(FILE*hFile, WORD enc, bool Seek /*= true*/)
|
|||
{
|
||||
Close();
|
||||
m_hFile = hFile;
|
||||
if (!m_hFile || !NStream::SetBinaryMode(m_hFile)) return false;
|
||||
if (!m_hFile) return false;
|
||||
if (!NStream::SetBinaryMode(m_hFile) && m_hFile != stdin) return false;
|
||||
fpos_t pos;
|
||||
if (Seek && !fgetpos(m_hFile, &pos)) rewind(m_hFile); else Seek = false;
|
||||
WORD cp = DetectUTFBOM(m_hFile);
|
||||
|
@ -377,10 +396,36 @@ bool NOStream::WriteString(const wchar_t*Str, size_t cch /*= -1*/)
|
|||
CharEncConv cec;
|
||||
if (!cec.Initialize(m_Enc.GetCodepage(), -1)) return false;
|
||||
cec.SetAllowOptimizedReturn(true);
|
||||
if ((unsigned)-1 != cch) cch *= sizeof(wchar_t); // cec.Convert wants byte count
|
||||
size_t cbConv;
|
||||
char *p = (char*) cec.Convert(Str, cch, &cbConv);
|
||||
return p && WriteOctets(p, cbConv);
|
||||
}
|
||||
bool NOStream::WritePlatformNLString(const wchar_t*Str, size_t cch /*= -1*/)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
size_t cch2 = 0, nlcount = 0;
|
||||
for(; cch2 < cch && Str[cch2]; ++cch2) if (L'\n' == Str[cch2]) ++nlcount;
|
||||
if (nlcount)
|
||||
{
|
||||
cch = cch2 + nlcount;
|
||||
wchar_t chPrev = 0, *buf = (wchar_t*) malloc(cch * sizeof(wchar_t));
|
||||
if (!buf) return false;
|
||||
for(size_t s = 0, d = 0; d < cch; ++s, ++d)
|
||||
{
|
||||
if (L'\n' == Str[s])
|
||||
{
|
||||
if (L'\r' != chPrev) buf[d++] = L'\r'; else --cch;
|
||||
}
|
||||
buf[d] = chPrev = Str[s];
|
||||
}
|
||||
bool retval = WriteString(buf, cch);
|
||||
free(buf);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
return WriteString(Str, cch);
|
||||
}
|
||||
|
||||
tstring NStreamLineReader::GetErrorMessage(UINT Error, const TCHAR*Filename, UINT Line)
|
||||
{
|
||||
|
@ -450,26 +495,7 @@ l_restart:
|
|||
else
|
||||
#endif
|
||||
{
|
||||
if (0xC0 == (0xC0 & chU8[0]))
|
||||
{
|
||||
++cb;
|
||||
if (0xE0 == (0xE0 & chU8[0]))
|
||||
{
|
||||
++cb;
|
||||
if (0xF0 == (0xF0 & chU8[0]))
|
||||
{
|
||||
++cb;
|
||||
if (0xF8 == (0xF8 & chU8[0]))
|
||||
{
|
||||
++cb;
|
||||
if (0xFC == (0xFE & chU8[0]))
|
||||
++cb;
|
||||
else
|
||||
goto l_badutf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!UTF8_GetTrailCount(chU8[0], cb)) goto l_badutf;
|
||||
for(BYTE moreU8 = 0; moreU8 < cb;)
|
||||
{
|
||||
BYTE b;
|
||||
|
|
56
Source/utf.h
56
Source/utf.h
|
@ -19,22 +19,12 @@
|
|||
#define NSIS_UTF_H
|
||||
|
||||
#include "Platform.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "util.h" // For my_fopen
|
||||
#ifdef _WIN32
|
||||
#include <io.h> // For _setmode
|
||||
#include <fcntl.h> // For _O_BINARY
|
||||
#endif
|
||||
|
||||
const WORD UNICODE_REPLACEMENT_CHARACTER = 0xfffd;
|
||||
|
||||
#define TSTR_INPUTCHARSET _T("ACP|OEM|CP#|UTF8|UTF16<LE|BE>")
|
||||
#define TSTR_OUTPUTCHARSET _T("ACP|OEM|CP#|UTF8[SIG]|UTF16<LE|BE>[BOM]")
|
||||
|
||||
|
||||
void RawTStrToASCII(const TCHAR*in,char*out,UINT maxcch);
|
||||
|
||||
template<typename T> T S7ChLwr(T c) { return c>='A' && c<='Z' ? (T)(c|32) : c; }
|
||||
template<typename T> T S7ChUpr(T c) { return c>='a' && c<='z' ? (T)(c-'a'+'A') : c; }
|
||||
template<typename T> bool S7IsChEqualI(char ch,T cmp)
|
||||
|
@ -58,12 +48,51 @@ inline UINT32 CodePointFromUTF16SurrogatePair(unsigned short lea,unsigned short
|
|||
return ((UINT32)lea << 10) + tra + surrogate_offset;
|
||||
}
|
||||
|
||||
inline bool UTF8_GetTrailCount(unsigned char chFirst, unsigned char &cb)
|
||||
{
|
||||
// This function should only be used to get a rough idea of how large the encoded
|
||||
// codepoint is, just because it returns true does not mean that it is valid UTF-8!
|
||||
cb = 0;
|
||||
if (0xC0 == (0xC0 & chFirst))
|
||||
{
|
||||
++cb;
|
||||
if (0xE0 == (0xE0 & chFirst))
|
||||
{
|
||||
++cb;
|
||||
if (0xF0 == (0xF0 & chFirst))
|
||||
{
|
||||
++cb;
|
||||
if (0xF8 == (0xF8 & chFirst))
|
||||
{
|
||||
++cb;
|
||||
if (0xFC == (0xFE & chFirst)) ++cb; else return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MAKENSIS
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "tstring.h"
|
||||
#ifdef _WIN32
|
||||
#include <io.h> // For _setmode
|
||||
#include <fcntl.h> // For _O_BINARY
|
||||
#endif
|
||||
|
||||
FILE* my_fopen(const TCHAR *path, const char *mode); // from util.h
|
||||
|
||||
void RawTStrToASCII(const TCHAR*in,char*out,UINT maxcch);
|
||||
|
||||
void UTF16InplaceEndianSwap(void*Buffer, UINT cch);
|
||||
UINT StrLenUTF16(const void*str);
|
||||
bool StrSetUTF16LE(tstring&dest, const void*src);
|
||||
|
||||
UINT WCFromCodePoint(wchar_t*Dest,UINT cchDest,UINT32 CodPt);
|
||||
wchar_t* DupWCFromBytes(void*Buffer,UINT cbBuffer,WORD SrcCP);
|
||||
UINT DetectUTFBOM(void*Buffer,UINT cb);
|
||||
UINT DetectUTFBOM(FILE*strm);
|
||||
WORD GetEncodingFromString(const TCHAR*s, bool&BOM);
|
||||
WORD GetEncodingFromString(const TCHAR*s);
|
||||
|
@ -220,8 +249,9 @@ protected:
|
|||
NStreamEncoding m_Enc;
|
||||
|
||||
public:
|
||||
NBaseStream() : m_hFile(0) {}
|
||||
NBaseStream(FILE *hFile = 0) : m_hFile(hFile) {}
|
||||
~NBaseStream() { Close(); }
|
||||
|
||||
FILE* GetHandle() const { return m_hFile; }
|
||||
NStreamEncoding& StreamEncoding() { return m_Enc; }
|
||||
bool IsEOF() const { return feof(m_hFile) != 0; }
|
||||
|
@ -280,6 +310,8 @@ public:
|
|||
|
||||
class NOStream : public NBaseStream {
|
||||
public:
|
||||
NOStream(FILE *hFile = 0) : NBaseStream(hFile) {}
|
||||
|
||||
bool CreateFileForWriting(const TCHAR* Path, WORD enc = NStreamEncoding::AUTO)
|
||||
{
|
||||
return Attach(my_fopen(Path, "w+b"), enc);
|
||||
|
@ -314,6 +346,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
bool WriteString(const wchar_t*Str, size_t cch = -1);
|
||||
bool WritePlatformNLString(const wchar_t*Str, size_t cch = -1);
|
||||
};
|
||||
|
||||
class NStreamLineReader {
|
||||
|
@ -343,4 +376,5 @@ protected:
|
|||
}
|
||||
};
|
||||
|
||||
#endif // MAKENSIS
|
||||
#endif // NSIS_UTF_H
|
||||
|
|
241
Source/util.cpp
241
Source/util.cpp
|
@ -26,6 +26,7 @@
|
|||
#include "util.h"
|
||||
#include "strlist.h"
|
||||
#include "winchar.h"
|
||||
#include "utf.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <ctype.h>
|
||||
|
@ -50,21 +51,9 @@ namespace Apple { // defines struct section
|
|||
|
||||
using namespace std;
|
||||
|
||||
int g_dopause=0;
|
||||
extern int g_display_errors;
|
||||
extern FILE *g_output;
|
||||
|
||||
void dopause(void)
|
||||
{
|
||||
if (g_dopause)
|
||||
{
|
||||
if (g_display_errors) _ftprintf(g_output,_T("MakeNSIS done - hit enter to close..."));
|
||||
fflush(stdout);
|
||||
int a;
|
||||
while ((a=_gettchar()) != _T('\r') && a != _T('\n') && a != 27/*esc*/);
|
||||
}
|
||||
}
|
||||
|
||||
double my_wtof(const wchar_t *str)
|
||||
{
|
||||
char buf[100];
|
||||
|
@ -639,8 +628,119 @@ size_t ExpandoStrFmtVaList(wchar_t*Stack, size_t cchStack, wchar_t**ppMalloc, co
|
|||
return cch;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && defined(_UNICODE)
|
||||
int RunChildProcessRedirected(LPCWSTR cmdprefix, LPCWSTR cmdmain)
|
||||
{
|
||||
// We have to deliver the requested output encoding to our host (if any) and the
|
||||
// only way to do that is to convert the pipe content from what we hope is UTF-8.
|
||||
// The reason we need a pipe in the first place is because we cannot trust the
|
||||
// child to call GetConsoleOutputCP(), and even if we could, UTF-16 is not valid there.
|
||||
UINT cp = CP_UTF8, mbtwcf = MB_ERR_INVALID_CHARS;
|
||||
errno = ENOMEM;
|
||||
if (!cmdprefix) cmdprefix = _T("");
|
||||
UINT cch1 = _tcslen(cmdprefix), cch2 = _tcslen(cmdmain);
|
||||
WCHAR *cmd = (WCHAR*) malloc( (cch1 + cch2 + 1) * sizeof(WCHAR) );
|
||||
if (!cmd) return -1;
|
||||
_tcscpy(cmd, cmdprefix);
|
||||
_tcscat(cmd, cmdmain);
|
||||
SECURITY_DESCRIPTOR sd = {1, 0, SE_DACL_PRESENT, NULL, };
|
||||
SECURITY_ATTRIBUTES sa = {sizeof(sa), &sd, true};
|
||||
const UINT orgwinconcp = GetConsoleCP(), orgwinconoutcp = GetConsoleOutputCP();
|
||||
HANDLE hPipRd, hPipWr;
|
||||
PROCESS_INFORMATION pi;
|
||||
BOOL ok = CreatePipe(&hPipRd, &hPipWr, &sa, 0);
|
||||
if (!ok)
|
||||
hPipRd = 0, hPipWr = 0;
|
||||
else
|
||||
{
|
||||
STARTUPINFO si = {sizeof(si)};
|
||||
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_HIDE;
|
||||
si.hStdOutput = si.hStdError = hPipWr;
|
||||
si.hStdInput = INVALID_HANDLE_VALUE;
|
||||
errno = ECHILD;
|
||||
SetConsoleOutputCP(cp);
|
||||
ok = CreateProcess(0, cmd, 0, 0, TRUE, 0, 0, 0, &si, &pi);
|
||||
CloseHandle(hPipWr); // We want ERROR_BROKEN_PIPE when the child is done
|
||||
}
|
||||
free(cmd);
|
||||
DWORD childec = -1;
|
||||
if (ok)
|
||||
{
|
||||
bool utf8 = true, okt;
|
||||
char iobuf[512];
|
||||
DWORD cbRead, cbOfs = 0, cchwb = 0;
|
||||
WCHAR wbuf[100], wchbuf[2+1]; // A surrogate pair + \0
|
||||
for(;;)
|
||||
{
|
||||
BOOL okr = ReadFile(hPipRd, iobuf+cbOfs, sizeof(iobuf)-cbOfs, &cbRead, 0);
|
||||
cbRead += cbOfs, cbOfs = 0;
|
||||
unsigned char cbTrail, cch;
|
||||
for(DWORD i = 0; i < cbRead;)
|
||||
{
|
||||
cch = 0;
|
||||
if (utf8)
|
||||
{
|
||||
okt = UTF8_GetTrailCount(iobuf[i], cbTrail);
|
||||
if (!okt) // Not UTF-8? Switching to ACP
|
||||
{
|
||||
switchtoacp:cp = CP_ACP, mbtwcf = 0, utf8 = false;
|
||||
SetConsoleOutputCP(cp);
|
||||
continue;
|
||||
}
|
||||
if (!cbTrail) cch++, wchbuf[0] = iobuf[i]; // ASCII
|
||||
}
|
||||
else
|
||||
{
|
||||
cbTrail = !!IsDBCSLeadByteEx(cp, iobuf[i]);
|
||||
}
|
||||
if (i+cbTrail >= cbRead) // Read more first?
|
||||
{
|
||||
memmove(iobuf, iobuf+i, cbOfs = cbRead - i);
|
||||
if (okr) break; else i = 0;
|
||||
}
|
||||
if (!cch)
|
||||
{
|
||||
cch = MultiByteToWideChar(cp, mbtwcf, &iobuf[i], 1+cbTrail, wchbuf, COUNTOF(wchbuf)-1);
|
||||
if (!cch)
|
||||
{
|
||||
if (utf8) goto switchtoacp;
|
||||
cch++, wchbuf[0] = UNICODE_REPLACEMENT_CHARACTER;
|
||||
}
|
||||
}
|
||||
i += 1+cbTrail;
|
||||
if (0xfeff == wchbuf[0] && 1 == cch) cch = 0; // MakeNsisW is not a fan of the BOM, eat it.
|
||||
if (!cch) continue;
|
||||
wbuf[cchwb++] = wchbuf[0];
|
||||
if (--cch) wbuf[cchwb++] = wchbuf[1];
|
||||
const bool fullbuf = cchwb+cch >= COUNTOF(wbuf)-1; // cch is 1 for surrogate pairs
|
||||
if (!okr || fullbuf || L'\n' == wchbuf[0]) // Stop on \n so \r\n conversion has enough context (...\r\n vs ...\n)
|
||||
{
|
||||
#ifdef MAKENSIS
|
||||
extern WINSIO_OSDATA g_osdata_stdout;
|
||||
WinStdIO_OStreamWrite(g_osdata_stdout, wbuf, cchwb); // Faster than _ftprintf
|
||||
#else
|
||||
wbuf[cchwb] = L'\0';
|
||||
_ftprintf(g_output, _T("%s"), wbuf);
|
||||
#endif
|
||||
cchwb = 0;
|
||||
}
|
||||
}
|
||||
if (!okr) break;
|
||||
}
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
GetExitCodeProcess(pi.hProcess, &childec);
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
}
|
||||
SetConsoleCP(orgwinconcp); SetConsoleOutputCP(orgwinconoutcp);
|
||||
CloseHandle(hPipRd);
|
||||
return childec;
|
||||
}
|
||||
#endif
|
||||
|
||||
int sane_system(const TCHAR *command) {
|
||||
int sane_system(const TCHAR *command)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
// workaround for bug #1509909
|
||||
|
@ -653,17 +753,119 @@ int sane_system(const TCHAR *command) {
|
|||
// `program files\nsis\makensis.exe" "args`
|
||||
// which obviously fails...
|
||||
//
|
||||
// to avoid the stripping, a harmless string is prefixed
|
||||
// to the command line.
|
||||
tstring command_s = _T("IF 1==1 ");
|
||||
command_s += command;
|
||||
return _tsystem(command_s.c_str());
|
||||
// to avoid the stripping, a harmless string is prefixed to the command line.
|
||||
const TCHAR* prefix = _T("IF 1==1 ");
|
||||
#ifdef _UNICODE
|
||||
if (!command) return 0;
|
||||
if (!*command) return 1;
|
||||
tstring fixedcmd = _tgetenv(_T("COMSPEC"));
|
||||
if (!fixedcmd.length()) fixedcmd = _T("CMD.EXE");
|
||||
fixedcmd += _T(" /C ");
|
||||
fixedcmd += prefix;
|
||||
return RunChildProcessRedirected(fixedcmd.c_str(), command);
|
||||
#else
|
||||
tstring fixedcmd = prefix + _T("") + command;
|
||||
return _tsystem(fixedcmd.c_str());
|
||||
#endif
|
||||
|
||||
#else
|
||||
return _tsystem(command);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
bool GetFileSize64(HANDLE hFile, ULARGE_INTEGER &uli)
|
||||
{
|
||||
uli.LowPart = GetFileSize(hFile, &uli.HighPart);
|
||||
return INVALID_FILE_SIZE != uli.LowPart || !GetLastError();
|
||||
}
|
||||
#endif
|
||||
#if defined(_WIN32) && defined(_UNICODE) && defined(MAKENSIS)
|
||||
#include <io.h> // for _get_osfhandle
|
||||
bool WINAPI WinStdIO_OStreamInit(WINSIO_OSDATA&osd, FILE*strm, WORD cp, int bom)
|
||||
{
|
||||
// bom < 0: override cp if UTF detected but never write BOM
|
||||
// bom = 0: ignore BOM and force cp
|
||||
// bom > 0: override cp if UTF detected, write BOM if it does not already exist
|
||||
const int fd = _fileno(strm);
|
||||
osd.mode = 0, osd.hCRT = strm, osd.hNative = (HANDLE) _get_osfhandle(fd);
|
||||
if (INVALID_HANDLE_VALUE == osd.hNative) return false;
|
||||
DWORD conmode;
|
||||
if (GetConsoleMode(osd.hNative, &conmode)) osd.mode++; else osd.mode--;
|
||||
bool succ = NStream::SetBinaryMode(fd);
|
||||
DWORD cbio = 0;
|
||||
ULARGE_INTEGER uli;
|
||||
if (succ && GetFileSize64(osd.hNative, uli) && uli.QuadPart)
|
||||
{
|
||||
OVERLAPPED olap = {0}; // Used to read from start of file
|
||||
unsigned char bufbom[4];
|
||||
if (ReadFile(osd.hNative, bufbom, sizeof(bufbom), &cbio, &olap))
|
||||
{
|
||||
UINT detbom = DetectUTFBOM(bufbom, cbio);
|
||||
if (detbom) cp = (WORD) detbom, bom = 0;
|
||||
}
|
||||
SetFilePointer(osd.hNative, 0, 0, FILE_END);
|
||||
}
|
||||
osd.mustwritebom = bom > 0 && !cbio, osd.cp = cp;
|
||||
return succ || (sizeof(TCHAR)-1 && WinStdIO_IsConsole(osd)); // Don't care about BOM for WriteConsoleW
|
||||
}
|
||||
bool WINAPI WinStdIO_OStreamWrite(WINSIO_OSDATA&osd, const wchar_t *Str, UINT cch)
|
||||
{
|
||||
if ((unsigned)-1 == cch) cch = _tcslen(Str);
|
||||
DWORD cbio;
|
||||
if (WinStdIO_IsConsole(osd))
|
||||
return !!WriteConsoleW(osd.hNative, Str, cch, &cbio, 0) || !cch;
|
||||
NOStream strm(osd.hCRT);
|
||||
NStreamEncoding &enc = strm.StreamEncoding();
|
||||
enc.SetCodepage(osd.cp);
|
||||
bool retval = false;
|
||||
if (osd.mustwritebom)
|
||||
{
|
||||
osd.mustwritebom = false;
|
||||
if (enc.IsUnicode() && !strm.WriteBOM(enc))
|
||||
{
|
||||
osd.mode = 1, osd.hNative = 0; // Something is wrong, stop writing!
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
retval = strm.WritePlatformNLString(Str, cch);
|
||||
end:
|
||||
strm.Detach();
|
||||
return retval;
|
||||
}
|
||||
int WINAPI WinStdIO_vfwprintf(FILE*strm, const wchar_t*Fmt, va_list val)
|
||||
{
|
||||
if (g_output == strm && Fmt)
|
||||
{
|
||||
extern WINSIO_OSDATA g_osdata_stdout;
|
||||
ExpandoString<wchar_t, NSIS_MAX_STRLEN> buf;
|
||||
errno = ENOMEM;
|
||||
UINT cch = buf.StrFmt(Fmt, val, false);
|
||||
if (cch && !WinStdIO_OStreamWrite(g_osdata_stdout, buf, cch))
|
||||
{
|
||||
cch = 0, errno = EIO;
|
||||
}
|
||||
return cch ? cch : (*Fmt ? -1 : 0);
|
||||
}
|
||||
return vfwprintf(strm, Fmt, val);
|
||||
}
|
||||
int WinStdIO_fwprintf(FILE*strm, const wchar_t*Fmt, ...)
|
||||
{
|
||||
va_list val;
|
||||
va_start(val, Fmt);
|
||||
int rv = _vftprintf(strm, Fmt, val);
|
||||
va_end(val);
|
||||
return rv;
|
||||
}
|
||||
int WinStdIO_wprintf(const wchar_t*Fmt, ...)
|
||||
{
|
||||
va_list val;
|
||||
va_start(val, Fmt);
|
||||
int rv = _vftprintf(g_output, Fmt, val);
|
||||
va_end(val);
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
void PrintColorFmtMsg(unsigned int type, const TCHAR *fmtstr, va_list args)
|
||||
{
|
||||
|
@ -693,6 +895,9 @@ gottxtattrbak:
|
|||
case 1: txtattr = FOREGROUND_INTENSITY|FOREGROUND_GREEN|FOREGROUND_RED; break;
|
||||
case 2: txtattr = FOREGROUND_INTENSITY|FOREGROUND_RED; break;
|
||||
}
|
||||
// Use original background color if our text will still be readable
|
||||
if ((contxtattrbak & 0xF0) != (txtattr<<4)) txtattr |= (contxtattrbak & 0xF0);
|
||||
if ((txtattr & 0xFF) == 0xFE) txtattr &= ~FOREGROUND_INTENSITY; // BrightYellow on BrightWhite is hard to read
|
||||
SetConsoleTextAttribute(hWin32Con, txtattr);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -30,13 +30,9 @@
|
|||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
// these are the standard pause-before-quit stuff.
|
||||
extern int g_dopause;
|
||||
extern void dopause(void);
|
||||
|
||||
extern double my_wtof(const wchar_t *str);
|
||||
extern unsigned int my_strncpy(TCHAR*Dest, const TCHAR*Src, unsigned int cchMax);
|
||||
|
||||
|
@ -72,10 +68,10 @@ public:
|
|||
if (!p) throw std::bad_alloc();
|
||||
m_heap = (T*) p;
|
||||
}
|
||||
size_t StrFmt(const T*FmtStr, va_list Args)
|
||||
size_t StrFmt(const T*FmtStr, va_list Args, bool throwonerr = true)
|
||||
{
|
||||
size_t n = ExpandoStrFmtVaList(m_stack, COUNTOF(m_stack), &m_heap, FmtStr, Args);
|
||||
if (!n && *FmtStr) throw std::bad_alloc();
|
||||
if (throwonerr && !n && *FmtStr) throw std::bad_alloc();
|
||||
return n;
|
||||
}
|
||||
T* GetPtr() { return m_heap ? m_heap : m_stack; }
|
||||
|
@ -87,6 +83,34 @@ int sane_system(const TCHAR *command);
|
|||
void PrintColorFmtMsg(unsigned int type, const TCHAR *fmtstr, va_list args);
|
||||
void FlushOutputAndResetPrintColor();
|
||||
#ifdef _WIN32
|
||||
#ifdef _UNICODE
|
||||
int RunChildProcessRedirected(LPCWSTR cmdprefix, LPCWSTR cmdmain);
|
||||
#ifdef MAKENSIS
|
||||
typedef struct {
|
||||
HANDLE hNative;
|
||||
FILE*hCRT;
|
||||
WORD cp;
|
||||
signed char mode; // -1 = redirected, 0 = unknown, 1 = console
|
||||
bool mustwritebom;
|
||||
} WINSIO_OSDATA;
|
||||
inline bool WinStdIO_IsConsole(WINSIO_OSDATA&osd) { return osd.mode > 0; }
|
||||
inline bool WinStdIO_IsRedirected(WINSIO_OSDATA&osd) { return osd.mode < 0; }
|
||||
bool WINAPI WinStdIO_OStreamInit(WINSIO_OSDATA&osd, FILE*strm, WORD cp, int bom = 1);
|
||||
bool WINAPI WinStdIO_OStreamWrite(WINSIO_OSDATA&osd, const wchar_t *Str, UINT cch = -1);
|
||||
int WINAPI WinStdIO_vfwprintf(FILE*strm, const wchar_t*Fmt, va_list val);
|
||||
int WinStdIO_fwprintf(FILE*strm, const wchar_t*Fmt, ...);
|
||||
int WinStdIO_wprintf(const wchar_t*Fmt, ...);
|
||||
// We don't hook fflush since the native handle is only used with WriteConsoleW
|
||||
#undef _vsntprintf
|
||||
#define _vsntprintf Error: TODO
|
||||
#undef _tprintf
|
||||
#define _tprintf WinStdIO_wprintf
|
||||
#undef _ftprintf
|
||||
#define _ftprintf WinStdIO_fwprintf
|
||||
#undef _vftprintf
|
||||
#define _vftprintf WinStdIO_vfwprintf
|
||||
#endif // ~MAKENSIS
|
||||
#endif // ~_UNICODE
|
||||
#define ResetPrintColor() FlushOutputAndResetPrintColor() // For reset ONLY use PrintColorFmtMsg(0,NULL ...
|
||||
#define SetPrintColorWARN() PrintColorFmtMsg(1|0x10, NULL, (va_list)NULL)
|
||||
#define SetPrintColorERR() PrintColorFmtMsg(2|0x10, NULL, (va_list)NULL)
|
||||
|
@ -94,7 +118,7 @@ void FlushOutputAndResetPrintColor();
|
|||
#define ResetPrintColor()
|
||||
#define SetPrintColorWARN()
|
||||
#define SetPrintColorERR()
|
||||
#endif
|
||||
#endif // ~_WIN32
|
||||
inline void PrintColorFmtMsg_WARN(const TCHAR *fmtstr, ...)
|
||||
{
|
||||
va_list val;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue