/*
   lcc.c

   Simple cc like interface, for rcc (lcc) and lcclnk.

   By - Scott Beasley, 03/24/97.
        scottb@lowcountry.com   
*/

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

/* Useful Macros. */
#define GetCommandLineArg(argnum) ((argnum)<=(argc-1))?argv[argnum]:""
#define NumOfCmdArgs() ((argc-1)>0?argc-1:0)
#define CheckArgCnt(reqnum) ((argc-1)>=(reqnum)?1:0)

/* Define for compiler and linker names. */
#define COMPILER "rcc "
#define LINKER   "lcclnk "

int main ( int argc, char **argv );

int main ( int argc, char **argv )
{
   int iRet = 0, iArgCnt = 1, iFileCnt = 0;
   int iCflgCnt = 0, iLdflgCnt = 0, iCnt = 0;
   int iLnkFlgs = 0, iNoLd = 0;
   char cFilesDone = 0;
   char strArg[256];
   char strCpFlgs[256], strLdFlgs[256];
   char *strFileLst[100], *strCflagLst[50];
   char *strLdflagLst[50], *strOffset;
     
   if ( !CheckArgCnt ( 1 ) ) {
      puts ( "Usage: lcc [-c] [compiler flags] files... [linker flags]" );
      puts ( "   ie: lcc hello.c -o hello.exe -s" );
      puts ( "lcc flag: -c  compile file(s) only, with no linking done" );
      exit ( 1 );
   }

   while ( 1 ) {
      strcpy ( strArg, GetCommandLineArg ( iArgCnt ) );

      if ( !strcmp ( strArg, "-c" ) && !cFilesDone ) {
         iNoLd = 1;
         iArgCnt++;
         continue;
      }
    
      if ( *strArg == '-' && !cFilesDone )
         *( strCflagLst + iCflgCnt++ ) = ( char * ) *( argv + iArgCnt );

      if ( *strArg == '-' && cFilesDone ) {
         iLnkFlgs = 1;
         *( strLdflagLst + iLdflgCnt++ ) = ( char * ) *( argv + iArgCnt );
      }

      if ( *strArg != '-' && !iLnkFlgs ) {
         cFilesDone = 1;
         *( strFileLst + iFileCnt++ ) = ( char * ) *( argv + iArgCnt );
      }

      if ( *strArg != '-' && iLnkFlgs ) {
         cFilesDone = 1;
         *( strLdflagLst + iLdflgCnt++ ) = ( char * ) *( argv + iArgCnt );
      }

      if ( iArgCnt == NumOfCmdArgs ( ) )
         break;
  
      iArgCnt++;
   }

   iCnt = 0;
   strcpy ( strCpFlgs, COMPILER );
   while ( iCnt != iCflgCnt ) {
      strcat ( strCpFlgs, *( strCflagLst + iCnt++ ) );
      strcat ( strCpFlgs, " " );      
   }

   iCnt = 0;
   strcpy ( strLdFlgs, LINKER );
   while ( iCnt != iLdflgCnt ) {
      strcat ( strLdFlgs, *( strLdflagLst + iCnt++ ) );
      strcat ( strLdFlgs, " " );      
   }

   iCnt = 0;
   memset ( strArg, 0, sizeof ( strArg ) );
   while ( iCnt != iFileCnt ) {
      strcpy ( strArg, strCpFlgs );
      strcat ( strArg, *( strFileLst + iCnt ) );

      if ( !strchr ( *( strFileLst + iCnt++ ), '.' ) ) {
         strcat ( strArg, ".c" );         
      }

      puts ( strArg );
      iRet = _system ( strArg );
      if ( iRet )
         break; 
   }   

   iCnt = 0;
   while ( !iRet && iCnt != iFileCnt && !iNoLd ) {
      strOffset = strchr ( *( strFileLst + iCnt++ ), '.' );
      if ( strOffset ) {
         *strOffset = 0;
      }
   }   

   iCnt = 0;
   memset ( strArg, 0, sizeof ( strArg ) );
   strcpy ( strArg, strLdFlgs );
   strcat ( strArg, " " );
   while ( !iRet && iCnt != iFileCnt && !iNoLd ) {
      strcat ( strArg, *( strFileLst + iCnt++ ) );
      strcat ( strArg, ".obj " );
   }

   if ( !iRet && *strArg && !iNoLd ) {
      puts ( strArg );
      iRet = _system ( strArg );
   }

   if ( iRet )
      printf ( "\nlcc ended with a return code of %d\n", iRet );

   return iRet;
}

/* 
   Taken from the make project.
*/
/*
 * This way, child programs will execute and return the
 * right exit code values.
 */

int _system(const char *cmd)
{
  BOOL                bResult;
  STARTUPINFO         si;
  PROCESS_INFORMATION pi;
  DWORD               exitcode;

  memset(&si,0,sizeof(STARTUPINFO));
  si.cb = sizeof(STARTUPINFO);
  
  bResult = CreateProcess(NULL,
			  cmd,
			  NULL,NULL, /* No security */
			  TRUE,	     /* Inherits handles */
			  0,	     /* Runs normally  */
			  NULL,NULL, /* Inherits env & cwd */
			  &si,&pi);

  if (bResult == FALSE) 
    return system(cmd);
   
  while (bResult = GetExitCodeProcess(pi.hProcess,&exitcode))
    if (exitcode != STILL_ACTIVE)
      break;

  if (bResult == FALSE) {
    printf("GetExitCodeProcess() returned FALSE\n");
    return -1;
  }

  return (int)exitcode;
}

