@@ -220,3 +220,141 @@ impl IntoRawSocket for net::UdpSocket {
220
220
self . into_inner ( ) . into_socket ( ) . into_inner ( )
221
221
}
222
222
}
223
+
224
+ #[ unstable( feature = "is_atty" , issue = "80937" ) ]
225
+ impl io:: IsAtty for sys:: stdio:: Stdin {
226
+ fn is_atty ( ) -> bool {
227
+ use c:: {
228
+ STD_ERROR_HANDLE as STD_ERROR , STD_INPUT_HANDLE as STD_INPUT ,
229
+ STD_OUTPUT_HANDLE as STD_OUTPUT ,
230
+ } ;
231
+
232
+ let fd = STD_INPUT ;
233
+ let others = [ STD_ERROR , STD_OUTPUT ] ;
234
+
235
+ if unsafe { console_on_any ( & [ fd] ) } {
236
+ // False positives aren't possible. If we got a console then
237
+ // we definitely have a tty on stdin.
238
+ return true ;
239
+ }
240
+
241
+ // At this point, we *could* have a false negative. We can determine that
242
+ // this is true negative if we can detect the presence of a console on
243
+ // any of the other streams. If another stream has a console, then we know
244
+ // we're in a Windows console and can therefore trust the negative.
245
+ if unsafe { console_on_any ( & others) } {
246
+ return false ;
247
+ }
248
+
249
+ // Otherwise, we fall back to a very strange msys hack to see if we can
250
+ // sneakily detect the presence of a tty.
251
+ unsafe { msys_tty_on ( fd) }
252
+ }
253
+ }
254
+
255
+ #[ unstable( feature = "is_atty" , issue = "80937" ) ]
256
+ impl io:: IsAtty for sys:: stdio:: Stdout {
257
+ fn is_atty ( ) -> bool {
258
+ use c:: {
259
+ STD_ERROR_HANDLE as STD_ERROR , STD_INPUT_HANDLE as STD_INPUT ,
260
+ STD_OUTPUT_HANDLE as STD_OUTPUT ,
261
+ } ;
262
+
263
+ let fd = STD_OUTPUT ;
264
+ let others = [ STD_INPUT , STD_ERROR ] ;
265
+
266
+ if unsafe { console_on_any ( & [ fd] ) } {
267
+ // False positives aren't possible. If we got a console then
268
+ // we definitely have a tty on stdin.
269
+ return true ;
270
+ }
271
+
272
+ // At this point, we *could* have a false negative. We can determine that
273
+ // this is true negative if we can detect the presence of a console on
274
+ // any of the other streams. If another stream has a console, then we know
275
+ // we're in a Windows console and can therefore trust the negative.
276
+ if unsafe { console_on_any ( & others) } {
277
+ return false ;
278
+ }
279
+
280
+ // Otherwise, we fall back to a very strange msys hack to see if we can
281
+ // sneakily detect the presence of a tty.
282
+ unsafe { msys_tty_on ( fd) }
283
+ }
284
+ }
285
+
286
+ #[ unstable( feature = "is_atty" , issue = "80937" ) ]
287
+ impl io:: IsAtty for sys:: stdio:: Stderr {
288
+ fn is_atty ( ) -> bool {
289
+ use c:: {
290
+ STD_ERROR_HANDLE as STD_ERROR , STD_INPUT_HANDLE as STD_INPUT ,
291
+ STD_OUTPUT_HANDLE as STD_OUTPUT ,
292
+ } ;
293
+
294
+ let fd = STD_ERROR ;
295
+ let others = [ STD_INPUT , STD_OUTPUT ] ;
296
+
297
+ if unsafe { console_on_any ( & [ fd] ) } {
298
+ // False positives aren't possible. If we got a console then
299
+ // we definitely have a tty on stdin.
300
+ return true ;
301
+ }
302
+
303
+ // At this point, we *could* have a false negative. We can determine that
304
+ // this is true negative if we can detect the presence of a console on
305
+ // any of the other streams. If another stream has a console, then we know
306
+ // we're in a Windows console and can therefore trust the negative.
307
+ if unsafe { console_on_any ( & others) } {
308
+ return false ;
309
+ }
310
+
311
+ // Otherwise, we fall back to a very strange msys hack to see if we can
312
+ // sneakily detect the presence of a tty.
313
+ unsafe { msys_tty_on ( fd) }
314
+ }
315
+ }
316
+
317
+ #[ unstable( feature = "is_atty" , issue = "80937" ) ]
318
+ unsafe fn console_on_any ( fds : & [ c:: DWORD ] ) -> bool {
319
+ use c:: { GetConsoleMode , GetStdHandle } ;
320
+
321
+ for & fd in fds {
322
+ let mut out = 0 ;
323
+ let handle = GetStdHandle ( fd) ;
324
+ if GetConsoleMode ( handle, & mut out) != 0 {
325
+ return true ;
326
+ }
327
+ }
328
+ false
329
+ }
330
+ #[ unstable( feature = "is_atty" , issue = "80937" ) ]
331
+ unsafe fn msys_tty_on ( fd : c:: DWORD ) -> bool {
332
+ use std:: { mem, slice} ;
333
+
334
+ use c:: {
335
+ c_void, FileNameInfo , GetFileInformationByHandleEx , GetStdHandle , FILE_NAME_INFO , MAX_PATH ,
336
+ } ;
337
+
338
+ let size = mem:: size_of :: < FILE_NAME_INFO > ( ) ;
339
+ let mut name_info_bytes = vec ! [ 0u8 ; size + MAX_PATH * mem:: size_of:: <WCHAR >( ) ] ;
340
+ let res = GetFileInformationByHandleEx (
341
+ GetStdHandle ( fd) ,
342
+ FileNameInfo ,
343
+ & mut * name_info_bytes as * mut _ as * mut c_void ,
344
+ name_info_bytes. len ( ) as u32 ,
345
+ ) ;
346
+ if res == 0 {
347
+ return false ;
348
+ }
349
+ let name_info: & FILE_NAME_INFO = & * ( name_info_bytes. as_ptr ( ) as * const FILE_NAME_INFO ) ;
350
+ let s =
351
+ slice:: from_raw_parts ( name_info. FileName . as_ptr ( ) , name_info. FileNameLength as usize / 2 ) ;
352
+ let name = String :: from_utf16_lossy ( s) ;
353
+ // This checks whether 'pty' exists in the file name, which indicates that
354
+ // a pseudo-terminal is attached. To mitigate against false positives
355
+ // (e.g., an actual file name that contains 'pty'), we also require that
356
+ // either the strings 'msys-' or 'cygwin-' are in the file name as well.)
357
+ let is_msys = name. contains ( "msys-" ) || name. contains ( "cygwin-" ) ;
358
+ let is_pty = name. contains ( "-pty" ) ;
359
+ is_msys && is_pty
360
+ }
0 commit comments