"Fossies" - the Fresh Open Source Software Archive 
Member "unrar/consio.cpp" (4 May 2022, 11213 Bytes) of package /linux/misc/unrarsrc-6.1.7.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "consio.cpp" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
6.1.4_vs_6.1.5.
1 #include "rar.hpp"
2 #include "log.cpp"
3
4 static MESSAGE_TYPE MsgStream=MSG_STDOUT;
5 static RAR_CHARSET RedirectCharset=RCH_DEFAULT;
6 static bool ProhibitInput=false;
7
8 const int MaxMsgSize=2*NM+2048;
9
10 static bool StdoutRedirected=false,StderrRedirected=false,StdinRedirected=false;
11
12 #ifdef _WIN_ALL
13 static bool IsRedirected(DWORD nStdHandle)
14 {
15 HANDLE hStd=GetStdHandle(nStdHandle);
16 DWORD Mode;
17 return GetFileType(hStd)!=FILE_TYPE_CHAR || GetConsoleMode(hStd,&Mode)==0;
18 }
19 #endif
20
21
22 void InitConsole()
23 {
24 #ifdef _WIN_ALL
25 // We want messages like file names or progress percent to be printed
26 // immediately. Use only in Windows, in Unix they can cause wprintf %ls
27 // to fail with non-English strings.
28 setbuf(stdout,NULL);
29 setbuf(stderr,NULL);
30
31 // Detect if output is redirected and set output mode properly.
32 // We do not want to send Unicode output to files and especially to pipes
33 // like '|more', which cannot handle them correctly in Windows.
34 // In Unix console output is UTF-8 and it is handled correctly
35 // when redirecting, so no need to perform any adjustments.
36 StdoutRedirected=IsRedirected(STD_OUTPUT_HANDLE);
37 StderrRedirected=IsRedirected(STD_ERROR_HANDLE);
38 StdinRedirected=IsRedirected(STD_INPUT_HANDLE);
39 #ifdef _MSC_VER
40 if (!StdoutRedirected)
41 _setmode(_fileno(stdout), _O_U16TEXT);
42 if (!StderrRedirected)
43 _setmode(_fileno(stderr), _O_U16TEXT);
44 #endif
45 #elif defined(_UNIX)
46 StdoutRedirected=!isatty(fileno(stdout));
47 StderrRedirected=!isatty(fileno(stderr));
48 StdinRedirected=!isatty(fileno(stdin));
49 #endif
50 }
51
52
53 void SetConsoleMsgStream(MESSAGE_TYPE MsgStream)
54 {
55 ::MsgStream=MsgStream;
56 }
57
58
59 void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset)
60 {
61 ::RedirectCharset=RedirectCharset;
62 }
63
64
65 void ProhibitConsoleInput()
66 {
67 ProhibitInput=true;
68 }
69
70
71 #ifndef SILENT
72 static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist)
73 {
74 // This buffer is for format string only, not for entire output,
75 // so it can be short enough.
76 wchar fmtw[1024];
77 PrintfPrepareFmt(fmt,fmtw,ASIZE(fmtw));
78 #ifdef _WIN_ALL
79 safebuf wchar Msg[MaxMsgSize];
80 if (dest==stdout && StdoutRedirected || dest==stderr && StderrRedirected)
81 {
82 HANDLE hOut=GetStdHandle(dest==stdout ? STD_OUTPUT_HANDLE:STD_ERROR_HANDLE);
83 vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
84 DWORD Written;
85 if (RedirectCharset==RCH_UNICODE)
86 WriteFile(hOut,Msg,(DWORD)wcslen(Msg)*sizeof(*Msg),&Written,NULL);
87 else
88 {
89 // Avoid Unicode for redirect in Windows, it does not work with pipes.
90 safebuf char MsgA[MaxMsgSize];
91 if (RedirectCharset==RCH_UTF8)
92 WideToUtf(Msg,MsgA,ASIZE(MsgA));
93 else
94 WideToChar(Msg,MsgA,ASIZE(MsgA));
95 if (RedirectCharset==RCH_DEFAULT || RedirectCharset==RCH_OEM)
96 CharToOemA(MsgA,MsgA); // Console tools like 'more' expect OEM encoding.
97
98 // We already converted \n to \r\n above, so we use WriteFile instead
99 // of C library to avoid unnecessary additional conversion.
100 WriteFile(hOut,MsgA,(DWORD)strlen(MsgA),&Written,NULL);
101 }
102 return;
103 }
104 // MSVC2008 vfwprintf writes every character to console separately
105 // and it is too slow. We use direct WriteConsole call instead.
106 vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
107 HANDLE hOut=GetStdHandle(dest==stderr ? STD_ERROR_HANDLE:STD_OUTPUT_HANDLE);
108 DWORD Written;
109 WriteConsole(hOut,Msg,(DWORD)wcslen(Msg),&Written,NULL);
110 #else
111 vfwprintf(dest,fmtw,arglist);
112 // We do not use setbuf(NULL) in Unix (see comments in InitConsole).
113 fflush(dest);
114 #endif
115 }
116
117
118 void mprintf(const wchar *fmt,...)
119 {
120 if (MsgStream==MSG_NULL || MsgStream==MSG_ERRONLY)
121 return;
122
123 fflush(stderr); // Ensure proper message order.
124
125 va_list arglist;
126 va_start(arglist,fmt);
127 FILE *dest=MsgStream==MSG_STDERR ? stderr:stdout;
128 cvt_wprintf(dest,fmt,arglist);
129 va_end(arglist);
130 }
131 #endif
132
133
134 #ifndef SILENT
135 void eprintf(const wchar *fmt,...)
136 {
137 if (MsgStream==MSG_NULL)
138 return;
139
140 fflush(stdout); // Ensure proper message order.
141
142 va_list arglist;
143 va_start(arglist,fmt);
144 cvt_wprintf(stderr,fmt,arglist);
145 va_end(arglist);
146 }
147 #endif
148
149
150 #ifndef SILENT
151 static void QuitIfInputProhibited()
152 {
153 // We cannot handle user prompts if -si is used to read file or archive data
154 // from stdin.
155 if (ProhibitInput)
156 {
157 mprintf(St(MStdinNoInput));
158 ErrHandler.Exit(RARX_FATAL);
159 }
160 }
161
162
163 static void GetPasswordText(wchar *Str,uint MaxLength)
164 {
165 if (MaxLength==0)
166 return;
167 QuitIfInputProhibited();
168 if (StdinRedirected)
169 getwstr(Str,MaxLength); // Read from pipe or redirected file.
170 else
171 {
172 #ifdef _WIN_ALL
173 HANDLE hConIn=GetStdHandle(STD_INPUT_HANDLE);
174 DWORD ConInMode;
175 GetConsoleMode(hConIn,&ConInMode);
176 SetConsoleMode(hConIn,ENABLE_LINE_INPUT); // Remove ENABLE_ECHO_INPUT.
177
178 // We prefer ReadConsole to ReadFile, so we can read Unicode input.
179 DWORD Read=0;
180 ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL);
181 Str[Read]=0;
182 SetConsoleMode(hConIn,ConInMode);
183
184 // If entered password is longer than MAXPASSWORD and truncated,
185 // read its unread part anyway, so it isn't read later as the second
186 // password for -p switch. Low level FlushConsoleInputBuffer doesn't help
187 // for high level ReadConsole, which in line input mode seems to store
188 // the rest of string in its own internal buffer.
189 if (wcschr(Str,'\r')==NULL) // If '\r' is missing, the password was truncated.
190 while (true)
191 {
192 wchar Trail[64];
193 DWORD TrailRead=0;
194 // Use ASIZE(Trail)-1 to reserve the space for trailing 0.
195 ReadConsole(hConIn,Trail,ASIZE(Trail)-1,&TrailRead,NULL);
196 Trail[TrailRead]=0;
197 if (TrailRead==0 || wcschr(Trail,'\r')!=NULL)
198 break;
199 }
200
201 #else
202 char StrA[MAXPASSWORD*4]; // "*4" for multibyte UTF-8 characters.
203 #if defined(_EMX) || defined (__VMS)
204 fgets(StrA,ASIZE(StrA)-1,stdin);
205 #elif defined(__sun)
206 strncpyz(StrA,getpassphrase(""),ASIZE(StrA));
207 #else
208 strncpyz(StrA,getpass(""),ASIZE(StrA));
209 #endif
210 CharToWide(StrA,Str,MaxLength);
211 cleandata(StrA,sizeof(StrA));
212 #endif
213 }
214 Str[MaxLength-1]=0;
215 RemoveLF(Str);
216 }
217 #endif
218
219
220 #ifndef SILENT
221 bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
222 {
223 if (!StdinRedirected)
224 uiAlarm(UIALARM_QUESTION);
225
226 while (true)
227 {
228 // if (!StdinRedirected)
229 if (Type==UIPASSWORD_GLOBAL)
230 eprintf(L"\n%s: ",St(MAskPsw));
231 else
232 eprintf(St(MAskPswFor),FileName);
233
234 wchar PlainPsw[MAXPASSWORD+1];
235 GetPasswordText(PlainPsw,ASIZE(PlainPsw));
236 if (*PlainPsw==0 && Type==UIPASSWORD_GLOBAL)
237 return false;
238 if (wcslen(PlainPsw)>=MAXPASSWORD)
239 {
240 PlainPsw[MAXPASSWORD-1]=0;
241 uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
242 }
243 if (!StdinRedirected && Type==UIPASSWORD_GLOBAL)
244 {
245 eprintf(St(MReAskPsw));
246 wchar CmpStr[MAXPASSWORD];
247 GetPasswordText(CmpStr,ASIZE(CmpStr));
248 if (*CmpStr==0 || wcscmp(PlainPsw,CmpStr)!=0)
249 {
250 eprintf(St(MNotMatchPsw));
251 cleandata(PlainPsw,sizeof(PlainPsw));
252 cleandata(CmpStr,sizeof(CmpStr));
253 continue;
254 }
255 cleandata(CmpStr,sizeof(CmpStr));
256 }
257 Password->Set(PlainPsw);
258 cleandata(PlainPsw,sizeof(PlainPsw));
259 break;
260 }
261 return true;
262 }
263 #endif
264
265
266 #ifndef SILENT
267 bool getwstr(wchar *str,size_t n)
268 {
269 // Print buffered prompt title function before waiting for input.
270 fflush(stderr);
271
272 QuitIfInputProhibited();
273
274 *str=0;
275 #if defined(_WIN_ALL)
276 // fgetws does not work well with non-English text in Windows,
277 // so we do not use it.
278 if (StdinRedirected) // ReadConsole does not work if redirected.
279 {
280 // fgets does not work well with pipes in Windows in our test.
281 // Let's use files.
282 Array<char> StrA(n*4); // Up to 4 UTF-8 characters per wchar_t.
283 File SrcFile;
284 SrcFile.SetHandleType(FILE_HANDLESTD);
285 SrcFile.SetLineInputMode(true);
286 int ReadSize=SrcFile.Read(&StrA[0],StrA.Size()-1);
287 if (ReadSize<=0)
288 {
289 // Looks like stdin is a null device. We can enter to infinite loop
290 // calling Ask(), so let's better exit.
291 ErrHandler.Exit(RARX_USERBREAK);
292 }
293 StrA[ReadSize]=0;
294
295 // We expect ANSI encoding here, but "echo text|rar ..." to pipe to RAR,
296 // such as send passwords, we get OEM encoding by default, unless we
297 // use "chcp" in console. But we avoid OEM to ANSI conversion,
298 // because we also want to handle ANSI files redirection correctly,
299 // like "rar ... < ansifile.txt".
300 CharToWide(&StrA[0],str,n);
301 cleandata(&StrA[0],StrA.Size()); // We can use this function to enter passwords.
302 }
303 else
304 {
305 DWORD ReadSize=0;
306 if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE),str,DWORD(n-1),&ReadSize,NULL)==0)
307 return false;
308 str[ReadSize]=0;
309 }
310 #else
311 if (fgetws(str,n,stdin)==NULL)
312 ErrHandler.Exit(RARX_USERBREAK); // Avoid infinite Ask() loop.
313 #endif
314 RemoveLF(str);
315 return true;
316 }
317 #endif
318
319
320 #ifndef SILENT
321 // We allow this function to return 0 in case of invalid input,
322 // because it might be convenient to press Enter to some not dangerous
323 // prompts like "insert disk with next volume". We should call this function
324 // again in case of 0 in dangerous prompt such as overwriting file.
325 int Ask(const wchar *AskStr)
326 {
327 uiAlarm(UIALARM_QUESTION);
328
329 const int MaxItems=10;
330 wchar Item[MaxItems][40];
331 int ItemKeyPos[MaxItems],NumItems=0;
332
333 for (const wchar *NextItem=AskStr;NextItem!=NULL;NextItem=wcschr(NextItem+1,'_'))
334 {
335 wchar *CurItem=Item[NumItems];
336 wcsncpyz(CurItem,NextItem+1,ASIZE(Item[0]));
337 wchar *EndItem=wcschr(CurItem,'_');
338 if (EndItem!=NULL)
339 *EndItem=0;
340 int KeyPos=0,CurKey;
341 while ((CurKey=CurItem[KeyPos])!=0)
342 {
343 bool Found=false;
344 for (int I=0;I<NumItems && !Found;I++)
345 if (toupperw(Item[I][ItemKeyPos[I]])==toupperw(CurKey))
346 Found=true;
347 if (!Found && CurKey!=' ')
348 break;
349 KeyPos++;
350 }
351 ItemKeyPos[NumItems]=KeyPos;
352 NumItems++;
353 }
354
355 for (int I=0;I<NumItems;I++)
356 {
357 eprintf(I==0 ? (NumItems>3 ? L"\n":L" "):L", ");
358 int KeyPos=ItemKeyPos[I];
359 for (int J=0;J<KeyPos;J++)
360 eprintf(L"%c",Item[I][J]);
361 eprintf(L"[%c]%ls",Item[I][KeyPos],&Item[I][KeyPos+1]);
362 }
363 eprintf(L" ");
364 wchar Str[50];
365 getwstr(Str,ASIZE(Str));
366 wchar Ch=toupperw(Str[0]);
367 for (int I=0;I<NumItems;I++)
368 if (Ch==Item[I][ItemKeyPos[I]])
369 return I+1;
370 return 0;
371 }
372 #endif
373
374
375 static bool IsCommentUnsafe(const wchar *Data,size_t Size)
376 {
377 for (size_t I=0;I<Size;I++)
378 if (Data[I]==27 && Data[I+1]=='[')
379 for (size_t J=I+2;J<Size;J++)
380 {
381 // Return true for <ESC>[{key};"{string}"p used to redefine
382 // a keyboard key on some terminals.
383 if (Data[J]=='\"')
384 return true;
385 if (!IsDigit(Data[J]) && Data[J]!=';')
386 break;
387 }
388 return false;
389 }
390
391
392 void OutComment(const wchar *Comment,size_t Size)
393 {
394 if (IsCommentUnsafe(Comment,Size))
395 return;
396 const size_t MaxOutSize=0x400;
397 for (size_t I=0;I<Size;I+=MaxOutSize)
398 {
399 wchar Msg[MaxOutSize+1];
400 size_t CopySize=Min(MaxOutSize,Size-I);
401 wcsncpy(Msg,Comment+I,CopySize);
402 Msg[CopySize]=0;
403 mprintf(L"%s",Msg);
404 }
405 mprintf(L"\n");
406 }