#!/bin/bash
##!/bin/sh -vx
######################################################################################
# Author:             Bobby Philip                                                   #
# Creation Date:      11/05/2001                                                     #
# Last Modified Date: 12/04/2001                                                     #
######################################################################################

#NEED TO PUT IN CODE TO SET IFS TO SAFE VALUES

# Bourne shell does not allow for the declaration of local
# variables in functions. Hence we create a non recursive method
# for processing all headers in a directory and its sub directories

######################################################################################

process_headers()
{

# make sure the source directory structure exists
  if  [ ! -d "$2" -o ! -r "$2" -o ! -x "$2" ]
  then
    echo "ERROR: Directory $2 is invalid"
    echo "*************  FAILING ***** FAILING *****************"
    exit 2
  fi

# get full path for the current working directory, the src and target dirs
  current_dir="`pwd`"
  src_parent_dir=`dirname "$2"`
  src_base_dir="`basename "$2"`"
  src_dir="`cd \"$src_parent_dir\" 2>/dev/null && pwd || echo \"$src_parent_dir\"`/$src_base_dir"

  target_parent_dir="`dirname "$3"`"
  target_base_dir="`basename "$3"`"
  target_dir="`cd \"$target_parent_dir\" 2>/dev/null && pwd || echo \"$target_parent_dir\"`/$target_base_dir"
# roseHome is the top rose source tree
  roseHome="$4"

# echo "*****************************************"
# echo "Parameter 1 = $1"
# echo "Parameter 2 = $2"
# echo "Parameter 3 = $3"
# echo "roseHome = $roseHome"
# echo "src_dir = $src_dir"
# echo "target_base_dir = $target_base_dir"
# echo "target_parent_dir = $target_parent_dir"
# echo "target_dir = $target_dir"
# echo "*****************************************"

# now check that the parent directory of target_dir exists and is writable
  if [ ! -d "$target_parent_dir" -o ! -w "$target_parent_dir" ]
  then
    echo "ERROR: Target directory cannot be created (Parent directory $target_parent_dir not writable)"
    exit 5
  fi
  changesNeededForThisDir=`find "$src_dir/." \( -name complex -o -name c++config.h \) -a -type f -a -print 2>/dev/null | wc -l`
  echo "$src_dir needs $changesNeededForThisDir change(s)"
  if test $changesNeededForThisDir -eq 0; then
    echo "$src_dir does not need any changes"
    target_dir=$src_dir
    target_base_dir=$src_base_dir
    target_parent_dir=$src_parent_dir
  else
    echo "$src_dir needs to be copied and modified"
    find "$src_dir/." -type d -a -print | sed -n "s|^${src_dir}\\(.*\\)\$|mkdir -p '$target_dir/\\1'|p" | sh -s
    if [[ "x$OSTYPE" == "xdarwin"* ]]; then
    find "$src_dir/." -type f -a -print | sed -n "s|^${src_dir}\\(.*\\)\$|ln -s -F '&' '$target_dir/\\1'|p" | sh -s
    else
    find "$src_dir/." -type f -a -print | sed -n "s|^${src_dir}\\(.*\\)\$|ln -s --force '&' '$target_dir/\\1'|p" | sh -s
    fi
  # find "$src_dir/." -type f -a -print | sed -n "s|^${src_dir}\\(.*\\)\$|ln -s '&' '$target_dir/\\1'|p" | sh -s &
    echo "Done copying"
    # Find the special-case files to process
    find "$src_dir/." \( -name complex -o -name c++config.h \) -a -type f -a -print 2>/dev/null | \
    while read srcName; do
     # echo "processing files in directory $srcDirName to put into $targetDirName"
     # this is not the most efficient thing to do ...
       targetName="`echo "$srcName" | sed "s|$src_dir|$target_dir|g"`"
       rm "$targetName" # In case targetName is a link to something in the base include directory
       case "`basename $srcName`" in
         "complex" )
           echo "Processing complex header file (commenting out private constructor) at $targetName"
           sed -e 's@_GLIBCXX_CONSTEXPR complex(_ComplexT __z)@// ***commented out for ROSE*** _GLIBCXX_CONSTEXPR complex(_ComplexT __z)@g' "$srcName" > "$targetName" 2>/dev/null
           ;;
         "c++config.h" )
           # JJW (10/29/2007): In GCC 4.2, the system header files use the visibility
           # attribute which EDG 3.3 does not support.  A #define can be changed to turn
           # that feature off, though.  Also, the built-in synchronization functions in
           # new versions of GCC are not yet supported in ROSE, so turn them off too.
           echo "Processing c++config header file (removing use of visibility attribute) at $targetName"
           cat "$srcName" | \
             sed 's/# *define _GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY 1/#define _GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY 0/' | \
             sed 's/# *define _GLIBCXX_USE_C99_FENV_TR1 1/#define _GLIBCXX_USE_C99_FENV_TR1 0/' | \
             sed 's/# *define _GLIBCXX_ATOMIC_BUILTINS/#undef _GLIBCXX_ATOMIC_BUILTINS/' | \
             sed 's/# *define _GLIBCXX_USE_FLOAT128/#undef _GLIBCXX_USE_FLOAT128/' > "$targetName"
           ;;
         * ) echo "Should not get here -- modify find pattern" >&2; exit 1 ;;
       esac
    done
  fi

 # DQ (4/11/2005): Copy the header file that is to be read first (within EDG processing) into the compile tree.
 # echo "Copying $roseHome/config/rose_edg_required_macros_and_functions.h to $target_parent_dir"
 # cp $roseHome/config/rose_edg_required_macros_and_functions.h $target_parent_dir

# go back to where we started from
  cd "$current_dir"
}

######################################################################################
# start of main
# check for correct number of arguments and 
# whether a source directory has been specified
if [ $# -eq 3 ]; then
  :
else
   echo "ERROR: Usage is $0 <compiler> <target_dir> <source_dir>"
   exit 1
fi

# echo "In main(): parameter 1 = $1  parameter 2 = $2 parameter 3 = $3"

# for now assume that if a compiler is specified that it is installed
# see if the full path name has been specified for compiler and if
# so check if the compiler executable exists in the specified directory
compilerName="`basename $1`"
compilerBinDir="`dirname $1`"
roseHome="$3"

echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
echo "compilerName   = $compilerName"
echo "compilerBinDir = $compilerBinDir"
echo "roseHome       = $roseHome"
echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"

# DQ (8/24/2009): Allow either "roseTranslator" or "roseAnalysis"
# if [ "$compilerName" == "roseTranslator" ]
# if [ "$compilerName" == "roseTranslator" || "$compilerName" == "roseAnalysis" ]
if [ "$compilerName" == "roseTranslator" ]
then
compilerName="g++"
echo "Changed compilerName from roseTranslator to $compilerName"

echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
echo "After change: compilerName   = $compilerName"
echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
elif [ "$compilerName" == "roseAnalysis" ]
then
compilerName="g++"
echo "Changed compilerName from roseAnalysis to $compilerName"
fi

# we try to ensure that paths can be given, to enable using different versions of the same compiler
if [ "$compilerBinDir" != "." ]
then
   [ -x "$1" ] || exit 1   # make sure that we have an executable
fi

# echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
# echo "targetDir originating string = $*"
# echo "targetDir =  $targetDir"
# echo "targetDirParent =  $targetDirParent"
# echo "targetDirBase =  $targetDirBase"
# echo "mainTargetDir =  $mainTargetDir"
# echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"


# determine the absolute path for the target dir
# targetDir=`echo $* | cut -f $# -d" "`
targetDir="$2"
targetDirParent="`dirname "$targetDir"`"
targetDirBase="`basename "$targetDir"`"
mainTargetDir="`cd \"$targetDirParent\" 2>/dev/null && pwd || echo \"$targetDirParent\"`/$targetDirBase"

# echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
# echo "Now these should be set ..."
# echo "targetDir =  $targetDir"
# echo "targetDirParent =  $targetDirParent"
# echo "targetDirBase =  $targetDirBase"
# echo "mainTargetDir =  $mainTargetDir"
# echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"

is_C_compiler="no"

#AS moved the mkdir of $mainTargetDir here because the ICC and gcc case need it below
# we will first ensure that targetDirName exists
if mkdir -p "$mainTargetDir"; then
  : # echo "created target directory"
else
  echo "ERROR: cannot create target directory $mainTargetDir"
  exit 1
fi

if [ ! -w "$mainTargetDir" ]
then
   echo "ERROR: target directory $mainTargetDir is not writable"
   exit 1
fi


# no src dir specified, try to determine automatically based on compiler name
 case "$compilerName" in
  # Support for compiling ROSE with GNU g++ compiler
  # g++|gcc|icpc|icc|mpicc|mpic++|mpiCC|mpicxx|roseTranslator)
  # g++|gcc|icpc|icc|mpicc|mpic++|mpiCC|mpicxx|c++)
  # g++*|gcc*|cc*|icpc|icc|mpicc|mpic++|mpiCC|mpicxx|c++|xt-xcc|xt-xc++)
    g++*|gcc*|cc*|icpc|mpiicpc|icc|mpiicc|mpicc|mpic++|mpiCC|mpicxx|c++|xt-xcc|xt-xc++)
         case "$compilerName" in
         # gcc*|cc*|icc|mpicc|xt-xcc)
           gcc*|cc*|icc|mpicc|mpiicc|xt-xcc)
              is_C_compiler="yes"
              language="c"
              ;;
           *)
              language="c++"
              ;;
          esac

       # DQ (1/14/2007): To work with Wave we supress the __STDC_HOSTED__ macro
         tmpFile="`mktemp -t roseconfigtempXXXXXXXXXX`"
         "$1" -E -dM -x $language /dev/null | grep -F -v -w -f "$roseHome/config/macro_names_to_remove" > "$tmpFile"
         sed "/REPLACE_ME_WITH_MACRO_DEFINITIONS/r$tmpFile" < "$roseHome/config/rose_edg_required_macros_and_functions.h.in" > "$mainTargetDir/rose_edg_required_macros_and_functions.h"

         echo "******************************************************"
         echo "******************************************************"
         cat "$tmpFile"
         echo "******************************************************"
         echo "******************************************************"
       # echo "Modified rose_edg_required_macros_and_functions.h file"
       # cat "$mainTargetDir/rose_edg_required_macros_and_functions.h"
       # echo "******************************************************"
       # echo "******************************************************"

         rm "$tmpFile"

       # echo "PREPROCESSOR_DEFS = $PREPROCESSOR_DEFS"
         echo "Generating  $mainTargetDir/rose_edg_required_macros_and_functions.h"

       # echo "Exiting as a test!"
       # exit 1

         ;;

  # Support for compiling ROSE with ROSE (must use translator named: "roseTranslator"
  # DQ (8/22/2009): Commented this out so that support would be the same as for g++ (ROSE acts like g++ by default)
  #  roseTranslator)
  #       compilerName="g++"
  #       echo "Note: changing compilerName configure variable from \"roseTranslator\" to $compilerName"
  #       ;;
    *) echo "ERROR: Not able to recognize compiler $1"
       echo "ERROR: Usage is create_system_headers compiler target_dir src_dir"
       exit 1
       ;;
 esac

# echo "local script variable compilerHeadersDirCmd = $compilerHeadersDirCmd"
# echo "Building separate header directories"

iDir=0
sh "$roseHome/config/get_compiler_header_dirs" "$1" | while read dirName
   do
         iDir=`expr "$iDir" + 1 `
        echo "processing header file directory $dirName to be mapped to $mainTargetDir/hdrs${iDir}"

      # DQ (1/14/2007): Added "&" so that this would happen in parallel (to improve performance of configure on multi-core machines). 
      # JJW (7/18/2008): Commented it out because the process does not take too
      # long and these commands mess up configure output and cause trouble if
      # you try Ctrl-C when configure is running
        process_headers "$1" "$dirName" "$mainTargetDir/hdrs${iDir}" "$roseHome" # &
   done

# DQ (1/14/2007): It is not required to wait until the calls to process_headers complete
# wait

# DQ (1/14/2007): This is not handled directly for each backend compiler (above).
# DQ (4/11/2005): Copy the header file that is to be read first (within EDG processing) into the compile tree.
# echo "Copying ($roseHome/config/rose_edg_required_macros_and_functions.h) to ($target_parent_dir) ..."
# cp $roseHome/config/rose_edg_required_macros_and_functions.h $target_parent_dir

# DQ (6/27/2006): We really should verify that "/usr/include/sys/cdefs.h" exists since we reference it explicitly 
# in the ROSE specific generated "sys/cdefs.h" header file.
#if [ -f /usr/include/sys/cdefs.h ]
#then
#    echo "Verified \"/usr/include/sys/cdefs.h\" exists ... (referenced by ROSE specific \"sys/cdefs.h\" header file)"
# else
#    echo "ERROR: Could not find \"/usr/include/sys/cdefs.h\" system header file ... (referenced by ROSE specific \"sys/cdefs.h\" header file)"
#    exit 5
#fi

# DQ (1/14/2007): The variable target_parent_dir is not set in this shell procedure, so it causes an error.
system_headers_directory="$mainTargetDir/hdrs"
echo "system_headers_directory = $system_headers_directory should be used instead of target_parent_dir = $target_parent_dir"

# echo "Exiting as a test! calling exit 1"
# exit 1

# DQ (6/27/2006): Copy a ROSE specific version of cdefs.h to $target_parent_dir/sys so that the "__flexarr"
# macro can be redefined so that Red Hat 7.3 will not require variable length arrays in definition of
# "struct __gconv_info __cd;" in "/usr/include/_G_config.h".  This is a common problem since C does not
# support this (gnu does however as an extension).  This is a problem for EDG and we fix it this way.

echo "Copying $roseHome/config/rose_specific_cdefs.h to $system_headers_directory/sys to fix __gconv_info incomplete definition problem ..."
mkdir -p "$system_headers_directory/sys"
# cp $roseHome/config/rose_specific_cdefs.h $target_parent_dir/sys/cdefs.h
cp "$roseHome/config/rose_specific_cdefs.h" "$system_headers_directory/sys/cdefs.h"

error_code=$?
if test $error_code != 0; then
     echo "Error in cp $roseHome/config/rose_specific_cdefs.h $system_headers_directory/sys/cdefs.h: nonzero exit code returned to caller error_code = $error_code" >&2
     exit 1
fi

if [ is_C_compiler = "yes" ]
then
    echo "We are handling C compiler specific details, so copy the ROSE specific fix for complex.h to $system_headers_directory" >&2
    cp "$roseHome/config/rose_specific_complex.h" "$system_headers_directory/complex.h"
fi

error_code=$?
if test $error_code != 0; then
     echo "Error in cp $roseHome/config/rose_specific_complex.h $system_headers_directory/complex.h: nonzero exit code returned to caller error_code = $error_code" >&2
     exit 1
fi

# echo "Leaving script for processing header files"
