/*
* %CopyrightBegin%
*
* Copyright Ericsson AB 1998-2009. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* %CopyrightEnd%
*/
#include "elog_global.h"
#include "elog_pipe_stdin.h"
/*
* Data for the handling of a pipe stdin,
* data is read in a separate thread, so locking and
* event signaling needs to be done.
*/
static CRITICAL_SECTION io_crit;
static char *stdin_buff = NULL;
static int stdin_siz = 0;
static int stdin_len = 0;
static int stdin_eof = 0;
/* end syncronized objects */
static int stdin_is_console = 0;
static HANDLE stdin_event;
DWORD WINAPI stdin_thread(LPVOID ptr){
HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
char buff[1];
DWORD red;
for(;;){
if(!ReadFile(in, buff, (DWORD) 1, &red, NULL)){
if(GetLastError() == ERROR_BROKEN_PIPE){
EnterCriticalSection(&io_crit);
stdin_eof = 1;
SetEvent(stdin_event);
LeaveCriticalSection(&io_crit);
return 0;
}
return 1;
}else if(red == 0){
EnterCriticalSection(&io_crit);
stdin_eof = 1;
SetEvent(stdin_event);
LeaveCriticalSection(&io_crit);
return 0;
}
#ifdef HARDDEBUG
fprintf(stderr,"stdin_thread go data (%d)\n",(int)*buff);
#endif
EnterCriticalSection(&io_crit);
if(stdin_len + 1 >= stdin_siz){
if(!stdin_siz)
stdin_buff = malloc(stdin_siz = 100);
else
stdin_buff = realloc(stdin_buff, stdin_siz +=100);
}
stdin_buff[stdin_len++] = *buff;
SetEvent(stdin_event);
LeaveCriticalSection(&io_crit);
}
return 0;
}
BOOL peek_pipe_stdin_eof(void){
BOOL ret;
EnterCriticalSection(&io_crit);
if((ret = !!stdin_eof))
ResetEvent(stdin_event); /* Now we "unsignal" */
LeaveCriticalSection(&io_crit);
return ret;
}
int read_pipe_stdin(char *buff, int max){
int ret;
EnterCriticalSection(&io_crit);
if(stdin_len == 0){
if(!stdin_eof){
LeaveCriticalSection(&io_crit);
WaitForSingleObject(stdin_event,INFINITE);
EnterCriticalSection(&io_crit);
if(!stdin_len){
if(stdin_eof){
/* Stay signaled */
LeaveCriticalSection(&io_crit);
return 0;
} else {
ResetEvent(stdin_event);
LeaveCriticalSection(&io_crit);
return -1;
}
}
} else {
/* Stay signaled */
LeaveCriticalSection(&io_crit);
return 0;
}
}
#ifdef HARDDEBUG
fprintf(stderr,"read_pipe_stdin got data.\n"
"max = %d, stdin_len = %d, *stdin_buff = %d\n",
max,stdin_len,*stdin_buff);
#endif
/* stdin_len should be something now */
if(stdin_len > max){
memcpy(buff,stdin_buff,max);
memmove(stdin_buff,stdin_buff + max,stdin_len - max);
stdin_len -= max;
ret = max;
} else {
memcpy(buff,stdin_buff,stdin_len);
ret = stdin_len;
stdin_len = 0;
}
if(!stdin_eof) /* Stay signaled if EOF */
ResetEvent(stdin_event);
LeaveCriticalSection(&io_crit);
return ret;
}
BOOL setup_pipe_stdin(void){
HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
DWORD dummy;
if(GetConsoleMode(in, &dummy)){
stdin_is_console = 1;
stdin_event = in;
return TRUE;
}
stdin_event = CreateEvent(NULL, TRUE, FALSE, NULL);
InitializeCriticalSection(&io_crit);
return (_beginthreadex(NULL,0,&stdin_thread,NULL,0,&dummy));
}
BOOL console_stdin(void){
return stdin_is_console;
}
HANDLE get_stdin_event(void){
return stdin_event;
}