2010-09-06 11 views
7

El archivo C siguiente da un resultado falso cuando NUL se canaliza a ella:NUL descriptor de archivo (isatty es falso)

int main() 
{ 
    printf("_isatty = %d\n", _isatty(0)); 
} 

el resultado es:

C:\Users\Edward\Dev\nulltest> test.exe < NUL 
_isatty = 64 

Estoy bastante seguro ¡NUL (también conocido como/dev/null) no es un dispositivo terminal! Entonces necesito detectar de otra manera si el descriptor de archivo corresponde o no a NUL. El número no tiene ningún significado específico; Lo veo cuando realmente tengo un terminal conectado.

¿Qué debo hacer? This question sugiere usar una función incompleta no documentada para obtener el nombre subyacente, presumiblemente comparándolo con NUL, pero eso se siente menos que ideal para mí. ¿Hay una mejor manera?

P.S. Esto ayudaría a resolver this GHC bug.

+0

Solo por curiosidad (y no estoy diciendo que lo que estás haciendo está mal): ¿por qué te importa donde la entrada de la venida ¿de? – paxdiablo

+0

Hay muchas aplicaciones que hacen cosas diferentes cuando detectan un terminal. Por ejemplo, si escribe 'python', entrará en modo interactivo, pero 'echo' imprimirá \ "bar \" "| python 'no mostrará ninguna de la pantalla de inicialización. –

+0

Tengo _hate_ esos programas :-) – paxdiablo

Respuesta

4

De msdn:

_isatty devuelve un valor distinto de cero si el descriptor está asociado con un dispositivo carácter. De lo contrario, _isatty devuelve 0.

NUL es como/dev/null en Unix, es un dispositivo de char.

Tenga en cuenta que en Linux, isatty es diferente:

Las pruebas de función isatty (fd) si es un descriptor de fichero abierto refiriéndose a un terminal.

Lo que puedes hacer es intentar comparar STDIN_FILENO (0) con $ {cwd}/NUL (usando estadísticas o estadísticas).

Actualización:

int ret = GetFileType(GetStdHandle(STD_INPUT_HANDLE)); 

Se FILE_TYPE_CHAR volverá a NUL o TTY.

Consulte GetFileType documentación para otros valores. Puede detectar archivos/dispositivo/tuberías.

Informe final de actualización:

Uso GetConsoleMode para la entrada y GetConsoleScreenBufferInfo para la salida.

CONSOLE_SCREEN_BUFFER_INFO sbi; 
DWORD mode; 
if (!GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode)) 
    fprintf(stderr, "not console\n"); 
else 
    fprintf(stderr, "console\n"); 
if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &sbi)) 
    fprintf(stderr, "not console\n"); 
else 
    fprintf(stderr, "console\n"); 
+0

¡Interesante! Eso implica que no deberíamos estar usando isatty para detectar si hay un terminal. ¿Hay una funcionalidad equivalente disponible en Windows? –

+0

_isatty está bloqueado, debería detectar si está usando un terminal, no si el fd es un dispositivo de caracteres. No estoy seguro de cuál es la mejor manera de hacerlo en Windows. Puede intentar verificar la implementación de cygwin/mingway isatty. También puede crear un contenedor lista negra $ (CWD)/NUL, ya que es probablemente el único dispositivo de caracteres que usará fácilmente en Windows. – iksaif

+0

Ok, encontré la solución real, actualicé mi respuesta – iksaif

-2

Puede usar fstat en el descriptor de archivo y comparar el miembro del dispositivo de la estructura resultante stat con el de /dev/null y ver si coinciden.

+1

No funciona. _stat devuelve invariablemente 2, mientras que _fstat devuelve invariablemente 0. –

0

Aquí hay una posible solución, pero no estoy seguro de que funcione todo el tiempo.Creo que va a trabajar para el caso específico de un descriptor de fichero nulo:

 
int real_isatty(int fd) { 
    DWORD st; 
    HANDLE h; 
    if (!_isatty(fd)) { 
     /* TTY must be a character device */ 
     return 0; 
    } 
    h = (HANDLE)_get_osfhandle(fd); 
    if (h == INVALID_HANDLE_VALUE) { 
     /* Broken handle can't be terminal */ 
     return 0; 
    } 
    if (!GetConsoleMode(h, &st)) { 
     /* GetConsoleMode appears to fail when it's not a TTY. */ 
     return 0; 
    } 
    return 1; 
} 
Cuestiones relacionadas