/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_rsc.hxx"

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#if defined (WNT) && defined (tcpp)
#define _spawnvp spawnvp
#define _P_WAIT P_WAIT
#endif

#ifdef UNX
#include <unistd.h>
#include <sys/wait.h>
#else // UNX

#include <io.h>
#include <process.h>
#if defined ( OS2 ) && !defined ( GCC )
#include <direct.h>
#endif
#if !defined ( CSET ) && !defined ( OS2 )
#include <dos.h>
#endif

#endif // UNX
#include <rsctools.hxx>
#include <rscerror.h>
#include <sal/main.h>
#include <tools/fsys.hxx>

/*************** C O D E ************************************************/
/****************************************************************/
/*																*/
/*	Function	:	fuer Ansi kompatibilitaet					*/
/*																*/
/****************************************************************/
#ifdef UNX
#define P_WAIT 0
	int spawnvp( int, const char * cmdname, char *const*  argv ){
		int rc(0);

		switch( fork() ){
			case -1:
				return( -1 );
			case 0:
				if( execvp( cmdname, argv ) == -1 )
					// an error occurs
					return( -1 );
				break;
			default:
				if( -1 == wait( &rc ) )
					return( -1 );
		}
		return( WEXITSTATUS( rc ) );
	}
#endif

/*************************************************************************
|*	  CallPrePro()
|*
|*	  Beschreibung
*************************************************************************/
static sal_Bool CallPrePro( const ByteString& rPrePro,
						const ByteString& rInput,
						const ByteString& rOutput,
						RscPtrPtr * pCmdLine,
						sal_Bool bResponse )
{
	RscPtrPtr		aNewCmdL;	// Kommandozeile
	RscPtrPtr		aRespCmdL;	 // Kommandozeile
	RscPtrPtr * 	pCmdL = &aNewCmdL;
	int			    i, nExit;
	FILE*			fRspFile = NULL;
	ByteString		aRspFileName;

	if( bResponse )
	{
		aRspFileName = ::GetTmpFileName();
		fRspFile = fopen( aRspFileName.GetBuffer(), "w" );
	}

	if( !fRspFile )
		aNewCmdL.Append( rsc_strdup( rPrePro.GetBuffer() ) );

    bool bVerbose = false;
	for( i = 1; i < int(pCmdLine->GetCount() -1); i++ )
    {
        if ( 0 == rsc_stricmp( (char *)pCmdLine->GetEntry( i ), "-verbose" ) )
        {
            bVerbose = true;
            continue;
        }
		if  (   !rsc_strnicmp( (char *)pCmdLine->GetEntry( i ), "-u", 2 )
		    ||  !rsc_strnicmp( (char *)pCmdLine->GetEntry( i ), "-i", 2 )
		    ||  !rsc_strnicmp( (char *)pCmdLine->GetEntry( i ), "-d", 2 )
            )
		{
			aNewCmdL.Append( rsc_strdup( (char *)pCmdLine->GetEntry( i ) ) );
		}
	}

	aNewCmdL.Append( rsc_strdup( rInput.GetBuffer() ) );
	aNewCmdL.Append( rsc_strdup( rOutput.GetBuffer() ) );
	aNewCmdL.Append( (void *)0 );

    if ( bVerbose )
    {
	    printf( "Preprocessor commandline: " );
	    for( i = 0; i < (int)(pCmdL->GetCount() -1); i++ )
	    {
		    printf( " " );
		    printf( "%s", (const char *)pCmdL->GetEntry( i ) );
	    }
	    printf( "\n" );
    }

	if( fRspFile )
	{
		aRespCmdL.Append( rsc_strdup( rPrePro.GetBuffer() ) );
		ByteString aTmpStr( '@' );
		aTmpStr += aRspFileName;
		aRespCmdL.Append( rsc_strdup( aTmpStr.GetBuffer() ) );
		aRespCmdL.Append( (void *)0 );

		pCmdL = &aRespCmdL;
		for( i = 0; i < (int)(aNewCmdL.GetCount() -1); i++ )
		{
#ifdef OS2
			fprintf( fRspFile, "%s\n", (const char *)aNewCmdL.GetEntry( i ) );
#else
			fprintf( fRspFile, "%s ", (const char *)aNewCmdL.GetEntry( i ) );
#endif
		}
		fclose( fRspFile );

        if ( bVerbose )
        {
		    printf( "Preprocessor startline: " );
		    for( i = 0; i < (int)(pCmdL->GetCount() -1); i++ )
		    {
			    printf( " " );
			    printf( "%s", (const char *)pCmdL->GetEntry( i ) );
		    }
		    printf( "\n" );
        }
	}

#if ((defined OS2 || defined WNT) && (defined TCPP || defined tcpp)) || defined UNX || defined OS2
	nExit = spawnvp( P_WAIT, rPrePro.GetBuffer(), (char* const*)pCmdL->GetBlock() );
#elif defined CSET
	nExit = spawnvp( P_WAIT, (char*)rPrePro.GetBuffer(), (const char**)pCmdL->GetBlock() );
#elif defined WTC
	nExit = spawnvp( P_WAIT, (char*)rPrePro.GetBuffer(), (const char* const*)pCmdL->GetBlock() );
#elif defined MTW
	nExit = spawnvp( P_WAIT, (char*)rPrePro.GetBuffer(), (char**)pCmdL->GetBlock() );
#else
	nExit = spawnvp( P_WAIT, (char*)rPrePro.GetBuffer(), (const char**)pCmdL->GetBlock() );
#endif

	if ( fRspFile )
        #if OSL_DEBUG_LEVEL > 5
        fprintf( stderr, "leaving response file %s\n", aRspFileName.GetBuffer() );
        #else
		unlink( aRspFileName.GetBuffer() );
        #endif
	if ( nExit )
		return sal_False;

	return sal_True;
}


/*************************************************************************
|*	  CallRsc2
|*
|*	  Beschreibung
*************************************************************************/
static sal_Bool CallRsc2( ByteString aRsc2Name,
					  RscStrList * pInputList,
					  ByteString aSrsName,
					  RscPtrPtr * pCmdLine )
{
	int 			i, nExit;
	ByteString* 	pString;
	ByteString		aRspFileName;	// Response-Datei
	FILE *			fRspFile;		// Response-Datei

	aRspFileName = ::GetTmpFileName();
	fRspFile = fopen( aRspFileName.GetBuffer(), "w" );

    RscVerbosity eVerbosity = RscVerbosityNormal;
	if( fRspFile )
	{
		for( i = 1; i < (int)(pCmdLine->GetCount() -1); i++ )
		{
			if ( !rsc_stricmp( (char *)pCmdLine->GetEntry( i ), "-verbose" ) )
            {
                eVerbosity = RscVerbosityVerbose;
                continue;
            }
			if ( !rsc_stricmp( (char *)pCmdLine->GetEntry( i ), "-quiet" ) )
            {
                eVerbosity = RscVerbositySilent;
                continue;
            }
			if( !rsc_strnicmp( (char *)pCmdLine->GetEntry( i ),  "-fp=", 4 )
			  || !rsc_strnicmp( (char *)pCmdLine->GetEntry( i ), "-fo=", 4 )
			  || !rsc_strnicmp( (char *)pCmdLine->GetEntry( i ), "-pp=", 4 )
			  || !rsc_strnicmp( (char *)pCmdLine->GetEntry( i ), "-rsc2=", 6 )
			  || !rsc_strnicmp( (char *)pCmdLine->GetEntry( i ), "-presponse", 9 )
			  || !rsc_strnicmp( (char *)pCmdLine->GetEntry( i ), "-rc", 3 )
			  || !rsc_stricmp( (char *)pCmdLine->GetEntry( i ), "-+" )
			  || !rsc_stricmp( (char *)pCmdLine->GetEntry( i ), "-br" )
			  || !rsc_stricmp( (char *)pCmdLine->GetEntry( i ), "-bz" )
			  || !rsc_stricmp( (char *)pCmdLine->GetEntry( i ), "-r" )
              // Am I the only one that thinks the following line inludes all the tests before?
			  || ( '-' != *(char *)pCmdLine->GetEntry( i ) ) )
			{
			}
			else
#ifdef OS2
				fprintf( fRspFile, "%s\n",
#else
				fprintf( fRspFile, "%s ",
#endif
						 (const char *)pCmdLine->GetEntry( i ) );
		};

#ifdef OS2
		fprintf( fRspFile, "%s\n", aSrsName.GetBuffer() );
#else
		fprintf( fRspFile, aSrsName.GetBuffer() );
#endif

		pString = pInputList->First();
		while( pString )
		{
#ifdef OS2
			fprintf( fRspFile, "%s\n", pString->GetBuffer() );
#else
			fprintf( fRspFile, " %s", pString->GetBuffer() );
#endif
			pString = pInputList->Next();
		};

		fclose( fRspFile );
	};

	RscPtrPtr		aNewCmdL;		// Kommandozeile
	aNewCmdL.Append( rsc_strdup( aRsc2Name.GetBuffer() ) );
	ByteString aTmpStr( '@' );
	aTmpStr += aRspFileName;
	aNewCmdL.Append( rsc_strdup( aTmpStr.GetBuffer() ) );
	aNewCmdL.Append( (void *)0 );

    if ( eVerbosity >= RscVerbosityVerbose )
    {
	    printf( "Rsc2 commandline: " );
	    printf( "%s", (const char *)aNewCmdL.GetEntry( 0 ) );
	    printf( " " );
	    printf( "%s", (const char *)aNewCmdL.GetEntry( 1 ) );
	    printf( "\n" );
    }

#if ((defined OS2 || defined WNT) && (defined TCPP || defined tcpp)) || defined UNX || defined OS2
	nExit = spawnvp( P_WAIT, aRsc2Name.GetBuffer(), (char* const*)aNewCmdL.GetBlock() );
#elif defined CSET
	nExit = spawnvp( P_WAIT, (char*)aRsc2Name.GetBuffer(), (char **)(const char**)aNewCmdL.GetBlock() );
#elif defined WTC
	nExit = spawnvp( P_WAIT, (char*)aRsc2Name.GetBuffer(), (const char* const*)aNewCmdL.GetBlock() );
#elif defined MTW
	nExit = spawnvp( P_WAIT, (char*)aRsc2Name.GetBuffer(), (char**)aNewCmdL.GetBlock() );
#else
	nExit = spawnvp( P_WAIT, (char*)aRsc2Name.GetBuffer(), (const char**)aNewCmdL.GetBlock() );
#endif

	if( fRspFile )
        #if OSL_DEBUG_LEVEL > 5
        fprintf( stderr, "leaving response file %s\n", aRspFileName.GetBuffer() );
        #else
		unlink( aRspFileName.GetBuffer() );
        #endif
	if( nExit )
		return( sal_False );
	return( sal_True );
}

/*************************************************************************
|*
|*	  main()
|*
|*	  Beschreibung
|*	  Ersterstellung	MM 05.09.91
|*	  Letzte Aenderung	MM 05.09.91
|*
*************************************************************************/
SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
{
	sal_Bool			bPrePro  = sal_True;
	sal_Bool			bResFile = sal_True;
	sal_Bool			bHelp	 = sal_False;
	sal_Bool			bError	 = sal_False;
	sal_Bool			bResponse = sal_False;
	ByteString		aSolarbin(getenv("SOLARBINDIR"));
	ByteString		aDelim("/");
	ByteString		aPrePro; //( aSolarbin + aDelim + ByteString("rscpp"));
	ByteString		aRsc2Name; //(  aSolarbin + aDelim + ByteString("rsc2"));
	ByteString		aSrsName;
	ByteString		aResName;
	RscStrList		aInputList;
	RscStrList		aTmpList;
	char *			pStr;
	char ** 		ppStr;
	RscPtrPtr		aCmdLine;		// Kommandozeile
	sal_uInt32		i;
	ByteString* 	pString;

	aPrePro = aSolarbin;
	aPrePro += aDelim;
	aPrePro += ByteString("rscpp");

	aRsc2Name = aSolarbin;
	aRsc2Name += aDelim;
	aRsc2Name += ByteString("rsc2");

	pStr = ::ResponseFile( &aCmdLine, argv, argc );
	if( pStr )
	{
		printf( "Cannot open response file <%s>\n", pStr );
		return( 1 );
	};

	ppStr  = (char **)aCmdLine.GetBlock();
	ppStr++;
	i = 1;
	sal_Bool bSetSrs = sal_False;
	while( ppStr && i < (aCmdLine.GetCount() -1) )
	{
		if( '-' == **ppStr )
		{
			if( !rsc_stricmp( (*ppStr) + 1, "p" )
			  || !rsc_stricmp( (*ppStr) + 1, "l" ) )
			{ // kein Preprozessor
				bPrePro = sal_False;
			}
			else if( !rsc_stricmp( (*ppStr) + 1, "r" )
			  || !rsc_stricmp( (*ppStr) + 1, "s" ) )
			{ // erzeugt kein .res-file
				bResFile = sal_False;
			}
			else if( !rsc_stricmp( (*ppStr) + 1, "h" ) )
			{ // Hilfe anzeigen
				bHelp = sal_True;
			}
			else if( !rsc_strnicmp( (*ppStr) + 1, "presponse", 9 ) )
			{ // anderer Name fuer den Preprozessor
				bResponse = sal_True;
			}
			else if( !rsc_strnicmp( (*ppStr) + 1, "pp=", 3 ) )
			{ // anderer Name fuer den Preprozessor
				aPrePro = (*ppStr) + 4;
			}
			else if( !rsc_strnicmp( (*ppStr) + 1, "rsc2=", 5 ) )
			{ // Accept alternate name for the rsc2 compiler
				aRsc2Name = (*ppStr) + 6;
			}
			else if( !rsc_strnicmp( (*ppStr) + 1, "fo=", 3 ) )
			{ // anderer Name fuer .res-file
				aResName = (*ppStr) + 4;
			}
			else if( !rsc_strnicmp( (*ppStr) + 1, "fp=", 3 ) )
			{ // anderer Name fuer .srs-file
				bSetSrs  = sal_True;
				aSrsName = (*ppStr);
			}
		}
		else
		{
			// Eingabedatei
			aInputList.Insert( new ByteString( *ppStr ), CONTAINER_APPEND );
		}
		ppStr++;
		i++;
	}

	if( aInputList.Count() )
	{
		/* build the output file names			*/
		if( ! aResName.Len() )
			aResName = OutputFile( *aInputList.First(), "res" );
		if( ! bSetSrs )
		{
			aSrsName = "-fp=";
			aSrsName += OutputFile( *aInputList.First(), "srs" );
		}
	};

	if( bHelp )
	{
		bPrePro = sal_False;
		bResFile = sal_False;
	};
	if( bPrePro && aInputList.Count() )
	{
		ByteString aTmpName;

		pString = aInputList.First();
		while( pString )
		{
			aTmpName = ::GetTmpFileName();
			if( !CallPrePro( aPrePro, *pString, aTmpName, &aCmdLine, bResponse ) )
			{
				printf( "Error starting preprocessor\n" );
				bError = sal_True;
				break;
			}
			aTmpList.Insert( new ByteString( aTmpName ), CONTAINER_APPEND );
			pString = aInputList.Next();
		};
	};

	if( !bError )
	{
		if( !CallRsc2( aRsc2Name, bPrePro ? &aTmpList : &aInputList,
					   aSrsName, &aCmdLine ) )
		{
			if( !bHelp )
			{
				printf( "Error starting rsc2 compiler\n" );
				bError = sal_True;
			}
		};
	};

	pString = aTmpList.First();
	while( pString )
	{
        #if OSL_DEBUG_LEVEL > 5
        fprintf( stderr, "leaving temp file %s\n", pString->GetBuffer() );
        #else
		unlink( pString->GetBuffer() );
        #endif
		pString = aTmpList.Next();
	};

	return( bError );
}

void RscExit( sal_uInt32 nExit )
{
	if( nExit )
		printf( "Program exit is %d\n", (int)nExit );
	exit( nExit );
}
