#! /bin/sh

#    May 29/13 - F.Majaess (cosmetic changes)
#
#id  f90split_reorder - Return an ordered list of code files to compile.
#
#    AUTHOR  - F.Majaess
#
#  PURPOSE - "f90split_reorder" script, given the dependency "dpds0001.mk" 
#            make file produced by "f90split", it returns a string of 
#            ordered files list honouring depencies mapping. to be used 
#            in proper ordering of code compilation.
#            NOTE: If requested via "list" switch option, it also produces
#                  the same ordered list, one entry per line,
#                  in "f90split_reordered_list" file. Also, it generates
#                  in  "f90split_reordered_subprogram_referenced_by_list" file
#                  a compiled list of "[In]direct referenced by" subprograms, 
#                  and in "f90split_reordered_subprogram_reference_to_list" 
#                  file a compiled list of "Dependent on" subprograms.
#                  In addition, if requested via "list" and "clean" switch
#                  combination, "f90split_reordered_modules_cleanup_sh"
#                  script file get produced which can be executed to
#                  delete any ".mod" file corresponding to inlined 
#                  "module" source code.
#
#pr PARAMETERS:
#pr
#pr   PRIMARY
#pr
#pr     mkfil   = Name of dependency make file produced by "f90split"
#pr               (='dpds0001.mk')
#pr
#pr   SECONDARY
#pr
#pr     list    = Switch controls producing "f90split_reordered_list" file.
#pr               (=no/yes)
#pr
#pr     clean   = Switch controls limiting referenced files in the returned
#pr               string to just existing files in the local subdirectory.
#pr               (=no/yes)
#pr

#ex EXAMPLE:
#ex
#ex   f90split_reorder list
#ex
#ex     The above example, provided "dpds0001.mk" valid local file exists,
#ex     results in returing a string of filenames ordered according to 
#ex     mapped depencies. It also produces similar info, one entry per line,
#ex     in "f90split_reordered_list" file. In addition, 
#ex     "f90split_reordered_subprogram_referenced_by_list" and 
#ex     "f90split_reordered_subprogram_reference_to_list" local files are produced.

IFS=' '
export IFS

mkfil=''
list=''
clean=''

#  * Obtain the filename and any specified option.

for arg in $@
do
  case $arg in
       *=*) eval "$arg"                      ;;
       -*) set $arg                          ;;
      LIST|list) list='yes'                  ;;
      CLEAN|clean) clean='yes'               ;;
         *) mkfil=${mkfil:=$arg}
  esac
done

list=${list:=no}
clean=${clean:=no}
mkfil=${mkfil:='dpds0001.mk'}

if [ -s "$mkfil" ] ; then
  # ------------------------------
  # Reorder the list based on "dpds0001.mk" produced file by "f90split"
  # and applying:
  #  "tr" to force upper case harmonization
  #  "sed" to massage further
  #  "AWK" to reformat by printing first argument for each other argument on each line
  #            basically preparing proper input for "tsort"
  #  "sort|uniq" to elimitae duplicates
  #  "tsort" to apply topological sort
  #  "tac" to reverse the lines (from last to first) so that dependent routines show
  #        after the routines they depend on
  #  "tee" to keep a copy of "ordered" list (if requested)
  #  "tr" to convert the lines into a string.
  # ------------------------------
  f90split_reorder_sed_script_file="/tmp/${HOSTID}_f90split_reorder_sed_script_file_$$_"`date +%Y%j%H%M%S`
  f90split_reorder_sed_script_file_1="${f90split_reorder_sed_script_file}_1"
  f90split_reorder_sed_script_file_2="${f90split_reorder_sed_script_file}_2"
  f90split_reorder_sed_script_file_3="${f90split_reorder_sed_script_file}_3"
  ( \rm -f $f90split_reorder_sed_script_file_1 $f90split_reorder_sed_script_file_2 $f90split_reorder_sed_script_file_3 2>>/dev/null || : ) 2>>/dev/null
  ( \rm -f ./f90split_reordered_list ./f90split_reordered_subprogram_referenced_by_list ./f90split_reordered_raw_subprogram_reference_to_list ./f90split_reordered_subprogram_reference_to_list || : )
  ( \rm -f ./f90split_reordered_modules_cleanup_sh || : )

  # Prepare in "$f90split_reorder_sed_script_file_1" sed script file for massaging ".mod" reference entries:

  cat $mkfil | sed -n -e '/\.mod : /p' | $AWK '{ xx=tolower($1) ; print "s/" xx "/" $3 "/g" ; }' | sed -e 's/\./\\./g' > $f90split_reorder_sed_script_file_1

  if [ "$list" = 'yes' ] ; then

   # Prepare in "$f90split_reorder_sed_script_file_2" sed script file for filtering out ".o" entries associated with ".mod":

   cat $mkfil | sed -n -e 's/\.mod : .*$/\.o /p' | sed -n -e 's/^/\/^/' -e 's/$/\/d/' -e '1,$p' | sed -e 's/\./\\./g' | sort | uniq > $f90split_reorder_sed_script_file_2

   # Prepare in "$f90split_reorder_sed_script_file_3" sed script file for expanding referenced subprograms:

   cat $mkfil | sed -f $f90split_reorder_sed_script_file_2 | sed -e 's/$/ /' | sed -e '/\.mod : /{
s/\.f90 /\.mod /g
}' |  sed -n -e 's/\.mod : /\.mod : /p' -e 's/\.o : /\.f90 : /p' | sed -n -e 's/^/s\/ /' -e 's/$/\/g/' -e 's/ *: */ \/ /' -e '1,$p' | sed -e 's/\./\\./g' | sort | uniq > $f90split_reorder_sed_script_file_3

   # Prepare "f90split_reordered_subprogram_referenced_by_list"  and "f90split_reordered_raw_subprogram_reference_to_list" files:

   cat $mkfil | sed -e 's/$/ /' | sed -f $f90split_reorder_sed_script_file_2 |  sed -e '/\.mod : /{
s/\.f90/\.mod/g
}' | sed -e 's/\.mod : /\.XxX : /' -e 's/\.o : /\.FXX : /' | sed -f $f90split_reorder_sed_script_file_3 | sed -e 's/\.XxX : /\.mod : /' -e 's/\.FXX : /\.f90 : /' | sort -k1,1 | uniq | sed -e 's/ *: */ --> /g' |  tee f90split_reordered_raw_subprogram_reference_to_list | sed -e 's/ *--> */ /g' | $AWK '{ for (i = 2 ; i<= NF ; ++i ) { xx=$i ; print xx " " $1; } ; }' | sort -k1,1 | uniq | $AWK -v modlx="fake" '{ if ( $1 == modlx ) { for (i = 2 ; i<= NF ; ++i ) { xx=$i ; if ( xx != modlx ) { printf "%s%s", " ", xx } ; } ; } else { printf "\n" ; modlx=$1 ; printf "%s%s%s", modlx , " : " , modlx ; for (i = 2 ; i<= NF ; ++i )  { xx=$i ; if ( xx != modlx ) { ; printf "%s%s", " ", xx } ; } ; } ; } END { printf "\n" } ' | sed -e 's/ : / <-- [In]directly referenced by -- /' | sed -e '/^ *$/d' > f90split_reordered_subprogram_referenced_by_list

   ( \rm -f $f90split_reorder_sed_script_file_2 $f90split_reorder_sed_script_file_3 2>>/dev/null || : ) 2>>/dev/null

   # Cleanup duplicate references from "f90split_reordered_raw_subprogram_reference_to_list" into "f90split_reordered_subprogram_reference_to_list" file:

   cat f90split_reordered_raw_subprogram_reference_to_list | sed -e 's/ *--> */ /' | $AWK '{ for (i = 2 ; i<= NF ; ++i ) { xx=$i ; print $1 " " xx ; } ; }' | sort -k1,1 | uniq | $AWK -v modlx="fake" '{ if ( $1 == modlx ) { for (i = 2 ; i<= NF ; ++i ) { xx=$i ; if ( xx != modlx ) { printf "%s%s", " ", xx } ; } ; } else { printf "\n" ; modlx=$1 ; printf "%s%s%s", modlx , " : " , modlx ; for (i = 2 ; i<= NF ; ++i ) { xx=$i ; if ( xx != modlx ) { printf "%s%s", " ", xx } ; } ; } ; } END { printf "\n" } ' | sed -e 's/ : / -- Dependent on --> /' | sed -e '/^ *$/d' > f90split_reordered_subprogram_reference_to_list
   ( \rm -f ./f90split_reordered_raw_subprogram_reference_to_list || : )

   # Generate "ordered" list and "f90split_reordered_list" file. 
   # Restrict only to existing files if asked for via "clean" option switch.

   if [ "$clean" = 'yes' ] ; then
    Modls_list=`cat $mkfil | sed -n -e '/\.mod : /p' | $AWK '{ print $1 ; }' | sort | uniq | sed -e 's/\.mod//' | tr '[\012]' '[\040]' | sed -e 's/ *$//'`
    if [ -n "${Modls_list}" ] ; then
     Mod_Delete_List=''
     for Mod in $Modls_list
      do
        if [ -s "./${Mod}.mod" -a -s "./${Mod}.f90" ] ; then
         Mod_Delete_List="$Mod_Delete_List ./${Mod}.mod"
        fi
      done
     if [ -n "$Mod_Delete_List" ] ; then
      echo '#! /bin/sh' > ./f90split_reordered_modules_cleanup_sh
      echo 'set -x' >> ./f90split_reordered_modules_cleanup_sh
      echo '\ls -ld '"$Mod_Delete_List" >> ./f90split_reordered_modules_cleanup_sh
      echo '/bin/rm -f '"$Mod_Delete_List" >> ./f90split_reordered_modules_cleanup_sh
      chmod u+x ./f90split_reordered_modules_cleanup_sh
     fi
    fi
   #List_Hold=`cat $mkfil | sed -f $f90split_reorder_sed_script_file_1 | sed -n -e 's/\.mod/\.f90/g' -e 's/\.F90/\.f90/g' -e 's/\.[Oo] /\.f90 /g' -e '1,$p' | sed -e 's/ : / /g' | $AWK '{ for (i = 2 ; i <= NF ; ++i ) { xx=$i ; print $1 " " xx ; } ; }' | sort | uniq | tsort | tac | tee f90split_reordered_list | tr '[\012]' '[\040]'`
    List_Hold=`cat $mkfil | sed -f $f90split_reorder_sed_script_file_1 | sed -n -e 's/\.mod/\.f90/g' -e 's/\.F90/\.f90/g' -e 's/\.[Oo] /\.f90 /g' -e '1,$p' | sed -e 's/ : / /g' | $AWK '{ for (i = 2 ; i <= NF ; ++i ) { xx=$i ; print $1 " " xx ; } ; }' | sort | uniq | tsort | tac | tr '[\012]' '[\040]'`
    Cleaned_List_Hold=''
    touch f90split_reordered_list
     
    for Mod in $List_Hold
     do
      if [ -s "$Mod" ] ; then
       Cleaned_List_Hold="$Cleaned_List_Hold $Mod"
       echo "$Mod" >> f90split_reordered_list
      fi
     done
     echo "$Cleaned_List_Hold"
   else
    Ordered_List=`cat $mkfil | sed -f $f90split_reorder_sed_script_file_1 | sed -n -e 's/\.mod/\.f90/g' -e 's/\.F90/\.f90/g' -e 's/\.[Oo] /\.f90 /g' -e '1,$p' | sed -e 's/ : / /g' | $AWK '{ for (i = 2 ; i <= NF ; ++i ) { xx=$i ; print $1 " " xx ; } ; }' | sort | uniq | tsort | tac | tee f90split_reordered_list | tr '[\012]' '[\040]'`
    echo "$Ordered_List"
   fi
  else

   # Generate "ordered" list and restrict only to existing files if asked for via "clean" option switch:

   if [ "$clean" = 'yes' ] ; then
    List_Hold=`cat $mkfil | sed -f $f90split_reorder_sed_script_file_1 | sed -n -e 's/\.mod/\.f90/g' -e 's/\.F90/\.f90/g' -e 's/\.[Oo] /\.f90 /g' -e '1,$p' | sed -e 's/ : / /g' | $AWK '{ for (i = 2 ; i <= NF ; ++i ) { xx=$i ; print $1 " " xx ; } ; }' | sort | uniq | tsort | tac | tr '[\012]' '[\040]'`
    Cleaned_List_Hold=''
    for Mod in $List_Hold
     do
      if [ -s "$Mod" ] ; then
       Cleaned_List_Hold="$Cleaned_List_Hold $Mod"
      fi
     done
     echo "$Cleaned_List_Hold"
   else
    Ordered_List=`cat $mkfil | sed -f $f90split_reorder_sed_script_file_1 | sed -n -e 's/\.mod/\.f90/g' -e 's/\.F90/\.f90/g' -e 's/\.[Oo] /\.f90 /g' -e '1,$p' | sed -e 's/ : / /g' | $AWK '{ for (i = 2 ; i <= NF ; ++i ) { xx=$i ; print $1 " " xx ; } ; }' | sort | uniq | tsort | tac | tr '[\012]' '[\040]'`
    echo "$Ordered_List"
   fi
  fi
  ( \rm -f $f90split_reorder_sed_script_file_1 2>>/dev/null || : ) 2>>/dev/null
fi
