#include "afx.h"

static char args[LINE_MAX];

static void wasm(void );
static void lasm(void );
static void lasm32(void );
static void masm(void );
static void ml(void );
static void nasm(void );
static void tasm(void );
static void tasmx(void );
static void tasm32(void );
static void link(void );
static void tlink(void );
static void valx(void );
static void wlink(void );


static void exec( char *program, char *param ) {
	static char *args[3];
	int retcode;

	assert( program != NULL );
    assert( param != NULL );
#if DEBUG
	printf("*** Search '%s'\n", program );
#endif
    fn_split( program );

    args[0] = xfind( fn_make(".exe"), getrundir() );
    args[1] = param;
    args[2] = NULL;

#if DEBUG
	printf("*** Run '%s' '%s'\n", args[0], args[1] );
#endif
    retcode = spawnvp( P_WAIT, args[0], (void *)args );

    if ( retcode > 0 ) {
    	fprintf( stderr, "\n'%s' exitcode = %d\n", program, retcode );
		if (! get_option(OPT_KEEPRSP) )
			unlink( RESPONSE );
    	exit( retcode );
    } else if ( retcode < 0 ) {
    	perror( program );
		if (! get_option(OPT_KEEPRSP) )
			unlink( RESPONSE );
      exit(1);
    }
}


static FILE *response( char *fname ) {
	FILE *fp;

	assert( fname != NULL );
	unlink( fname );
	fp = fopen( fname, "wt" );
	if (!fp) {
		perror( fname );
      exit(1);
	}
	return fp;
}


void compile(void) {
	int i;

	if ( cpp_file_cnt() > 0 ) {
		FILE *fp = response( RESPONSE );
		int sys = get_dosex();
      fprintf( fp, " /c /W%c %s%ci %ce %cl %cA %cX %s \"/I%s\"", 
			( sys == OPT_W32CON || sys == OPT_W32GUI || sys == OPT_W32DLL ? 
			 	'c' : 'a'), // we aren't being too specific on the /W switch
							// since the compiler isn't spawning the linker directly
			( get_option( OPT_C99) ? "/9 " : "" ),
			( get_option( OPT_CPPFILE) ? '+' : '-' ),
			( get_option( OPT_ERRFILE) ? '+' : '-' ),
			( get_option( OPT_LSTFILE) ? '+' : '-' ),
			( get_option( OPT_EXTEND) ? '+' : '-' ),
			( get_option( OPT_EXCEPTION) ? '+' : '-' ),
			get_cc_opt(),
			get_inc_path()
		);
		if ( get_assembler() == OPT_NASM )
			fprintf( fp, " -C+N");
		else if ( get_assembler() == OPT_WASM ||
			get_assembler() == OPT_LASM ||
            get_assembler() == OPT_MASM ||
            get_assembler() == OPT_ML )
			fprintf( fp, " -C+M");
		for ( i = 0; i < cpp_file_cnt(); i++ )
			fprintf( fp, "\n%s", cpp_file(i) );
		fclose( fp );
		exec( "CC386", "/f" RESPONSE );
		if (! get_option(OPT_KEEPRSP) )
			unlink( RESPONSE );
	}
}


void assembly(void) {	

	switch( get_assembler() ) {
		case OPT_NASM:	nasm(); break;
		case OPT_TASM:	tasm(); break;
		case OPT_TASMX:	tasmx(); break;
		case OPT_TASM32:tasm32(); break;
		case OPT_MASM:	masm(); break;
		case OPT_ML:	ml(); break;
		case OPT_WASM:	wasm(); break;
		case OPT_LASM:	lasm(); break;
		case OPT_LASM32:lasm32(); break;
		default:
			fprintf( stderr, "Unknown assembler, use NASN...\n");
			nasm();
            break;
	}
	if ( !get_option(OPT_KEEPGEN) )
		del_asm_tmpfiles();
}


void linking(void) {
	switch( get_linker() ) {
		case OPT_VALX:	valx(); break;
		case OPT_TLINK: tlink(); break;
		case OPT_LINK:	link(); break;
		case OPT_WLINK: wlink(); break;
		default:
			fprintf( stderr, "Unknown linker, use VALX...\n");
			valx();
            break;
	}
	
	if ( !get_option(OPT_KEEPGEN) )
		del_obj_tmpfiles();

}

/*
**	Assembler
*/

void wasm(void) {
	int i;

	if ( asm_file_cnt() > 0 ) {
		for( i = 0; i < asm_file_cnt(); i++ ) {
			fn_split( asm_file(i) );
			sprintf( args, "-4ps -fpi87 -q -mf %s -fo=%s -fe=%s %s",
				get_option(OPT_DEBUG) ? "/d1" : "",
				fn_temp( ".obj" ),
                get_option(OPT_LSTFILE) ? fn_temp(".lst") : "NUL",
                asm_file(i)
			);
			exec( "WASM", args );
		}
	}
}

static void lasmz( char *lasm_name );

void lasm(void) {
	lasmz( "LASM" );
}

void lasm32(void) {
	lasmz( "LASM32" );
}

void lasmz(char *lasm_name) {
	int i;

	if ( asm_file_cnt() > 0 ) {
		for( i = 0; i < asm_file_cnt(); i++ ) {
			fn_split( asm_file(i) );
			sprintf( args, "/G1 /O /S /U /Y %s /FO%s /L%s %s",
				get_option(OPT_DEBUG) ? "/ZH" : "",
				fn_temp( ".obj" ),
                get_option(OPT_LSTFILE) ? fn_temp(".lst") : "NUL",
                asm_file(i)
			);
			exec( lasm_name, args );
		}
	}
}

void masm(void) {
	int i;

	if ( asm_file_cnt() > 0 ) {
		for( i = 0; i < asm_file_cnt(); i++ ) {
			fn_split( asm_file(i) );
			sprintf( "/t /Ml %s %s,%s,%s,NUL",
				get_option(OPT_DEBUG) ? "/Zi" : "",
				asm_file(i),
				fn_temp( ".obj" ),
                get_option(OPT_LSTFILE) ? fn_temp(".lst") : "NUL"
			);
			exec( "MASM", args );
		}
	}
}


void ml(void) {
	int i;

	if ( asm_file_cnt() > 0 ) {
		for( i = 0; i < asm_file_cnt(); i++ ) {
			fn_split( asm_file(i) );
			sprintf( args, "/nologo /c /Cp %s /Fo%s /Fl%s %s",
				get_option(OPT_DEBUG) ? "/Zi /Zd" : "",
				fn_temp( ".obj" ),
                get_option(OPT_LSTFILE) ? fn_temp(".lst") : "NUL",
                asm_file(i)
			);
			exec( "ML", args );
		}
	}
}


void nasm(void) {
	int i;

	if (  asm_file_cnt() > 0 ) {
		for( i = 0; i < asm_file_cnt(); i++ ) {
			strcpy( args, "-f obj " );
			if ( get_option( OPT_LSTFILE) ) {
				strcat( args, "-l ");
				fn_split( asm_file(i) );
				strcat( args, fn_temp(".lst") );
				strcat( args, " " );
			}
			strcat( args, asm_file(i) );
			exec( "NASM", args );
		}
	}
}

static void tasmz(char *);

void tasm(void) {
	tasmz( "TASM" );
}

void tasmx(void) {
	tasmz( "TASMX" );
}

void tasm32(void) {
	tasmz( "TASM32" );
}

void tasmz( char *tasm_name ) {
	FILE *fp;
	int i;

	if (  asm_file_cnt() > 0 ) {
		fp = response( RESPONSE );
		for( i = 0; i < asm_file_cnt(); i++ ) {
    		fprintf( fp, "/t /ml /m /z%c",
        		get_option(OPT_DEBUG) ? 'i' : 'n' );
			fn_split( asm_file(i) );
			fprintf( fp, " %s,%s,%s,NUL;\n",
				asm_file(i),
				fn_temp( ".obj"),
				get_option(OPT_LSTFILE) ? fn_temp( ".lst") : "NUL"
			);
		}
		fclose(fp);
    	exec( tasm_name, "@" RESPONSE );
		if (! get_option(OPT_KEEPRSP) )
			unlink( RESPONSE );
	}
}


void link(void) {
	int i;
	FILE *fp;

	if ( ( obj_file_cnt() + lib_file_cnt() ) > 0 ) {
		if ( get_dosex() != OPT_PMODE )
			fprintf( stderr, "LINK use only with PMODE!\n" );
		sprintf( args, "/NOIGNORECASE %s @" RESPONSE " ", 
			get_option(OPT_MAPFILE) ? "/MAP" : "" );	
		fp = response( RESPONSE );
		if (! get_option(OPT_NODEFLIB) ) {
			if ( get_option(OPT_DEBUG) )
				fprintf(fp,"%s\\C0DOSD.OBJ", get_syslib_path() );
			else
				fprintf(fp,"%s\\C0DOS.OBJ", get_syslib_path() );
		}
		for ( i = 0; i < obj_file_cnt(); i++ )
			fprintf( fp, " %s", obj_file(i) );
		fprintf( fp, "\n%s\n%s\n",  
			get_exe_name(),
			get_option( OPT_MAPFILE) ? get_exe_name() : "NUL"
		);
		if (! get_option(OPT_NODEFLIB) )
			fprintf(fp,"%s\\CLDOS.LIB", get_syslib_path() );
		for ( i = 0; i < lib_file_cnt(); i++ )
			fprintf( fp, " %s", lib_file(i) );
		fprintf( fp, "\n" );
		fclose(fp);
		exec("LINK", args );					
		if (! get_option(OPT_KEEPRSP) )
			unlink( RESPONSE );
	}
}

void tlink(void) {
	int i;
	FILE *fp;

	if ( ( obj_file_cnt() + lib_file_cnt() ) > 0 ) {
		if ( get_dosex() != OPT_PMODE )
			fprintf( stderr, "TLINK use only with PMODE!\n" );
		fp = response( RESPONSE );
		fprintf( fp, "/3/c/d%s ", 
			get_option(OPT_MAPFILE) ? "/m/l/s" : "/x",
            get_option(OPT_DEBUG) ? "/v" : ""
		);
		if ( lib_file_cnt() > 0 )
			fprintf(fp, "/L%s ", get_lib_path() );
		if (! get_option(OPT_NODEFLIB) ) {
			if ( get_option(OPT_DEBUG) )
				fprintf(fp,"%s\\C0DOSD.OBJ", get_syslib_path() );
			else
				fprintf(fp,"%s\\C0DOS.OBJ", get_syslib_path() );
		}
		for ( i = 0; i < obj_file_cnt(); i++ )
			fprintf( fp, " %s", obj_file(i) );
		fprintf( fp, ",%s,%s,",  
			get_exe_name(),
			get_option( OPT_MAPFILE) ? get_exe_name() : "NUL"
		);
		if (! get_option(OPT_NODEFLIB) )
			fprintf(fp,"%s\\CLDOS.LIB", get_syslib_path() );
		for ( i = 0; i < lib_file_cnt(); i++ )
			fprintf( fp, " %s", lib_file(i) );
		fprintf( fp, "\n" );
		fclose(fp);
		exec("TLINK", "@" RESPONSE );					
		if (! get_option(OPT_KEEPRSP) )
			unlink( RESPONSE );
	}
}


void valx(void) {
	int i;
	FILE *fp;
	char *c0 = "C0DOS.OBJ";
	char *c0d= "C0DOSD.OBJ";
	char *cl = "CLDOS.LIB";
	char *ci = NULL;
	char *dosx = NULL;
   char *lnk_op = "/NCI /32";


	if ( ( obj_file_cnt() + lib_file_cnt() ) > 0 ) {
		int sys = get_dosex();
		switch ( sys ) {
			case OPT_W32CON:
				c0d = c0 = "C0xwin.obj"; cl = "CLWIN.LIB"; ci = "CLIMP.LIB"; 
				lnk_op = "/NCI /PE";
                break;
			case OPT_W32GUI:
				c0d = c0 = "C0win.obj"; cl = "CLWIN.LIB"; ci = "CLIMP.LIB"; 
                lnk_op = "/NCI /PE /WIN";
                break;
			case OPT_W32DLL: 
				c0d = c0 = "C0dwin.obj"; cl = "CLWIN.LIB"; ci = "CLIMP.LIB";
                lnk_op = "/NCI /PE /BDL";
				break;
         case OPT_DOS32A:
            c0d = "c0doswd.obj" ;
			c0 = "c0dosw.obj" ;
            lnk_op = "/NCI /LE" ;
			dosx = "stub32a.exe" ;
            break ;
		    case OPT_PMODEW:
	            c0d = "c0doswd.obj" ;
				c0 = "c0dosw.obj" ;
        	    lnk_op = "/NCI /LE" ;
				dosx = "pmodew.exe"; 
				break;
		    case OPT_DOS4G:	
	            c0d = "c0doswd.obj" ;
				c0 = "c0dosw.obj" ;
        	    lnk_op = "/NCI /LE" ;
				dosx = "4gstub.exe"; 
				break;
		    case OPT_WDOSX:	
	            c0d = "c0doswd.obj" ;
				c0 = "c0dosw.obj" ;
        	    lnk_op = "/NCI /LE" ;
				dosx = "wdosxle.exe"; 
				break;
		    case OPT_ZRDX:	
	            c0d = "c0doswd.obj" ;
				c0 = "c0dosw.obj" ;
        	    lnk_op = "/NCI /LE" ;
				dosx = "zrdx.exe"; 
				break;
		    case OPT_CAUSEWAY:	
	            c0d = "c0doswd.obj" ;
				c0 = "c0dosw.obj" ;
        	    lnk_op = "/NCI /LE" ;
				dosx = "cwstub.exe"; 
				break;
			case OPT_HXDOS:
				c0d = c0 = "C0xwin.obj"; 
				cl = "CLWIN.LIB"; 
				ci = "CLIMP.LIB"; 
				lnk_op = "/NCI /PE";
				dosx = "dpmist32.bin";
				break;
			default:
				fprintf( stderr, "VALX use only with PMODE!\n" );
			case OPT_PMODE:
				break;
		}
		fp = response( RESPONSE );
		fprintf( fp, "-NOCA -USE32 %s ",
			get_option(OPT_MAPFILE) ? "-MAP" : "-NOMAP" );	
		if ( lnk_op )
			fprintf( fp, "%s ", lnk_op);
		if (dosx)
			fprintf(fp, "-STB:(%s\\%s) ", get_syslib_path(), dosx);
		if (! get_option(OPT_NODEFLIB) ) {
			if ( get_option(OPT_DEBUG) )
            fprintf(fp,"\"%s\\%s\"", get_syslib_path(), c0d );
			else
            fprintf(fp,"\"%s\\%s\"", get_syslib_path(), c0 );
		}
		for ( i = 0; i < obj_file_cnt(); i++ )
			fprintf( fp, " %s", obj_file(i) );
		fprintf( fp, ",%s,%s,",  
			get_exe_name(),
			get_option( OPT_MAPFILE) ? get_exe_name() : "NUL"
		);
		if (! get_option(OPT_NODEFLIB) )
         fprintf(fp,"\"%s\\%s\"", get_syslib_path(), cl );
		if (ci)
         fprintf(fp," \"%s\\%s\"", get_syslib_path(), ci );
		for ( i = 0; i < lib_file_cnt(); i++ )
			fprintf( fp, " %s", lib_file(i) );
		fprintf( fp, "\n" );
		for ( i = 0; i < res_file_cnt(); i++ )
			fprintf( fp, " %s", res_file(i) );
        fprintf( fp, "\n\n" );
		fclose(fp);
		exec("VALX", "@" RESPONSE );
		if (! get_option(OPT_KEEPRSP) )
			unlink( RESPONSE );
  	    if ( !get_option(OPT_KEEPGEN) )
		{
		    del_res_tmpfiles();
		}
	}
}


void wlink(void) {
	int i;
	char *dosx;
	FILE *fp;

	if ( ( obj_file_cnt() + lib_file_cnt() ) > 0 ) {
		switch ( get_dosex() ) {
		    case OPT_PMODEW:dosx = "pmodew.exe"; break;
		    case OPT_DOS4G:	dosx = "4gs.exe"; break;
		    case OPT_WDOSX:	dosx = "wdosxle.exe"; break;
		    case OPT_DOS32A:dosx = "dos32a.exe"; break;
		    case OPT_ZRDX:	dosx = "zrdx.exe"; break;
		    case OPT_CAUSEWAY:	dosx = "cwstub.exe"; break;
			case OPT_PMODE:	
			default:
				fprintf( stderr, "WLINK NO use with PMODE!\n" );
				dosx = "4gs.exe";
				break;
		}
		fp = response( RESPONSE );
		fprintf( fp,
			"op osname=CC386[%s]\n"
			"format os2 le\n"
			"op nod\n"
			"op quiet\n"
			"op stub=%s\\%s\n"
			"name %s\n",
		    dosx,
		    get_syslib_path(),
		    dosx,
		    get_exe_name()
		);
		if ( get_option(OPT_MAPFILE) )
			fprintf( fp, "op map\n" );
		if ( get_option(OPT_DEBUG) )
			fprintf( fp, "debug all \nop symf\n" );
		if (! get_option(OPT_NODEFLIB) )
			fprintf( fp, "file %s\\C0DOSW.OBJ\n", get_syslib_path() );
		for( i = 0; i < obj_file_cnt(); i++)
			fprintf( fp, "file %s\n", obj_file(i) );
		if (! get_option(OPT_NODEFLIB) )
			fprintf( fp, "library %s\\CLDOS.LIB\n", get_syslib_path() );
		for( i = 0; i < lib_file_cnt(); i++)
			fprintf( fp, "library %s\n", lib_file(i) );
		fclose(fp);
		exec("WLINK", "@" RESPONSE );
		if (! get_option(OPT_KEEPRSP) )
			unlink( RESPONSE );
	}
}
void xrc(void) {
	int i;

	if (  rc_file_cnt() > 0 ) {
		for( i = 0; i < rc_file_cnt(); i++ ) {
			sprintf( args, "/r \"/i%s\" ", get_inc_path() );
			strcat( args, rc_file(i) );
			exec( "xrc", args );
		}
	}
}
