2010-09-06 8 views
7

Il seguente file C dà un risultato fasullo quando NUL viene convogliato ad esso:Rileva NUL descrittore di file (isatty è fasullo)

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

il risultato è:

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

Sono abbastanza sicuro NUL (ovvero/dev/null) non è un dispositivo terminale! Quindi ho bisogno di rilevare in un altro modo se il descrittore di file corrisponde o meno a NUL. Il numero non ha alcun significato specifico; Lo vedo quando in realtà ho un terminale collegato.

Cosa devo fare? This question suggerisce di utilizzare una funzione non documentata per ottenere il nome sottostante, presumibilmente confrontandolo con NUL, ma non mi sembra ideale. C'è un modo migliore?

P.S. Questo aiuterebbe a risolvere this GHC bug.

+0

solo per interesse (e non sto dicendo che quello che stai facendo è sbagliato): Perché ti interessa dove l'ingresso della venuta a partire dal? – paxdiablo

+0

Ci sono molte applicazioni che fanno cose diverse quando rilevano un terminale. Ad esempio, se digiti "python", passerà in modalità interattiva, ma "echo" print \ "bar \" "| python 'non mostrerà alcuna schermata di inizializzazione. –

+0

I _hate_ quei programmi :-) – paxdiablo

risposta

4

Da msdn:

_isatty restituisce un valore diverso da zero se il descrittore è associato ad un dispositivo carattere. Altrimenti, _isatty restituisce 0.

NUL è come/dev/null su Unix, è un dispositivo char.

noti che su Linux, isatty è differente:

La prova delle funzioni isatty() se fd è un descrittore di file aperto riferendosi ad un terminale.

Quello che puoi fare è provare a confrontare STDIN_FILENO (0) con $ {cwd}/NUL (utilizzando stat o stat).

Aggiornamento:

int ret = GetFileType(GetStdHandle(STD_INPUT_HANDLE)); 

Si tornerà FILE_TYPE_CHAR per NUL o TTY.

Vedere la documentazione GetFileType per altri valori. È possibile rilevare i file/dispositivo char/pipe.

aggiornamento finale:

Usa GetConsoleMode per l'ingresso e GetConsoleScreenBufferInfo per l'uscita.

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

Interessante! Ciò implica che in realtà non dovremmo usare isatty per rilevare se esiste un terminale. Esiste una funzionalità equivalente disponibile su Windows? –

+0

_isatty è buggato, dovrebbe rilevare se stai usando un terminale, non se il fd è un dispositivo di carattere. Non sono sicuro di quale sia il modo migliore per farlo su Windows. Puoi provare a verificare l'implementazione di cygwin/mingway. Puoi anche creare un wrapper nella lista nera $ (CWD)/NUL, in quanto probabilmente è l'unico dispositivo a caratteri che potrai usare facilmente su Windows. – iksaif

+0

Ok, ho trovato la soluzione reale, ho aggiornato la mia risposta – iksaif

-2

È possibile utilizzare fstat sul descrittore di file e confrontare il membro del dispositivo della struttura risultante stat con quello per /dev/null e verificare se corrispondono.

+1

Non funziona. _stat restituisce invariabilmente 2, mentre _fstat restituisce invariabilmente 0. –

0

Ecco una possibile soluzione, ma non sono convinto che funzioni tutto il tempo.Credo che funzionerà per il caso specifico di un file descrittore NUL:

 
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; 
} 
Problemi correlati