/*
** The cvsgui protocol used by WinCvs
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
** 
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
** 
** You should have received a copy of the GNU Lesser General Public
** License along with this library; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/*!
	\file cvsgui.c
	\brief Glue code implementation for communicating with CVS over pipes

	Glue code to intercept some low level I/O calls and tunnel them inside the communication pipes

	\author Alexandre Parenteau <aubonbeurre@hotmail.com> --- November 1999
	\note To be used by CVS client
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#ifndef WIN32
#include <unistd.h>
#endif

#include <limits.h>

#if defined(WIN32) && !defined(PATH_MAX)
#	ifdef _MAX_PATH
#		define PATH_MAX _MAX_PATH
#	else 
#		define PATH_MAX 512
#	endif
#endif

#include "cvsgui.h"
#include "cvsgui_process.h"
#include "cvsgui_protocol.h"

pipe_t _cvsgui_readfd = 0;	/*!< Read pipe file descriptor */
pipe_t _cvsgui_writefd = 0;	/*!< Write pipe file descriptor */

#if !defined(WIN32) && !defined(__GNUC__)
static off_t outseek;					/*!< Output file position */
static off_t errseek;					/*!< Error file position */
static char outname[PATH_MAX] = {0};	/*!< Output file name  */
static char errname[PATH_MAX] = {0};	/*!< Error file name */
static FILE* outlog;					/*!< Output file */
static FILE* errlog;					/*!< Error file */
#endif

/*!
	Get the environmental variable
	\param env Name of the environmental variable to get
	\return The value of the environmental variable
*/
char* cvsguiglue_getenv(const char* env)
{
	char* res = 0L;

	if( _cvsgui_readfd == 0 )
		return getenv(env);

	cvsguiglue_flushconsole(0);

	if( env && gp_getenv_write(_cvsgui_writefd, env) )
	{
		res = gp_getenv_read(_cvsgui_readfd);;
	}

	return res;
}

/*!
	Report the exit code and exit
	\param code Exit code
*/
void cvsguiglue_close(int code)
{
	cvsguiglue_flushconsole(1);
	
	if( _cvsgui_writefd != 0 )
		gp_quit_write(_cvsgui_writefd, code);
}

/*!
	Reopen the <b>stdout</b> and <b>stderr</b> consoles
*/
static void reopen_consoles(void)
{
#if !defined(WIN32) && !defined(__GNUC__)
    strcpy(outname, tempnam(0L, 0L));
    strcpy(errname, tempnam(0L, 0L));
    strcat(outname, ".out");
    strcat(errname, ".err");

	outlog = freopen(outname, "w+", stdout);
	if( outlog == 0L )
	{
		fprintf(stderr, "Unable to reopen stdout !\n");
		exit(1);
	}

	errlog = freopen(errname, "w+", stderr);
	if( errlog == 0L )
	{
		fprintf(stderr, "Unable to reopen stderr !\n");
		exit(1);
	}
	
	outseek = 0;
	errseek = 0;
#endif
}

#if !defined(WIN32) && !defined(__GNUC__)
/*!
	Close consoles
*/
static void close_consoles(void)
{
	if( outlog != 0L )
		fclose(outlog);

	if( errlog != 0L )
		fclose(errlog);

	if( outname[0] )
		unlink(outname);
	
	if( errname[0] )
		unlink(errname);

	outlog = 0L;
	errlog = 0L;
	outname[0] = '\0';
	errname[0] = '\0';
}

#if !defined(CVS_FSEEK)
#	define CVS_FSEEK fseek
#endif

#if !defined(CVS_FTELL)
#	define CVS_FTELL ftell
#endif

/*!
	Flush console
	\param log Console file
	\param oldpos Position in the console file
*/
static void myflush(FILE* log, off_t* oldpos)
{
	off_t newpos, pos;

#	define BUF_SIZE 8000
	char buf[BUF_SIZE];

	size_t len;

	pos = CVS_FSEEK(log, *oldpos, SEEK_SET);
	if( pos != 0 )
		goto fail;

	while( !feof(log) && !ferror(log) )
	{
		len = fread(buf, sizeof(char), BUF_SIZE, log);
		if( len > 0 )
		{
			if( log == outlog )
				gp_console_write(_cvsgui_writefd, buf, len, 0, 0);

			if( log == errlog )
				gp_console_write(_cvsgui_writefd, buf, len, 1, 0);
		}
	}

	if( ferror(log) )
		goto fail;

	newpos = CVS_FTELL(log);
	if( newpos < 0 )
		goto fail;

	*oldpos = newpos;

	return;

fail:
	fprintf(stderr, "Unable to redirect stdout/stderr !\n");
}
#endif

/*!
	Flush consoles
	\param closeit Set to non-zero to close consoles
*/
void cvsguiglue_flushconsole(int closeit)
{
	fflush(stdout);
	fflush(stderr);
	
#if !defined(WIN32) && !defined(__GNUC__)
	if( outlog != 0L )
		myflush(outlog, &outseek);
	
	if( errlog != 0L )
		myflush(errlog, &errseek);
	
	if( closeit )
		close_consoles();
#endif
}

/*!
	Main function
	\param argc Arguments count
	\param argv Arguments
	\return The exit code
	\note Detects whether the cvsgui protocol should be activated
*/
int cvsguiglue_init(const char *arg1, const char *arg2)
{
 	/* On Win64, long is 32bits, but pipe_t is 64bits */
#ifndef _WIN32
	unsigned  rfd,wfd;
	sscanf(arg1,"%u",&rfd);
	sscanf(arg2,"%u",&wfd);
#else
	unsigned __int64 rfd,wfd;
	sscanf(arg1,"%I64u",&rfd);
	sscanf(arg2,"%I64u",&wfd);
#endif
	_cvsgui_readfd = (pipe_t)rfd;
	_cvsgui_writefd = (pipe_t)wfd;

	cvs_process_init();
	reopen_consoles();
	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1