// $Id: ccDriver.java,v 1.25 2002/02/27 16:05:04 msato Exp $
// $RWC_Release: Omni-1.6 $
// $RWC_Copyright:
//  Omni Compiler Software Version 1.5-1.6
//  Copyright (C) 2002 PC Cluster Consortium
//  
//  This software is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License version
//  2.1 published by the Free Software Foundation.
//  
//  Omni Compiler Software Version 1.0-1.4
//  Copyright (C) 1999, 2000, 2001.
//   Tsukuba Research Center, Real World Computing Partnership, Japan.
//  
//  Please check the Copyright and License information in the files named
//  COPYRIGHT and LICENSE under the top  directory of the Omni Compiler
//  Software release kit.
//  
//  
//  $
package exc.util;

import java.io.*;
import exc.object.*;
import exc.block.*;
import java.lang.Runtime;
import java.util.Vector;
import java.util.Hashtable;

//
// CC driver super class
//
public class ccDriver {
  String ccDriverName;
  protected String tmp_i = "tmp.i";
  protected String tmp_x = "tmp.x";
  protected String tmp_xx = "tmp.xx";
  protected String tmp_c = "tmp.c";
  protected String tmp_cc = "tmp.cc";

  protected String ld_opts = "";
  protected String cpp_opts = "";
  protected String cc_opts = "";
  protected String lib_opts = "";

  protected String cfront_opts = "";
  protected String ffront_opts = "";

  // protected String CPP_command = "cpp";
  protected String CPP_command = "cc -E";
  protected String CC_command = "cc";
  protected String CFRONT_command = "C-front";
  protected String FFRONT_command = "F-front";
  protected String CXXFRONT_command = "Cxx-front";

  protected boolean only_exc_flag = false;
  protected boolean only_cfront_flag=false;
  protected boolean verbose = false;
  protected boolean no_tmp_files = false;
  protected boolean stop_at_asm = false;
  protected boolean stop_at_cc =false;
  protected boolean debugFlag = false;

  protected String ompc_dir = "";

  Hashtable templateTable;

  public ccDriver(String name){
    ccDriverName = name;
  }

  public void setupTemplate(){
    templateTable = new Hashtable();
    String ompc_template = System.getProperty("OMPC_TEMPLATE");
    if(ompc_template == null){
      System.err.println("no OMPC_TEMPLATE");
      System.exit(1);
    }
    if(verbose) System.err.println("setUpEnv '"+ompc_template+"'");
    try {
      BufferedReader in = new BufferedReader(new FileReader(ompc_template));
      while(true){
	String line = in.readLine();
	if(line == null) break;
	int pos = line.indexOf("=");
	if(pos < 0) continue;
	String name = line.substring(0,pos);
	String value = line.substring(pos+1,line.length());
	if(value.length() == 0) continue;

	templateTable.put(name.intern(),value);

	if(verbose) System.err.println("SetupEnv: "+name+"="+value);

	/* setup standard env */
	if(name.equals("CC"))  CC_command = value;
	else if(name.equals("CPP"))  CPP_command = value;
	else if(name.equals("CFRONT")) CFRONT_command = value;
	else if(name.equals("FFRONT")) FFRONT_command = value;
	else if(name.equals("CXXFRONT")) CXXFRONT_command = value;
      }
    } catch(IOException e){
      System.err.println("IOException: "+e);
      System.exit(1);
    } catch(IndexOutOfBoundsException e){
      System.err.println("IndexOutOfBounds: "+e);
      System.exit(1);
    }
    ompc_dir = System.getProperty("OMPC_DIR");
  }

  public String getTemplateValue(String name){
    return (String)templateTable.get(name);
  }

  // abstract class
  public boolean parseArg(String arg){ return false; }
  public void init(){ }
  public void run(XobjectFile f){ }
  public void printUsage() { }

  public void Usage(){
    System.err.println("java "+ccDriverName+" options infile");
    System.err.println("options: -I<path> -Ddef -Udef for cpp");
    System.err.println("options: -v, verbose");
    System.err.println("options: -x, stop at tmp.x");
    System.err.println("options: -X, stop at tmp.xx after java exc phase");
    System.err.println("options: -t, leave temporary files, tmp.*");
    System.err.println("options: -c, -S, -o, -g, -O");
    printUsage();
    System.err.println("options: -L<path>, -l<lib> and other options passed for ld");
    System.err.println("options: -h, -help, print this");
    System.exit(1);
  }
    
  public void run(String args[]){
    String outfile = null;
    Vector srcfiles = new Vector();
    Vector objfiles = new Vector();
    String objfile,srcfile;
    String cmd;

    for(int ac = 0; ac < args.length; ac++){
      String arg = args[ac];
      if(arg.startsWith("-")){
	if(arg.equals("-h") || arg.equals("-help")) Usage();
	else if(arg.equals("-x")) only_cfront_flag = true;
	else if(arg.equals("-X")) only_exc_flag = true;
	else if(arg.equals("-t")) no_tmp_files = true;
	else if(arg.equals("-v")) verbose = true;
	else if(arg.equals("-S")) stop_at_asm = true;
	else if(arg.equals("-c")) stop_at_cc = true;
	else if(arg.equals("-o")) outfile = args[++ac];
	else if(arg.equals("--debug")){
	  System.err.println("debug flag on ...");
	  debugFlag = true;
	  verbose = true;
	  no_tmp_files = true;
	} else if(arg.equals("-g"))
	  cc_opts += " "+arg;
	else if(arg.startsWith("-O"))
	  cc_opts += " "+arg;
	else if(arg.startsWith("-D") ||
		arg.startsWith("-I") ||
		arg.startsWith("-U"))
	  cpp_opts += " " + convForSH(arg);
	else if(arg.startsWith("-l") || arg.startsWith("-L"))
	  lib_opts += " "+arg;
	else if(!parseArg(arg))
	  ld_opts += " "+arg;
      } else if(arg.endsWith(".c") || arg.endsWith(".s") ||
		arg.endsWith(".f") || arg.endsWith(".F") ||
		arg.endsWith(".cc"))
	srcfiles.addElement(arg);
      else if(arg.endsWith(".o"))
	objfiles.addElement(arg);
      else  /* *.a file ? */
	objfiles.addElement(arg);
    }

    // setup Template
    setupTemplate();

    // call subclass init.
    init();

    // temporary
    if(only_cfront_flag || only_exc_flag) no_tmp_files = true;
    if(!no_tmp_files){
      String tmp_name = System.getProperty("OMPC_TMP");
      if(tmp_name != null){
	tmp_i = tmp_name+".i";
	tmp_x = tmp_name+".x";
	tmp_c = tmp_name+".c";
	tmp_cc = tmp_name+".cc";
	tmp_xx = tmp_name+".xx";
      }
    }
	
    for(int i = 0; i < srcfiles.size(); i++){
      srcfile = (String)srcfiles.elementAt(i);
      File ftest = new File(srcfile);
      if(!ftest.exists()){
	System.err.println("Cannot find '"+srcfile+"'...");
	System.exit(0);
      }
      System.err.println("Compiling '"+srcfile+"'...");
      int pos = srcfile.lastIndexOf(".");
      if(pos < 0) objfile = srcfile;
      else objfile = srcfile.substring(0,pos); 
      if(stop_at_asm) objfile += ".s";
      else objfile += ".o";
      if(stop_at_cc || stop_at_asm){
	if(outfile != null) objfile = outfile;
      } else objfiles.addElement(objfile);

      if(srcfile.endsWith(".c") ||
	 srcfile.endsWith(".f") || srcfile.endsWith(".F")||
	 srcfile.endsWith(".cc"))
	compile(srcfile,objfile);
      else if(!stop_at_asm && srcfile.endsWith(".s"))
	execCommand(CC_command+" -c "+srcfile+" -o "+objfile);
    }

    if(stop_at_asm || stop_at_cc) System.exit(0);
    if(objfiles.size() == 0) System.exit(0);

    // finally link 
    cmd = CC_command+" "+cc_opts;
    for(int i = 0; i < objfiles.size(); i++)
      cmd += " "+(String)objfiles.elementAt(i);
    if(outfile != null) cmd += " -o "+outfile;
    cmd += " "+lib_opts+" "+ld_opts;
    execCommand(cmd);
  }

  // compile C source program
  void compile(String srcfile,String objfile){
    boolean is_F = false;
    boolean is_Cxx = false;
    String tmp_output = tmp_c;

    if(srcfile.endsWith(".F")){
      execCommand(CPP_command + " "+cpp_opts+" "+srcfile+" > "+tmp_i);
      execCommand(FFRONT_command+" "+ffront_opts+" "+tmp_i+" "+tmp_x);
      is_F = true;
    } else if(srcfile.endsWith(".f")){
      execCommand(FFRONT_command+" "+ffront_opts+" "+srcfile+" "+tmp_x);
      is_F = true;
    } else if(srcfile.endsWith(".cc")){ /* .cc */
      execCommand(CPP_command + " "+cpp_opts+" "+srcfile+" > "+tmp_i);
      execCommand(CXXFRONT_command+" "+cfront_opts+
		  " -outx "+tmp_i+" -xf "+tmp_x);
      tmp_output = tmp_cc;  /* change file type */
      is_Cxx = true;
    } else if(srcfile.endsWith(".c")){
      // execCommand(CPP_command + " "+cpp_opts+" "+srcfile+" "+tmp_i);
      execCommand(CPP_command + " "+cpp_opts+" "+srcfile+" > "+tmp_i);
      execCommand(CFRONT_command+" "+cfront_opts+
		  " -outx "+tmp_i+" -xf "+tmp_x);
    } else {
      System.err.println("Fatal: unknown file type '"+srcfile+"'");
      System.exit(1);
    }

    if(only_cfront_flag) System.exit(0);
       
    XobjectFile f = new XobjectFile();
    f.debugFlag = debugFlag;
    if(is_F) f.Language = XobjectFile.F77_LANG;
    if(is_Cxx) f.Language = XobjectFile.CXX_LANG;

    if(verbose) System.err.println("reading tmp.x ...");
    f.Input(tmp_x);


    if (is_F && ompc_dir != null) {
	f.addHeaderLine("#include \"" + ompc_dir + "/lib/openmp/include/omniBackend.h\"");
    }

    run(f);

    if(is_Cxx && f.findIdent("_ompc_main") != null){
      f.addHeaderLine("extern \"C\" int _ompc_main();");
    }

    if(verbose) System.err.println("writing tmp.c ...");
    if(no_tmp_files) f.Output(tmp_xx);	// final output
    f.Decompile(tmp_output);	// final output
    if(only_exc_flag) System.exit(0);
       
    String cmd = CC_command + " "+cc_opts;
    if(stop_at_asm)  cmd += " -S ";
    else cmd += " -c ";
    cmd += " "+tmp_output+" -o "+objfile;
    execCommand(cmd);
  }

  void execCommand(String cmd){
    int c;
    String  cmdarray[] = { "/bin/sh", "-c", cmd};

    try {
      Runtime r = Runtime.getRuntime();
      if(verbose) System.err.println(cmd);
      Process p = r.exec(cmdarray);
      InputStream in = p.getErrorStream();
      while((c = in.read()) != -1) System.err.write(c);
      System.err.flush();
      p.waitFor();
      if(p.exitValue() != 0){
	System.err.println("Error "+p.exitValue());
	System.exit(p.exitValue());
      }
    } catch(IOException e){
      System.err.println("IOException: "+e);
      System.exit(1);
    } catch(InterruptedException e){
      System.err.println("InterruptedException: "+e);
      System.exit(1);
    }
  }

  String convForSH (String arg) {
    char str[] = arg.toCharArray ();
    String ret = "";
    int len = arg.length();
    for (int i=0; i<len; i++) {
	if (str[i] == '\\') {
	    ret = ret + "\\\\";
	} else if (str[i] == '\''){
	    ret = ret + "\'\\'\'";
	} else {
	    ret = ret + str[i];
	}
    }
    return "'" + ret + "'"; 
  }
}

