7
static int KbdAnsi(char *Addr,int Size);
9
#if !defined(GUI) && !defined(SILENT)
10
static void RawPrint(char *Msg,MESSAGE_TYPE MessageType);
14
4
static MESSAGE_TYPE MsgStream=MSG_STDOUT;
15
5
static bool Sound=false;
16
6
const int MaxMsgSize=2*NM+2048;
9
static bool StdoutRedirected=false,StderrRedirected=false,StdinRedirected=false;
14
static bool IsRedirected(DWORD nStdHandle)
16
HANDLE hStd=GetStdHandle(nStdHandle);
18
return GetFileType(hStd)!=FILE_TYPE_CHAR || GetConsoleMode(hStd,&Mode)==0;
26
// We want messages like file names or progress percent to be printed
27
// immediately. Use only in Windows, in Unix they can cause wprintf %ls
28
// to fail with non-English strings.
32
// Detect if output is redirected and set output mode properly.
33
// We do not want to send Unicode output to files and especially to pipes
34
// like '|more', which cannot handle them correctly in Windows.
35
// In Unix console output is UTF-8 and it is handled correctly
36
// when redirecting, so no need to perform any adjustments.
37
StdoutRedirected=IsRedirected(STD_OUTPUT_HANDLE);
38
StderrRedirected=IsRedirected(STD_ERROR_HANDLE);
39
StdinRedirected=IsRedirected(STD_INPUT_HANDLE);
41
if (!StdoutRedirected)
42
_setmode(_fileno(stdout), _O_U16TEXT);
43
if (!StderrRedirected)
44
_setmode(_fileno(stderr), _O_U16TEXT);
18
50
void InitConsoleOptions(MESSAGE_TYPE MsgStream,bool Sound)
20
52
::MsgStream=MsgStream;
24
#if !defined(GUI) && !defined(SILENT)
25
void mprintf(const char *fmt,...)
58
static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist)
60
// This buffer is for format string only, not for entire output,
61
// so it can be short enough.
63
PrintfPrepareFmt(fmt,fmtw,ASIZE(fmtw));
65
safebuf wchar Msg[MaxMsgSize];
66
if (dest==stdout && StdoutRedirected || dest==stderr && StderrRedirected)
68
// Avoid Unicode for redirect in Windows, it does not work with pipes.
69
vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
70
safebuf char MsgA[MaxMsgSize];
71
WideToChar(Msg,MsgA,ASIZE(MsgA));
72
CharToOemA(MsgA,MsgA); // Console tools like 'more' expect OEM encoding.
74
// We already converted \n to \r\n above, so we use WriteFile instead
75
// of C library to avoid unnecessary additional conversion.
76
HANDLE hOut=GetStdHandle(dest==stdout ? STD_OUTPUT_HANDLE:STD_ERROR_HANDLE);
78
WriteFile(hOut,MsgA,(DWORD)strlen(MsgA),&Written,NULL);
81
// MSVC2008 vfwprintf writes every character to console separately
82
// and it is too slow. We use direct WriteConsole call instead.
83
vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
84
HANDLE hOut=GetStdHandle(dest==stderr ? STD_ERROR_HANDLE:STD_OUTPUT_HANDLE);
86
WriteConsole(hOut,Msg,(DWORD)wcslen(Msg),&Written,NULL);
88
vfwprintf(dest,fmtw,arglist);
89
// We do not use setbuf(NULL) in Unix (see comments in InitConsole).
95
void mprintf(const wchar *fmt,...)
27
97
if (MsgStream==MSG_NULL || MsgStream==MSG_ERRONLY)
32
vsnprintf(Msg,ASIZE(Msg),fmt,argptr);
34
// Different vsnprintf implementation can return either -1 or >=MaxMsgSize
35
// if string is truncated. So we do not check exit code and always zero
36
// terminate the string for safety. It is faster than check for error.
37
Msg[ASIZE(Msg)-1] = 0;
39
RawPrint(Msg,MsgStream);
100
fflush(stderr); // Ensure proper message order.
103
va_start(arglist,fmt);
104
FILE *dest=MsgStream==MSG_STDERR ? stderr:stdout;
105
cvt_wprintf(dest,fmt,arglist);
45
#if !defined(GUI) && !defined(SILENT)
46
void eprintf(const char *fmt,...)
112
void eprintf(const wchar *fmt,...)
48
114
if (MsgStream==MSG_NULL)
50
safebuf char Msg[MaxMsgSize];
53
vsnprintf(Msg,ASIZE(Msg),fmt,argptr);
55
// Different vsnprintf implementation can return either -1 or >=MaxMsgSize
56
// if string is truncated. So we do not check exit code and always zero
57
// terminate the string for safety. It is faster than check for error.
58
Msg[ASIZE(Msg)-1] = 0;
60
RawPrint(Msg,MSG_STDERR);
66
#if !defined(GUI) && !defined(SILENT)
67
void RawPrint(char *Msg,MESSAGE_TYPE MessageType)
73
OutFile.SetHandleType(FILE_HANDLESTD);
77
OutFile.SetHandleType(FILE_HANDLEERR);
85
char OutMsg[MaxMsgSize];
87
for (size_t I=0;Msg[I]!=0;I++)
89
if (Msg[I]=='\n' && (I==0 || Msg[I-1]!='\r') && OutPos<ASIZE(OutMsg)-1)
90
OutMsg[OutPos++]='\r';
91
if (OutPos<ASIZE(OutMsg)-1)
92
OutMsg[OutPos++]=Msg[I];
97
#if defined(_UNIX) || defined(_EMX)
98
char OutMsg[MaxMsgSize],*OutPos=OutMsg;
99
for (size_t I=0;Msg[I]!=0;I++)
106
OutFile.Write(Msg,strlen(Msg));
117
fflush(stdout); // Ensure proper message order.
120
va_start(arglist,fmt);
121
cvt_wprintf(stderr,fmt,arglist);
135
158
SetConsoleMode(hConIn,ENABLE_LINE_INPUT);
136
159
SetConsoleMode(hConOut,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT);
138
ReadConsoleW(hConIn,Str,MaxLength-1,&Read,NULL);
161
ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL);
140
163
SetConsoleMode(hConIn,ConInMode);
141
164
SetConsoleMode(hConOut,ConOutMode);
143
166
char StrA[MAXPASSWORD];
144
#if defined(_EMX) || defined(_BEOS) || defined(__sparc) || defined(sparc) || defined (__VMS)
167
#if defined(_EMX) || defined (__VMS)
145
168
fgets(StrA,ASIZE(StrA)-1,stdin);
170
strncpyz(StrA,getpassphrase(""),ASIZE(StrA));
147
172
strncpyz(StrA,getpass(""),ASIZE(StrA));
160
bool GetPassword(PASSWORD_TYPE Type,const char *FileName,const wchar *FileNameW,
161
SecPassword *Password)
184
bool GetConsolePassword(PASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
166
char PromptStr[NM+256];
167
#if defined(_EMX) || defined(_BEOS)
168
strcpy(PromptStr,St(MAskPswEcho));
170
strcpy(PromptStr,St(MAskPsw));
172
if (Type!=PASSWORD_GLOBAL)
174
strcat(PromptStr,St(MFor));
175
char *NameOnly=PointToName(FileName);
176
if (strlen(PromptStr)+strlen(NameOnly)<ASIZE(PromptStr))
177
strcat(PromptStr,NameOnly);
179
eprintf("\n%s: ",PromptStr);
190
if (Type==PASSWORD_GLOBAL)
191
eprintf(L"\n%s: ",St(MAskPsw));
193
eprintf(St(MAskPswFor),FileName);
181
195
wchar PlainPsw[MAXPASSWORD];
182
196
GetPasswordText(PlainPsw,ASIZE(PlainPsw));
183
197
if (*PlainPsw==0 && Type==PASSWORD_GLOBAL)
185
199
if (Type==PASSWORD_GLOBAL)
187
201
eprintf(St(MReAskPsw));
200
214
cleandata(PlainPsw,sizeof(PlainPsw));
208
#if !defined(GUI) && !defined(SILENT)
223
bool getwstr(wchar *str,size_t n)
213
#if defined(__GNUC__) || defined(sun)
214
EndOfFile=(fgets(Str,sizeof(Str),stdin)==NULL);
225
// Print buffered prompt title function before waiting for input.
229
#if defined(_WIN_ALL)
230
// fgetws does not work well with non-English text in Windows,
231
// so we do not use it.
232
if (StdinRedirected) // ReadConsole does not work if redirected.
234
// fgets does not work well with pipes in Windows in our test.
236
Array<char> StrA(n*4); // Up to 4 UTF-8 characters per wchar_t.
238
SrcFile.SetHandleType(FILE_HANDLESTD);
239
int ReadSize=SrcFile.Read(&StrA[0],StrA.Size()-1);
242
// Looks like stdin is a null device. We can enter to infinite loop
243
// calling Ask(), so let's better exit.
244
ErrHandler.Exit(RARX_USERBREAK);
247
CharToWide(&StrA[0],str,n);
252
if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE),str,DWORD(n-1),&ReadSize,NULL)==0)
217
SrcFile.SetHandleType(FILE_HANDLESTD);
218
EndOfFile=(SrcFile.Read(Str,sizeof(Str))==0);
257
if (fgetws(str,n,stdin)==NULL)
258
ErrHandler.Exit(RARX_USERBREAK); // Avoid infinite Ask() loop.
222
// Looks like stdin is a null device. We can enter to infinite loop
223
// calling Ask(), so let's better exit.
224
ErrHandler.Exit(RARX_USERBREAK);
231
#if !defined(GUI) && !defined(SILENT)
232
int Ask(const char *AskStr)
267
int Ask(const wchar *AskStr)
234
271
const int MaxItems=10;
235
char Item[MaxItems][40];
272
wchar Item[MaxItems][40];
236
273
int ItemKeyPos[MaxItems],NumItems=0;
238
for (const char *NextItem=AskStr;NextItem!=NULL;NextItem=strchr(NextItem+1,'_'))
275
for (const wchar *NextItem=AskStr;NextItem!=NULL;NextItem=wcschr(NextItem+1,'_'))
240
char *CurItem=Item[NumItems];
241
strncpyz(CurItem,NextItem+1,ASIZE(Item[0]));
242
char *EndItem=strchr(CurItem,'_');
277
wchar *CurItem=Item[NumItems];
278
wcsncpyz(CurItem,NextItem+1,ASIZE(Item[0]));
279
wchar *EndItem=wcschr(CurItem,'_');
243
280
if (EndItem!=NULL)
245
282
int KeyPos=0,CurKey;
260
297
for (int I=0;I<NumItems;I++)
262
eprintf(I==0 ? (NumItems>4 ? "\n":" "):", ");
299
eprintf(I==0 ? (NumItems>4 ? L"\n":L" "):L", ");
263
300
int KeyPos=ItemKeyPos[I];
264
301
for (int J=0;J<KeyPos;J++)
265
eprintf("%c",Item[I][J]);
266
eprintf("[%c]%s",Item[I][KeyPos],&Item[I][KeyPos+1]);
302
eprintf(L"%c",Item[I][J]);
303
eprintf(L"[%c]%ls",Item[I][KeyPos],&Item[I][KeyPos+1]);
270
#if defined(_WIN_ALL)
271
OemToCharBuffA((LPCSTR)&Ch,(LPSTR)&Ch,1);
307
getwstr(Str,ASIZE(Str));
308
wchar Ch=toupperw(Str[0]);
274
309
for (int I=0;I<NumItems;I++)
275
if (Ch==(byte)Item[I][ItemKeyPos[I]])
310
if (Ch==Item[I][ItemKeyPos[I]])
282
int KbdAnsi(char *Addr,size_t Size)
317
static bool IsCommentUnsafe(const wchar *Data,size_t Size)
286
319
for (size_t I=0;I<Size;I++)
287
if (Addr[I]==27 && Addr[I+1]=='[')
320
if (Data[I]==27 && Data[I+1]=='[')
289
321
for (size_t J=I+2;J<Size;J++)
293
if (!IsDigit(Addr[J]) && Addr[J]!=';')
323
// Return true for <ESC>[{key};"{string}"p used to redefine
324
// a keyboard key on some terminals.
327
if (!IsDigit(Data[J]) && Data[J]!=';')
303
void OutComment(char *Comment,size_t Size)
334
void OutComment(const wchar *Comment,size_t Size)
306
if (KbdAnsi(Comment,Size)==2)
336
if (IsCommentUnsafe(Comment,Size))
308
338
const size_t MaxOutSize=0x400;
309
339
for (size_t I=0;I<Size;I+=MaxOutSize)
311
char Msg[MaxOutSize+1];
341
wchar Msg[MaxOutSize+1];
312
342
size_t CopySize=Min(MaxOutSize,Size-I);
313
strncpy(Msg,Comment+I,CopySize);
343
wcsncpy(Msg,Comment+I,CopySize);