2011-07-27 8 views
13

Básicamente quiero probar si stdin tiene entrada (como si hace eco y lo canaliza). He encontrado soluciones que funcionan, pero son feas, y me gusta que mis soluciones estén limpias.Pruebe si stdin tiene entrada para C++ (Windows y/o Linux)

En Linux utilizo este:

bool StdinOpen() { 
    FILE* handle = popen("test -p /dev/stdin", "r"); 
    return pclose(handle) == 0; 
} 

Sé que debo añadir más control de errores, pero es el punto.

En las ventanas que utilizan este:

bool StdinOpen() { 
    static HANDLE handle = GetStdHandle(STD_INPUT_HANDLE); 
    DWORD bytes_left; 
    PeekNamedPipe(handle, NULL, 0, NULL, &bytes_left, NULL); 
    return bytes_left; 
} 

que está muy bien para Linux, pero me gustaría saber cuáles son las API equivalentes que puedo llamar sin necesidad de utilizar un tubo (como por test -f $file que haces fopen($file, "r") != NULL). Tengo una idea de que podría open("/dev/stdin", "r") y hacer lo mismo, pero quiero saber la mejor manera de hacerlo.

Resumen: Quiero saber las API podría utilizar para sustituir a test -p /dev/stdin para Linux, y, si se sabe una mejor solución para las ventanas.

+0

Su solución 'PeekNamedPipe' falla si la entrada estándar es un identificador de archivo (en lugar de una pipa). Además, su variable 'handle' no debe ser estática. Si el mango se redirecciona mientras se ejecuta tu aplicación, te sorprenderás más tarde. –

+0

@Billy: No creo que se pueda redirigir aleatoriamente un identificador. Claro, puedes cambiar lo que consideras que es stdin, pero el viejo mango aún está allí. Pero estoy de acuerdo con la primera parte. – Mehrdad

+0

Lionel B proporciona algún código para Linux en http://bytes.com/topic/c/answers/841283-how-make-non-blocking-call-cin; la discusión también vale la pena leerla. –

Respuesta

13

Aquí hay una solución para POSIX (Linux): No estoy seguro de cuál es el equivalente de poll() en Windows. En Unix, el descriptor de archivo con el número 0 es la entrada estándar.

#include <stdio.h> 
#include <sys/poll.h> 

int main(void) 
{ 
     struct pollfd fds; 
     int ret; 
     fds.fd = 0; /* this is STDIN */ 
     fds.events = POLLIN; 
     ret = poll(&fds, 1, 0); 
     if(ret == 1) 
       printf("Yep\n"); 
     else if(ret == 0) 
       printf("No\n"); 
     else 
       printf("Error\n"); 
     return 0; 
} 

Pruebas:

$ ./stdin 
No 
$ echo "foo" | ./stdin 
Yep 
+0

Esto es exactamente lo que quería. Ahora, te estaría eternamente agradecido si pudieras decirme cómo medir el tamaño del búfer de entrada, pero no quiero sonar como un cerdo de preguntas. – norcalli

+0

Puede usar read() para obtener la entrada. Primero configure el descriptor de archivo 0 como no bloqueante usando fcntl(), luego read() devolverá el número de bytes leídos o 0 cuando no haya más datos entrantes. – Antti

+2

+1. Otra alternativa comúnmente utilizada es 'select()' - uso conceptualmente similar. Es crucial tener en cuenta que estos preguntan al sistema operativo si hay nuevos datos disponibles en el descriptor: si está operando en ese nivel, debe usar 'read()' también en el descriptor, no puede usar library- nivel stdin streams o 'std :: cin' (a menos que proporcione una nueva implementación de búfer). –

1

Sería esto no funciona?

std::cin.rdbuf()->in_avail(); 
Cuestiones relacionadas