#!/bin/sh

#    Dec 05/06 - F. Majaess (Added support for "source_asis" code)
#    Sep 21/04 - F. Majaess (Revised to target "sv08src" for 
#                            lssub/lsmod in Victoria)
#    Jul 08/99 - F. Majaess (Added "sublib" and fix a bug).
#    Aug 21/96 - F. Majaess (Add "view"/"vwr" switches)
#    Feb 29/96 - F. Majaess (Enforce searching for files with ".*dk" 
#                            extension instead of ".*" when targeting 
#                            lsmod/newdiag2) 
#    Jan 22/95 - F. Majaess (Modify for RCS libraries implementation)
#    Jan 21/95 - E. Chan (Include newdiag directory)
#    Sep 08/93 - F. Majaess (Quote strings in "tr" call)
#    Jun 24/93 - E. Chan (Add extraction of files from ljdiag and lsmod)
#    Dec 15/92 - E. Chan (Add vd option)
#    Dec 11/92 - E. Chan (Translate filenames to lower case before 
#                         executing the "find" command)
#    Dec 02/91 - M. Lazare

#id  getcode - Searches the official CCRN source code file structure
#id            on the server for the specified source code file "fil",
#id            and copies the contents into a file called "fil".src
#id            in the current working directory, where "fil" is the
#id            name of the update deck, fortran program, subroutine,
#id            or function.  

#    AUTHOR  - M. Lazare

#hd  PURPOSE - "getcode" gets a file of source code from the official CCRN 
#hd            source code file structure on the server and copies the 
#hd            contents into a file called "fil".src in the current working
#hd            directory.  Here, "fil" is the name of an update deck, fortran 
#hd            program, subroutine, or function.
#hd 
#hd            It uses the UNIX utility "find" to obtain the code and 
#hd            to copy its contents. The starting search point is specified
#hd            by the user via the required positional parameter as follows:
#hd 
#hd                  lssub    ->    start search at $CCRNSRC/source$OSbin/lssub
#hd                  lspgm    ->    start search at $CCRNSRC/source$OSbin/lspgm
#hd                  lsmod    ->    start search at $CCRNSRC/source$OSbin/lsmod
#hd                  diag4    ->    start search at $CCRNSRC/source$OSbin/diag4 
#hd                  newdiag  ->    start search at /data/ccrn/gen/newdiag
#hd
#hd                  (for:
#hd                   lssub_asis lspgm_asis ...  the search targets the
#hd                  corresponding subdirectory under $CCRNSRC/source_asis)
#hd          
#hd        
#hd            unless a value is specified for "sublib" (see below), in which
#hd            case the search targets "$CCRNSRC/source$OSbin/$lib/.../$sublib" 
#hd            instead.
#hd 
#hd            The official CCRN source code on the server is organized into
#hd            one UNIX file for each update deck, fortran program, subroutine, 
#hd            or function. Fortran programs, subroutines, and functions are 
#hd            compilable code, with "---.f" extensions. If the "vd" option is 
#hd            used, the programs are retrieved in variable dimension format 
#hd            with "---.vd" extensions. Update decks may contain scripts or 
#hd            fortran source code.
#hd 
#hd            The "lnum" switch turns on the generation of identification line 
#hd            numbers (i.e the name of the update deck, program, subroutine, 
#hd            or function followed by a line number). These begin at column
#hd            83. Note that the line numbering is done from the perspective of 
#hd            how update is used to pre-process CCRD/N code. Line numbers
#hd            begin with the DECK update directive. In the case of functions
#hd            and subroutines, this directive is not part of the source code
#hd            unless placed there during model submission job processing. 
#hd            However, this is precisely when these line numbers would be the 
#hd            the most useful, line numbering is adjusted to begin with "2" at
#hd            the SUBROUTINE/FUNCTION statement -- leaving room for the DECK 
#hd            directive. Programs are not handled this way in model submission 
#hd            jobs and, consequently, the numbering begins at "1" at the 
#hd            PROGRAM statement. 
#hd 
#hd            This script is meant to emulate the "GDK" and "XDK" procedures
#hd            under the old NOS/COS technology.

#pr  PARAMETERS:
#pr 
#pr    POSITIONAL
#pr 
#pr        fil  = name of subroutine, function or program (i.e. name of file to
#pr               be found, without the ".f" or ".vd" extensions).
#pr 
#pr        lib  = subdirectory in $CCRNSRC/source$OSbin to start search from (i.e.
#pr               lssub for subroutines and functions, lspgm for programs, 
#pr               lsmod for GCM fortran source code in update form, and 
#pr               diag4 for diagnostic COS jcl).
#pr               ($CCRNSRC/source_asis is targeted if "_asis" suffix is specified)
#pr
#pr      sublib = (optional); subdirectory residing ( not necessarily immediately)
#pr               under $CCRNSRC/source$OSbin/$lib to start search for "fil" from 
#pr               instead of the default $CCRNSRC/source$OSbin/$lib.
#pr               (i.e. if lib=lssub and sublib=gcm6u; target search subdirectory 
#pr                     will be $CCRNSRC/source$OSbin/lssub/.../gcm6u )
#pr 
#pr    SECONDARY
#pr 
#pr         vd  = switch to access variable dimensioned program code
#pr 
#pr       lnum  = switch to enable generation of identification line numbers 
#pr               (useful if making modifications to the source code using update). 
#pr  
#pr      print  = switch to generate hardcopy printout by automatically invoking 
#pr               script "lsh". 
#pr
#pr      view   = switch enabling just viewing the code.
#pr
#pr      vwr    = user's preferred viewer utility (=$PAGER).
#pr               (used only if "view" switch is on)

#ex  EXAMPLES:
#ex 
#ex   1) getcode gaussg lssub
#ex 
#ex      The above example gets the source code for the subroutine "gaussg" by
#ex      doing a find for the "gaussg.f" file, starting from
#ex      $CCRNSRC/source$OSbin/lssub.

#ex   2) getcode gpqtz diag4 lnum
#ex 
#ex      The above example gets the source code for the deck "gpqtz" by executing
#ex      a find for the "gpqtz.dk" file starting at $CCRNSRC/source$OSbin/diag4. 
#ex      The source code is stamped with identification line numbers beginning 
#ex      at column 83. 

#ex   3) getcode xit lssub view vwr=vi
#ex 
#ex      The above example finds "xit.f" code by searching from 
#ex      $CCRNSRC/source$OSbin/lssub and then invoking "vi" to view the
#ex      found file.

#ex   4) getcode rstrt6u lsmod gcm6u lnum view vwr=vi
#ex
#ex      The above example gets the source code for the deck "rstrt6u" by executing
#ex      a find for the "rstrt6u.dk" file starting at 
#ex      $CCRNSRC/source$OSbin/lsmod/.../gcm6u.
#ex      The source code is stamped with identification line numbers beginning at
#ex      column 83.  Then the copy is viewed by "vi" before being deleted upon
#ex      exiting.


#ex   5) getcode progx lspgm_asis 
#ex
#ex      The above example results in searching for "progx" in
#ex        $CCRNSRC/source_asis/lspgm_asis
#ex      and copying it upon successful "find" into "progx.src..." 
#ex      local filename.

#  * Set variable to the version of "awk" to be used. The original version
#  * of 'awk' does not have the capabilities required for this script
#  * and 'nawk' must be used instead. Fortunately, it seems that on most
#  * systems, 'awk' is actually 'nawk'. On systems where this is not the
#  * case, the variable AWK must be set to nawk.

AWK=${AWK:-awk}

#  * Obtain the file names and any specified option.

arg_list=$@
for arg in $arg_list
do
  case $arg in
      -*) set $arg                                  ;;
      vd) vd=yes                                    ;;
    lnum) lnum=yes                                  ;;
    view) view=yes                                  ;;
    view=*|vwr=*) eval $arg                         ;;
   print) print=yes                                 ;;
       *) tmp1=${fil:+$arg} ; tmp2=${lib:+$arg}        ; 
          sublib=${sublib:=$tmp2} ; lib=${lib:=$tmp1}  ; 
          fil=${fil:=$arg}
  esac
done 

#  * Exit if no value set for lib.

if [ -z "$lib" ] ; then
  echo "Getcode: Must specify both the file and the library (in that order)"
  exit 1
fi

vwr=${vwr:="$PAGER"}
view=${view:='no'}

lib=`echo $lib | tr '[A-Z]' '[a-z]'`
fil=`echo $fil | tr '[A-Z]' '[a-z]'`
touch $fil.src$$ > /dev/null 2> /dev/null
if [ ! -f "$fil.src$$" ] ; then
  if [ "$lnum" != 'yes' -a "$print" != 'yes' -a "$view" = 'yes' ] ; then
    echo "Note: $vwr will be invoked from $HOME/tmp instead of current subdirectory"
    cd $HOME/tmp
  else
    echo "Sorry, you are not permitted to write into current subdirectory!"
    echo "       please re-invoke the script from a writable subdirectory!"
    exit 2
  fi
else
 \rm -f $fil.src$$
fi
if [ "$SITE_ID" = 'Victoria' -a \( "$lib" = 'lsmod' -o "$lib" = 'lssub' \) -a -d "$CCRNSRC/sv08src/." ] ; then
  if [ -n "$OSbin" -a ! -d "$CCRNSRC/sv08src/source${OSbin}/." ] ; then
   unset OSbin
  fi
  CCRNSRC="$CCRNSRC/sv08src"
fi
ASIS=`echo $lib | sed -e 's/^.*_asis *$/yes/g'`

if [ "$lib" = 'lspgm' -o "$lib" = 'lspgm_asis' ] ; then

  #
  #  * Case 1: Programs.
  #

  #  * Set target search directory.

  if [ "$ASIS" = 'yes' ] ; then
   if [ -n "$sublib" ] ; then
     libpath=`find -L $CCRNSRC/source_asis/${lib}/. -name $sublib -print -depth 2>/dev/null `
     if [ -z "$libpath" -o \( -n "$libpath" -a ! -d "$libpath" \) ] ; then
       echo "Getcode: unable to find --> $sublib <-- subdirectory under $CCRNSRC/source_asis/$lib !"
       exit 1
     fi
   else
     libpath="$CCRNSRC/source_asis/$lib"
   fi
  else
   if [ -n "$sublib" ] ; then
     libpath=`find -L $CCRNSRC/source${OSbin}/${lib}/. -name $sublib -print -depth 2>/dev/null `
     if [ -z "$libpath" -o \( -n "$libpath" -a ! -d "$libpath" \) ] ; then
       echo "Getcode: unable to find --> $sublib <-- subdirectory under $CCRNSRC/source${OSbin}/$lib !"
       exit 1
     fi
   else
     # libpath="$CCRNSRC/source${OSbin}/$lib"
     libpath="$CCRNSRC/source${OSbin}/$lib/.f${OSbin}"
     if [ ! -d "$CCRNSRC/source${OSbin}/$lib/.f${OSbin}" -a "${OSbin}" = '_linux64' ] ; then
      libpath=`echo $libpath | sed -e 's/_linux64 *$/_linux/'`
     fi
   fi
  fi

  #  * Variable dimenion code is stored in "---.vd" files.
  
  if [ "$vd" = 'yes' ] ; then
    find -L ${libpath}/. -name $fil.vd -exec cp {} $fil.src$$ 2>/dev/null \;
  else
    find -L ${libpath}/. -name $fil.f  -exec cp {} $fil.src$$ 2>/dev/null \;
  fi

elif [ "$lib" = 'lssub' -o "$lib" = 'lssub_asis' ] ; then

  #
  #  * Case 2: Subroutines or functions.
  #

  #  * Set target search directory.

  if [ "$ASIS" = 'yes' ] ; then
   if [ -n "$sublib" ] ; then
     libpath=`find -L $CCRNSRC/source_asis/${lib}/. -name $sublib -print -depth 2>/dev/null `
     if [ -z "$libpath" -o \( -n "$libpath" -a ! -d "$libpath" \) ] ; then
       echo "Getcode: unable to find --> $sublib <-- subdirectory under $CCRNSRC/source_asis/$lib !"
       exit 2
     fi
   else
     libpath="$CCRNSRC/source_asis/$lib"
   fi
  else
   if [ -n "$sublib" ] ; then
     libpath=`find -L $CCRNSRC/source${OSbin}/${lib}/. -name $sublib -print -depth 2>/dev/null `
     if [ -z "$libpath" -o \( -n "$libpath" -a ! -d "$libpath" \) ] ; then
       echo "Getcode: unable to find --> $sublib <-- subdirectory under $CCRNSRC/source${OSbin}/$lib !"
       exit 2
     fi
   else
     libpath="$CCRNSRC/source${OSbin}/$lib"
   fi
  fi

  #  * Fortran code is stored in "---.f" files.

  find -L ${libpath}/. -name $fil.f -exec cp {} $fil.src$$ 2>/dev/null \;

else

  #
  #  * Case 3: JCL decks or Fortran source code in GCM model decks. 
  #

  fil=`expr $fil : '\([^.]*\).*'`

  #  * JCL source code is stored in "---.dk" or "---.cdk" files.

  if [ "$lib" = newdiag ] ; then
    lib=newdiag2
  fi

  #  * Set target search directory.

  if [ "$ASIS" = 'yes' ] ; then
   if [ -n "$sublib" ] ; then
     libpath=`find -L $CCRNSRC/source_asis/${lib}/. -name $sublib -print -depth 2>/dev/null `
     if [ -z "$libpath" -o \( -n "$libpath" -a ! -d "$libpath" \) ] ; then
       echo "Getcode: unable to find --> $sublib <-- subdirectory under $CCRNSRC/source_asis/$lib !"
       exit 1
     fi
   else
     libpath="$CCRNSRC/source_asis/$lib"
   fi
  else
   if [ -n "$sublib" ] ; then
     libpath=`find -L $CCRNSRC/source${OSbin}/${lib}/. -name $sublib -print -depth 2>/dev/null `
     if [ -z "$libpath" -o \( -n "$libpath" -a ! -d "$libpath" \) ] ; then
       echo "Getcode: unable to find --> $sublib <-- subdirectory under $CCRNSRC/source${OSbin}/$lib !"
       exit 1
     fi
   else
     libpath="$CCRNSRC/source${OSbin}/$lib"
   fi
  fi

  find -L ${libpath}/. -name "$fil.*dk" -exec cp {} $fil.src$$ 2>/dev/null \;

fi

#  * Verify that the file has indeed been found and copied. Print out
#  * error message and exit accordingly.

if [ ! -f "$fil.src$$" ] ; then

  echo "routine $fil cannot be found in $lib"
  exit 2
else
  chmod u+w $fil.src$$
fi

#  * Add identification line numbers to the files of source code, if requested. 

if [ "$lnum" = 'yes' -o "$print" = 'yes' ] ; then
  
  $AWK '
      #  Extract identification from the first line of the source file which
      #  must begin with a DECK, PROGRAM, or SUBROUTINE declaration.

      $1 ~ /^[*%][^ ]*DECK/ || $1 ~ /^#[^ ]*deck/ || $1 ~ /[Pp][Rr][Oo][Gg][Rr][Aa][Mm]/ {
        if ( linenum == 0 ) {
          id = $2
          linenum = 1
        } 
      }
      $1 ~ /[Ss][Uu][Bb][Rr][Oo][Uu][Tt][Ii][Nn][Ee]/ || $1 ~ /[Ff][Uu][Nn][Cc][Tt][Ii][Oo][Nn]/ || $1 ~ /[Mm][Oo][Dd][Uu][Ll][Ee]/ {
        id = $2
        sub (/\(.*$/,"",id)
        linenum = 2
      }
      $2 ~ /[Ff][Uu][Nn][Cc][Tt][Ii][Oo][Nn]/ && $0 !~ /^[Cc#*]/ {
        id = $3
        sub (/\(.*$/,"",id)
        linenum = 2
      }

      #  Generate the identification stamp and print it out at the end
      #  of each line.

      {
        stamp = id "." linenum
        sub (/ *$/,"",$0)
	printf ( "%-82s%s%-15s\n",$0," ",stamp)
        linenum = ++linenum 
      } 
  '                                        $fil.src$$ > tmpfile$$
   
  mv tmpfile$$ $fil.src$$

fi
if [ "$view" = 'yes' ] ; then
  $vwr $fil.src$$
fi

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

  lsh $fil.src$$
  echo 'Remove local file containing source code (default=no)? '\\c
  read ans
  if [ "$ans" = 'y' -o "$ans" = 'yes' ] ; then
    rm $fil.src$$
  fi

fi
if [ "$view" = 'yes' -a -s $fil.src$$ ] ; then
 rm $fil.src$$
fi

exit
