/* lib_spawn		spawn and pipe routines for unix and nt */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include "lprintf.h"

#ifdef WIN32
#include <windows.h>
#include <process.h>
#include <io.h>
#include <sys\stat.h>
#include <direct.h>
#else
#include <sys/types.h>
#include <sys/wait.h>
#endif

#ifdef WIN32
#define STDIN_FILENO  _fileno(stdin)
#define STDOUT_FILENO  _fileno(stdout)
#endif

#ifdef isunix
#define flushall() fflush(NULL)
#include <pwd.h>
#endif

#ifdef isunix
#include <unistd.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#endif

#include "lib_spawn.h"
#include "emsg.h"
void close_on_exec(int fd);

#ifndef false
#define false 0
#define true !false
#endif
#ifndef FALSE
#define FALSE 0
#define TRUE !FALSE
#endif

#define BFSZ 1000

int spawn_write(int h, char *bf, int len);

enum {PREAD,PWRITE};

int lib_sp_write(int f, char *bf){
	int count=strlen(bf);

	return spawn_write(f, bf, count);
}

int spawn_read(int h, char *bf, int len);

/* blocking read line from spawned process  */
int lib_sp_read(int f, char *bf, int maxsz){
	int  r,i;
	char *p = bf;

	maxsz--;
	for (r=0; r<maxsz; p++,r++){
		i = spawn_read(f, p, 1);
		if (i<0)
		{
			*bf=0;
			return -1;
		}
		if (i==0){r--;p--; break;}
		if (*p == '\n') break;
	}
	p++; *p = 0;
/*	if (p>bf) if (bf[r]=='\r') {
		bf[r] = 0;
		r--;
	}*/
	return ++r;
}


#ifdef isunix
int lib_spawn_wait(int x){
	return TRUE;
}
int lib_spawn_wait_finished(int h)
{
	int status;
	waitpid(h,&status,0);
	return TRUE;
}

int spawn_close(int h)
{
	int r;
	int ecode;
	close(h);
	r = waitpid(-1,&ecode,WNOHANG | WUNTRACED);
	return r;
}

/* spawn read with waitpid stuff really needs extra pid parameter */
int spawn_readx(int h, char *bf, int len, int spawn_pid){
	int navail;
	int r;
	int ecode;
	int n=0;
	if (spawn_pid<0) return -1;
again:
	n++;
	ioctl(h,FIONREAD,&navail);
	if (navail<=0) {
		r = waitpid(spawn_pid,&ecode,WNOHANG | WUNTRACED);
		if (r==spawn_pid) {
			spawn_pid = -1;
			dmsg("Spawned Process exited normally\n");
			ioctl(h,FIONREAD,&navail);
			if (navail>0) goto onemore; 
			return -1;
		} 
		if (r==0) {
			dmsg("No process available yet\n");
			sleep(1);
			if (n==600) return -1;
			goto again;
		}
		if (r<0) {
			imsg("An error occured %s\n",strerror(errno));
			return -1;
		}
	}
onemore:
	if (len>navail) len=navail;
	return read(h,bf,len);
}

int spawn_read_timed(int h, char *bf, int len, int secs)
{
        int i,nc;
        fd_set readfd,writefd,exceptfd;
        static struct timeval timeout;
	int navail;        
        timeout.tv_sec = secs; /*Wake up once a second*/
        timeout.tv_usec = 0;

        FD_ZERO(&readfd);
        FD_ZERO(&writefd);
        FD_ZERO(&exceptfd);

        FD_SET(h,&readfd);

        nc = select(h+1,&readfd,&writefd,&exceptfd,&timeout);
        if (nc<0) { filemsg("Spawn Select failed\n"); return -1;}
	if (nc==0) {  filemsg("Spawn Select failed2\n"); return -1;}
/*
	Chris removed next bit as doesn't make sense.
	  navail = 0;
	ioctl(h,FIONREAD,&navail);

	if (navail<len) {  filemsg("ioctl failed2\n"); return -1;}*/
	return spawn_read(h,bf,len);
}

int spawn_read(int h, char *bf, int len){
	int navail;
	int r;
	int ecode;
	int n=0;
/*
again:
	n++;
	ioctl(h,FIONREAD,&navail);
	if (navail<=0) {
		return navail;
	}
onemore:
	if (len>navail) len=navail;
*/
	return read(h,bf,len);
}

int spawn_write(int h, char *bf, int len){
	return write(h,bf,len);
}

int lib_spawn(char *cmd, char *env[], int *xin, int *xout, char *msg){
	int r;
	static int xread[2];
	char *s;
	int n;
	static int xwrite[2];
	static char *args[100];
	static char xcmd[BFSZ];
	if (pipe(xread)!=0) {strcpy(msg,strerror(errno)); return FALSE;}
	if (pipe(xwrite)!=0) {strcpy(msg,strerror(errno)); return FALSE;}
	
	ncpy(xcmd,cmd,BFSZ-1);
	s = strtok(cmd," \r\n");
	for (n=0;s!=NULL;) {
		args[n++] = s;
		s = strtok(NULL," \r\n");
	}
	args[n++] = NULL;
	args[n++] = NULL;
	*xin = xread[1];
	*xout = xwrite[0];
	close_on_exec(*xin);
	close_on_exec(*xout);
	close_on_exec(fileno(stdin));
	close_on_exec(fileno(stdout));
	close_on_exec(fileno(stderr));
	fflush(NULL);
	r = fork();
	if (r==0) { /* Child process */
		dup2(xread[0],STDIN_FILENO);
		close(xread[0]);
		dup2(xwrite[1],STDOUT_FILENO);
		close(xwrite[1]);
		if (execve(args[0],args,env)<0) {
			emsg("lib_spawn: Error on exec (%s) %s %s",args[0],cmd,strerror(errno));
			fflush(NULL);
			exit(0);
		}

		/* on success execl doesn't return */			;
		printf("Panic shouldn't get here");
	}
	close(xread[0]);
	close(xwrite[1]);
	return r;	

}
#endif

#ifdef WIN32
int spawn_write(int h, char *bf, int len){
	int rlen;
	dmsg("Writing data %d bytes\n",len);
	if (!WriteFile((HANDLE) h,bf,len,&rlen,NULL)) {
		emsg("Write failed %d",GetLastError());	
	}
	dmsg("Writing data done\n");
	return rlen;
}




#define BUFSIZE 4096 
 
static HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup, 
   hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup, 
   hInputFile, hSaveStdin, hSaveStdout; 
 
BOOL CreateChildProcess(char *cmd, char *env); 
VOID WriteToPipe(VOID); 
VOID ReadFromPipe(VOID); 
VOID ErrorExit(LPTSTR); 
VOID ErrMsg(LPTSTR, BOOL); 
 
int spawn_close(int h){
	CloseHandle((HANDLE) h);
	return TRUE;
}

int spawn_read_timed(int h, char *bf, int len, int secs)
{
	return spawn_read(h,bf,len);
}
#define INVALID_HANDLE NULL
int spawn_read(int h, char *bf, int len){
	int rlen=0;

	bf[0] = 0;
	if (!ReadFile((HANDLE) h,bf,len,&rlen,NULL)) {
		imsg("filter: Read failed %d\n",GetLastError());	
		return -1;
	}
	bf[rlen]=0;
	/* dmsg("Got %d %s",rlen,bf);*/ 
	return rlen;
}

int lib_spawn_zz(char *cmd, char *env[],int *hin, int *hout,char *msg ){
	char *s;
	char envblock[20000];
	int i;
	SECURITY_ATTRIBUTES saAttr; 
	BOOL fSuccess; 

	strcpy(msg,"");
	s = envblock;
	for (i=0;env[i]!=NULL;i++) {
		strcpy(s,env[i]);
		s += strlen(s) + 1;
	}
	*s++ = 0;
	*s++ = 0;
	
 
 
   saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
   saAttr.bInheritHandle = TRUE; 
   saAttr.lpSecurityDescriptor = NULL; 
 
 
   hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
 
 
   if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) 
      ErrorExit("Stdout pipe creation failed\n"); 
 
 
   if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr)) 
      ErrorExit("Redirecting STDOUT failed"); 
 

    fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
        GetCurrentProcess(), &hChildStdoutRdDup , 0,
        FALSE,
        DUPLICATE_SAME_ACCESS);
    if( !fSuccess )
        ErrorExit("DuplicateHandle failed");
    CloseHandle(hChildStdoutRd);

 
   hSaveStdin = GetStdHandle(STD_INPUT_HANDLE); 
 
   if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) 
      ErrorExit("Stdin pipe creation failed\n"); 
 
 
   if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd)) 
      ErrorExit("Redirecting Stdin failed"); 
 
 
   fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr, 
      GetCurrentProcess(), &hChildStdinWrDup, 0, 
      FALSE,                  /* not inherited */
      DUPLICATE_SAME_ACCESS); 
   if (! fSuccess) 
      ErrorExit("DuplicateHandle failed"); 
 
   CloseHandle(hChildStdinWr); 
 
 
   if (! CreateChildProcess(cmd,envblock)) 
      ErrorExit("Create process failed"); 
 
   if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin)) 
      ErrorExit("Re-redirecting Stdin failed\n"); 
 
   if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout)) 
      ErrorExit("Re-redirecting Stdout failed\n"); 

   *hout = (int) hChildStdoutRdDup;
   *hin =  (int) hChildStdinWrDup;
   return 0; 
} 
 
BOOL CreateChildProcess(char *cmd, char *envblock) { 
   PROCESS_INFORMATION piProcInfo; 
   STARTUPINFO siStartInfo; 
   ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
   siStartInfo.cb = sizeof(STARTUPINFO); 
   return CreateProcess(NULL, 
      cmd,       /* command line */
      NULL,          /* process security attributes */
      NULL,          /* primary thread security attributes */
      TRUE,          /* handles are inherited */
      0,             /* creation flags */
      envblock,      /* use parent's environment */
      NULL,          /* use parent's current directory */
      &siStartInfo,  /* STARTUPINFO pointer */
      &piProcInfo);  /* receives PROCESS_INFORMATION */
}


VOID ReadFromPipe(VOID) { 
   DWORD dwRead, dwWritten; 
   CHAR chBuf[BUFSIZE]; 
   HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 

 
   for (;;) 
   { 
      if( !ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead, 
         NULL) || dwRead == 0) break; 
      if (! WriteFile(hSaveStdout, chBuf, dwRead, &dwWritten, NULL)) 
         break; 
   } 
} 
 
VOID ErrorExit (LPTSTR lpszMessage) { 
   emsg("ErrorExit %s\n", lpszMessage); 
   ExitProcess(0); 
} 
 



int lib_spawn(char *cmd, char *env[],int *hin, int *hout,char *msg ){
	static DWORD len;
	HANDLE read1,write1,read2,write2,read3,write3;
	int er;
	char *s;
	char envblock[20000];
	int i;
	STARTUPINFO st;
	PROCESS_INFORMATION p;
	SECURITY_ATTRIBUTES sec;

	strcpy(msg,"");
	s = envblock;
	for (i=0;env[i]!=NULL;i++) {
		strcpy(s,env[i]);
		s += strlen(s) + 1;
	}
	*s++ = 0;
	*s++ = 0;
	sec.nLength = sizeof(sec);
	sec.lpSecurityDescriptor = NULL;
	sec.bInheritHandle = TRUE;
	GetStartupInfo(&st);
	CreatePipe(&read1,&write1,&sec,10000);
	CreatePipe(&read2,&write2,&sec,10000);
	CreatePipe(&read3,&write3,&sec,10000);
	st.hStdInput = read1;
	st.hStdOutput = write2;
	st.hStdError = write3;
	st.dwFlags = STARTF_USESTDHANDLES;
	if (CreateProcess(NULL,cmd,NULL,NULL
		,TRUE,DETACHED_PROCESS
		,envblock,NULL  
		,&st,&p)) {
	} else {
		er = GetLastError();
	        emsg("CreateProcess Failed err %d (%.200s)\n",er,cmd);
		if (er==ERROR_PATH_NOT_FOUND) strcpy(msg,"Path Not Found");
		if (er==ERROR_FILE_NOT_FOUND) strcpy(msg,"File Not Found");
		if (er==ERROR_ACCESS_DENIED) strcpy(msg,"Access Denied");
		CloseHandle(write1);
		CloseHandle(write2);
		CloseHandle(write3);
		CloseHandle(read3);
		CloseHandle(read2);
		CloseHandle(read1);
		return -1;
	}
	CloseHandle(p.hThread);
	CloseHandle(write2);
	CloseHandle(write3);
	CloseHandle(read3);
	CloseHandle(read1);
	*hin = (int) write1;
	*hout = (int) read2;
	return (int) p.hProcess;
}
int lib_spawn_wait_finished(int x)
{
	int n=0;
	int i;

	for (i=0; i<9000; i++) {
		if (!spawn_isalive(x)) break;
		Sleep(10);
	}
	return TRUE;
}
		
int lib_spawn_wait(int x)
{
	int ecode;
	int n=0;
	dmsg("Closing handle %d\n",x);
again:
	if (GetExitCodeProcess((HANDLE) x,&ecode)) {
		if (ecode==STILL_ACTIVE) {
			dmsg("Still active %d\n",++n);
			Sleep(100);
			if (n>10) return TRUE;
			goto again;
		}
		dmsg("Not Still active\n");
		CloseHandle((HANDLE) x);
		return FALSE;
	} 
	dmsg("exitcodeprocess failed\n");
	emsg("GetExitCode(%d) Failed, error=%d\n",x,GetLastError());
	return TRUE;
}

#endif

#ifdef WIN32
char *winmsg(int i)
{
	static char bf[1000];
	LPVOID lpMsgBuf;
	char *s;
	FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
		, NULL
		,i
		, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)
		, (LPTSTR) &lpMsgBuf, 0, NULL);

	strncpy(bf,lpMsgBuf,100); bf[100] = 0;
	LocalFree(lpMsgBuf);
	s = strchr(bf,'\n'); 	if (s!=NULL) *s = 0;
	s = strchr(bf,'\r'); 	if (s!=NULL) *s = 0;
	return bf;
}
#endif

#ifdef WIN32
int iswinnt(void)
{
	OSVERSIONINFO Ver;

	Ver.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
	if(!GetVersionEx(&Ver))
		return TRUE;
	if(Ver.dwPlatformId==VER_PLATFORM_WIN32_NT)
		return TRUE;
	return FALSE;
}
#endif

int spawn_kill(int x)
{
#ifdef isunix
	imsg("spawn_kill(pid=%d) killing process\n",x);
	if(spawn_isalive(x))
	{
		int ecode, i, y;

 		imsg("killing slave process, handle %d\n", x);
		if(kill(x, SIGKILL)!=0) 
			imsg("*** Warning *** kill(%d) Failed, %s\n", x, strerror(errno));

		for(i=0;i<25;i++)
		{
			y=waitpid(x,&ecode,WNOHANG | WUNTRACED);
			if (y==x) break;
			if (y==0) imsg("waitpid(%d) failed, this is normal (%s)\n",x,strerror(errno));
			sleep(2);
		}
		if(i==25)
			wmsg("** Process %d resisted killing\n", x);
	} else imsg("it was already dead\n");
	return TRUE;
#endif
#ifdef WIN32
	int i;
	HANDLE ph;
	DWORD permission;


	imsg("spawn_kill(pid=%d) killing process\n",x);

	if(iswinnt())	permission=PROCESS_ALL_ACCESS;
	else		permission=PROCESS_QUERY_INFORMATION;
/*	if(iswinnt())	permission=SYNCHRONIZE;
	else		permission=PROCESS_QUERY_INFORMATION;
*/	
	ph=OpenProcess(permission, FALSE, x);
	if(ph==NULL) {
	    imsg("process already finished (pid=%d)\n",x);
	    dmsg("OpenProcess(%s)\n",winmsg(GetLastError()));
	    return FALSE;
	}

	i=TerminateProcess(ph, 0);
	if(i==FALSE) { emsg("TerminateProcess(%s)\n",winmsg(GetLastError())); return FALSE; }
	CloseHandle(ph);
	return TRUE;
#endif
}
int spawn_kill_h(int x)
{
#ifdef isunix
	return spawn_kill(x);
#endif
#ifdef WIN32
	int i;
	HANDLE ph = (HANDLE) x;
	DWORD permission;


	imsg("spawn_kill(h=%d) killing process\n",x);

	if(iswinnt())	permission=PROCESS_ALL_ACCESS;
	else		permission=PROCESS_QUERY_INFORMATION;
	i=TerminateProcess(ph, 0);
	if(i==FALSE) { emsg("TerminateProcess(%s)\n",winmsg(GetLastError())); return FALSE; }
	CloseHandle(ph);
	return TRUE;
#endif
}
int spawn_release(int pid)
{
#ifdef isunix
	int ecode;
	int r;
	int i;
	int y;

	for(i=0;i<10;i++) {
		y=waitpid(pid,&ecode,WNOHANG | WUNTRACED);
		if (y==pid) break;
		if (y==0) imsg("waitpid(%d) failed, this is normal (%s)\n",pid,strerror(errno));
		sleep(1);
	}
#endif
	return TRUE;
}
int spawn_isalive(int x)
{
#ifdef isunix
	int ecode;
	int r;

	errno=0;
	if (x<=0) return FALSE;
	r=waitpid(x,&ecode,WNOHANG | WUNTRACED);
	if(r==x) return FALSE;
	if(errno==ECHILD) return FALSE;
	return TRUE;
#endif
#ifdef WIN32
	DWORD code;
	HANDLE ph;
	DWORD permission;

	if (x== 0) return FALSE;
	if (x== -1) return FALSE;

	if(iswinnt())	permission=PROCESS_ALL_ACCESS;
	else		permission=PROCESS_QUERY_INFORMATION;
	ph=OpenProcess(permission, FALSE, x);
	if(ph==NULL) {
	    imsg("process already finished (pid=%d)\n",x);
	    imsg("OpenProcess(%s)\n",winmsg(GetLastError()));
	    return FALSE;
	}
	if (!GetExitCodeProcess((HANDLE)ph, &code)) {
	    imsg("GetExitCodeProcess(%d,%s)\n",x,winmsg(GetLastError()));
	}
	CloseHandle(ph);
	if (code==STILL_ACTIVE) return TRUE;
	imsg("Process not still active %d\n",x);
	return FALSE;
#endif
}

int lib_spawn_cmd(char *cmd);

#ifdef WIN32
char *mygetenv(char *s)
{
	s = getenv(s);
	if (s==NULL) return "";
	return s;
}
#endif

int lib_spawn_cmd(char *cmd) {
#ifdef WIN32
	static DWORD len;
	int er;
	char *s;
	int i;
	char *env[1000];
	char envblock[20000];
	STARTUPINFO st;
	PROCESS_INFORMATION p;
	SECURITY_ATTRIBUTES sec;
	int nenv =0;
	char bf[BFSZ];

#define addenv(xx) lprintf(bf,BFSZ-1,"%s=%s",xx,mygetenv(xx)); env[nenv++] = strdup(bf); 
	addenv("Path");
	addenv("COMPUTERNAME");	
	addenv("ComSpec");	
	addenv("Cpu");	
	addenv("HOMEDRIVE");	
	addenv("HOMEPATH");	
	addenv("NUMBER_OF_PROCESSORS");	
	addenv("OS");	
	addenv("Os2LibPath");	
	addenv("PATHEXT");	
	addenv("PROCESSOR_ARCHITECTURE");	
	addenv("PROCESSOR_IDENTIFIER");	
	addenv("PROCESSOR_LEVEL");	
	addenv("PROCESSOR_REVISION");	
	addenv("SystemDrive");	
	addenv("SystemRoot");	
	addenv("TEMP");	
	addenv("TMP");	
	addenv("USERDOMAIN");	
	addenv("USERNAME");	
	addenv("USERPROFILE");	
	addenv("WINDIR");	
	env[nenv] = NULL;
	
	s = envblock;
	for (i=0;env[i]!=NULL;i++) {
		strcpy(s,env[i]);
		s += strlen(s) + 1;
	}
	*s++ = 0;
	*s++ = 0;
	sec.nLength = sizeof(sec);
	sec.lpSecurityDescriptor = NULL;
	sec.bInheritHandle = FALSE;
	GetStartupInfo(&st);
	st.dwFlags = 0;
	imsg("CreateProcess(%s)\n",cmd);
	if (CreateProcess(NULL,cmd,NULL,NULL
		,FALSE,DETACHED_PROCESS
		,envblock,NULL  
		,&st,&p)) {
	} else {
	    er = GetLastError();
	    emsg("CreateProcess Failed err %d (%.200s)\n",er,cmd);
	    if (er==ERROR_PATH_NOT_FOUND) emsg("Couldn't spawn expire process - Path Not Found\n");
	    if (er==ERROR_FILE_NOT_FOUND) emsg("Couldn't spawn expire process - File Not Found\n");
	    if (er==ERROR_ACCESS_DENIED) emsg("Couldn't spawn expire process - Access Denied\n");
	    return -1; /* invalid process id because spawn unsuccessful */
	}
	imsg("CreateProcess Finished\n");
	CloseHandle(p.hThread);
	/* Added next line, as it should always be closed yes ? */
	CloseHandle(p.hProcess);
	return (int)p.dwProcessId; /* process id */
#endif

#ifdef isunix
	int r;
	static int xread[2];
	static int xwrite[2];
	char xcmd[BFSZ];
	char *s;
	static char *env[500];
	static char *args[100];
	int nargs = 0;
	int i=0;

#ifdef HAS_ENVIRON
	extern char **environ;
	for (i=0; environ[i]!=NULL; i++) {
		env[i] = environ[i];
		imsg("Environment (%.100s)\n",environ[i]);
		if (i>200) break;
	}
	env[i++] = NULL;
	env[i++] = NULL;
#else
	env[0] = NULL;
	env[1] = NULL;
#endif
	close_on_exec(fileno(stdin));
	close_on_exec(fileno(stdout));
	close_on_exec(fileno(stderr));
	fflush(NULL);
#ifdef USE_VFORK
	log_spawn("About to vfork now %s\n",cmd);
	r = vfork();
#else
	log_spawn("About to fork now %s\n",cmd);
	r = fork();
#endif
	log_spawn("Fork completed %d\n",r);
	if (r== -1) {
		emsg("fork failed %s\n",strerror(errno));
	}
	if (r==0) { /* Child process */
	    log_spawn("Process created ok, now running (%s)\n",cmd);
	    ncpy(xcmd,cmd,200);
     	    s = strtok(xcmd," \t");
    	    for (;s!=NULL;) {
		args[nargs++] = strdup(s);
		s = strtok(NULL," \t");
	    }
	    args[nargs] = NULL;
    
	    log_spawn("Exec this command (%s)\n",cmd);
	    if (execve(args[0],args,env)<0) {
#ifdef USE_VFORK
		log_spawn("lib_spawn: Error on exec %s %s",cmd,strerror(errno));
		_exit(0);
#endif
		    log_spawn("lib_spawn: Error on exec %s %s",cmd,strerror(errno));
			emsg("lib_spawn: Error on exec %s %s",cmd,strerror(errno));
			fflush(NULL);
			exit(0);
	    }
	    
		/* on success execl doesn't return */			;
	    printf("Panic shouldn't get here");
	    exit(0);
	}
	return r; /* process id */	
#endif
}


int lib_sp_bread(int f, char *bf, unsigned int maxsz){
	unsigned int  r,i;
	char *p, temp[10];
	unsigned long navail=0;

#ifdef isunix
	int err;
	err = ioctl(f,FIONREAD,&navail);
#endif
	bf[0] = 0;
#ifdef WIN32
	 if (!PeekNamedPipe((HANDLE)f,temp,9,NULL,&navail,NULL)){
		 emsg("lib_sp_bread: Peeknamedpipe failed err %d",GetLastError());	
		 return -1;
	 }
#endif
	/* dmsg("Bytes available = %u\n",navail); */
	if (!navail) return false;
	if (navail>maxsz-1) navail = maxsz-1;
	for(r=0,p=bf; *p; p++,r++) ;

	if ((r += navail)>maxsz){
		emsg("Error too many chars available %u, max %d, throwing some away.\n", navail, maxsz);
		p = bf;
	}

#ifdef WIN32
	i = spawn_read(f, p, navail);
#endif
#ifdef isunix
	i = spawn_read(f, p, navail);
#endif
	if (i==-1){
		emsg("lib_sp_bread: error on read");
		return -1;
	}
	if (i==0){
		emsg("Only read %d of %d available\n", i, (int)navail);
		return 0;
	}
	p[i] = 0;
	/* if (i!= (int)navail)
		dmsg("Error only read %d of %d available\n", i, (int)navail);*/
	if (p[i-1]=='\n') {
		dmsg("lib_sp_bread() returning true.\n");
		return 1;
	}
	/*dmsg("lib_sp_bread() returning false.\n"); */
	return 0;

/*
	0 = no data yet
	1 = got line
	-1 = channel closed, fatal error
	
	*/
}
