#!/bin/sh

#  * ---------------------------- Version 1.2 ----------------------------------
#  * Mar 31/15 - F. Majaess (Revised in support of parameter defined comdeck name 
#  *                         to be in-lined)
#  * Jul 17/13 - F. Majaess (Extend functionality in support of tree structured
#  *                         "MODULES" subdirectory)
#  * Jun 19/13 - F. Majaess (Revised in support of "MODULES" reserved 
#  *                         subdirectory name for "module" subprograms.)
#  * Mar 06/12 - F. Majaess (Added support for "USRXBIN")
#  * Nov 04/05 - F. Majaess (Check and abort if lines operated on are targeted 
#  *                         more than once by the update directives)
#  * Oct 02/03 - F. Majaess (Scan for blank space(s) right after 'DEF,' in 
#  *                         "IF" conditional statement and abort upon matching 
#  *                         occurences. Such syntax lead to failed processing 
#  *                         of conditional test)
#  * Aug 29/00 - F. Majaess (Revised to issue an error message with bad exit
#                            status value on empty output)
#  * Jun 03/99 - F. Majaess (Revised to test treating "update_dir" and, if 
#  *                         applicable, "TSTRDIR" and user's "extra_lib" as tree 
#  *                         structured subdirectories in scanning to expand dk/cdk).
#  * May 21/99 - F. Majaess (Limit "sed_limit" setting to 4000 )
#  * Oct 07/98 - F. Majaess (Revised to allow *ODIR lines)
#  * Jun 09/97 - F. Majaess (Revised to allow *PDIR/*VDIR lines,
#  *                         protect against skipping "compile" directives,
#  *                         ensure no collision occurs between [com]decks 
#  *                         sharing the same initial character sequence in 
#  *                         the names)
#  * Dec 11/96 - F. Majaess (copy files individually instead of all at once
#  *                         since "cp" aborts on the 1st unsatisfied reference)
#  * Sep 17/96 - F. Majaess (ensure system default "rm" is used)
#  * Jan 31/96 - F. Majaess (Implement allowing code testing option)
#  * Dec 04/95 - F. Majaess (ensure user have write permission on copied decks)
#  * Apr 13/95 - F. Majaess (Make sure all referenced decks are defined)
#  * Mar 27/95 - E. Chan (Add new parameter "extra_lib")
#  * May 11/94 - E. Chan (Support both upper and lower case directives)
#  * Jan 19/93 - E. Chan (Strip out lines containing 'end_of_data' when in-
#  *                      lining comdecks. Also add recognition of "#" as a
#  *                      leading character to DECK and COMDECK directives
#  *                      and treat ". comdeck.cdk" as "CALL COMDECK".
#  *                      This last change is made everywhere except in the
#  *                      user defined deck section because, "pure" Unix 
#  *                      decks created by the user will not require update.)
#  * ---------------------------- Version 1.1 ----------------------------------
#  * Aug 05/93 - E. Chan (Ignore empty input to I directive and streamline
#  *                      sed_script2 if sed_limit is reached)
#  * Jul 29/93 - E. Chan (Add "cdk" and "noexpd" options and modify
#  *                      sed_limit to 9,600 characters)
#  * ---------------------------- Version 1.0 ----------------------------------
#  * May 21/93 - E. Chan

#id update   - extracts source code from files in a given directory
#id            and modifies them according to specified directives

#   AUTHOR  - E. Chan

#hd PURPOSE - update extracts source code contained in a set of files 
#hd           located in a specified directory. Each file in the directory
#hd           should contain a well defined piece of source code -- 
#hd           e.g. a COS jcl deck or a Fortran subroutine. Input directives
#hd           supplied from an input file to 'update' are used to extract
#hd           and/or modify source code from one or more of these files. 
#hd           The resulting code is placed either in output files with the
#hd           same names as the original files or in a single file in the
#hd           order that they are referred to in the input file.

#pr PARAMETERS:
#pr
#pr  POSITIONAL
#pr
#pr       input = name of file containing input directives
#pr
#pr         lib = name of update library subdirectory containing the source
#pr               code files in $CCRNSRC/source$OSbin (must be a valid update 
#pr               library name such as 'diag3', 'lsmod', ... )
#pr               NOTE: Contents of "MODULES" tree structured subdirectory, 
#pr                     if present under "lib", get checked as well as "lib"
#pr                     for the source code files. 
#pr 
#pr      output = name of output file where all processed decks are to 
#pr               placed (if not specified, decks are put into separate 
#pr               files with the same name as the decks followed by a ".dk"
#pr               extension) -- note that common decks are not included
#pr               unless the "cdk" switch is used
#pr
#pr  PRIMARY
#pr     
#pr  extra_lb2 = absolute path to extra library which is searched for decks
#pr              and common decks ahead of "extra_lib" and "lib"
#pr              (default: not defined)
#pr     
#pr  extra_lib = absolute path to extra library which is searched for decks
#pr              and common decks ahead of the named update library specified
#pr              by the positional parameter "lib" (default: not defined)
#pr 
#pr  SECONDARY
#pr 
#pr         def = switch to turn on processing of conditional definitions
#pr   
#pr      usrlib = switch to allow defining the "lib" parameter above
#pr               as the full path to a user created update library directory
#pr
#pr        list = switch to enable printing of identification line numbers 
#pr   
#pr         cdk = switch to enable placing processed common decks on output 
#pr               in addition to regular decks
#pr 
#pr      noexpd = switch to prevent expansion of all embedded CALL directives
  
#ex EXAMPLE:
#ex   
#ex     update in newdiag2 out
#ex
#ex     The above example generates the file "out" from "newdiag2" according
#ex     to directives specified in input file "in".     

#  * Obtain the name of the submission file, the update library, and any 
#  * specified option.
# set -x
for arg in $@
do
  case $arg in
         -*) set $arg                                     ;;
        *=*) eval $arg                                    ;;
        def) def=yes                                      ;;
     usrlib) usrlib=yes                                   ;;
       list) list=yes                                     ;;
        cdk) cdk=yes                                      ;;
     noexpd) noexpd=yes                                   ;;
          *) tmp2=${lib:+$arg}   ; output=${output:=$tmp2} ;
             tmp1=${input:+$arg} ; lib=${lib:=$tmp1}       ;
             input=${input:=$arg}
  esac
done

#  *************** SYSTEM DEPENDENT DEFINITIONS *************************

#  * Set variable to the location of the main update library directory. 
#  * This is system dependent (although $UPDTLIB may be redefined in
#  * the future). 

if [ "$usrlib" = 'yes' ] ; then
  update_dir=$lib
else
  update_dir=$CCRNSRC/source${OSbin}/$lib
fi

#  * 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}

#  * A limitation in sed (undocumented) prevents the appending of more
#  * than about 9700 - 10,100 characters total inside sets of braces in a 
#  * sed script (the actual number seems to be machine dependent). 
#  * If the input directive file hits this limit, an alternate
#  * method for doing the appending of lines must be used.  The variable 
#  * sed_limit must be set to below the current maximum number of
#  * characters allowed.

#  * The limitation inside sets of braces in a sed script is found
#  * to be:
#  *        ~ 4000 characters on IBM running AIX 
#  * and    ~ 40 lines on the NEC SX4 running Super-UX. 
#  * Therefore:

# sed_limit=9600
 sed_limit=4000

#  **********************************************************************

#  * Check if the input directive file exists and the update library 
#  * directory is specified.

if [ ! -f "$input" ] ; then
  echo "Abort in 'update': input file $input does not exist."
  exit 1
elif [ ! -d "$update_dir/." ] ; then
  echo "Abort in 'update': update directory $update_dir does not exist."
  exit 2
fi 
#  * Extract name and path information from the input file and also from 
#  * the output file, if it is specified.

input_path=`expr $input : '\(.*\)/'`
input_name=`expr //$input : '.*/\(.*\)'`

if [ -n "$output" ] ; then
  output_path=`expr $output : '\(.*\)/'`
  output_name=`expr //$output : '.*/\(.*\)'`
fi

#  * Setup to use "USRXBIN" if set.

. usrxbin_split

#  * Define parameters containing path information. The default directory
#  * is set to the current directory.

cdpath=`pwd`
input_path=${input_path:=$cdpath}
output_path=${output_path:=$cdpath}
export list

#  * Ensure no blank space(s) follow right after 'DEF,' in "IF"
#  * conditional statements in the update directives file...

(\rm -f Updt_Illegal || : )
sed -n -e '/^%[Ii][Ff] .*[DdEeFf] *, /p' $input_path/$input_name > Updt_Illegal
if [ -s "Updt_Illegal" ] ; then
 echo "\nUpdate: ***ERROR***-> Detected, in the specified update directives, blank space(s) right after 'DEF,' conditional test:\n"
 cat Updt_Illegal
 echo "\nUpdate: ***ERROR***-> Please correct detected syntax errors ..."
 exit 1 
fi

# Define "Updt_xpndme" function to aid in checking for duplicate
# directives later on.

Updt_xpndme () {
 Argmnt="$1"
 Argmnt_strng=`echo $Argmnt | sed -e 's/^ *$//g'`
 if [ ! -z "$Argmnt_strng" ] ; then
  Prfx=`echo $Argmnt | $AWK -F '.' '{print $1}'`
  Rng=`echo $Argmnt | $AWK -F '.' '{print $2}'`
  if [ -n "$Rng" ] ; then
   Lwr_bnd=`echo $Rng | $AWK -F ',' '{print $1}'`
   Upr_bnd=`echo $Rng | $AWK -F ',' '{print $2}'`
   if [ -n "$Upr_bnd" -a "$Upr_bnd" != "$Lwr_bnd" ] ; then
    cntr="$Lwr_bnd"
    while [ $cntr -le $Upr_bnd ] 
     do
      echo "${Prfx}.${cntr}"
      cntr=`expr $cntr + 1`
     done 
   else
     echo "$Argmnt"
   fi
  else
   echo "$Argmnt"
  fi
 fi
 }

export Updt_xpndme

#  * Move into a temporary directory to execute the script.

Ustamp="${HOSTID}_"`date +%Y%j%H%M%S`
if [ "$SITE_ID" = 'DrvlSC' ] ; then
 mkdir $CCRNTMP/tmp_update_$$_$Ustamp
 cd $CCRNTMP/tmp_update_$$_$Ustamp
else
 mkdir $HOME/tmp/tmp_update_$$_$Ustamp
 cd $HOME/tmp/tmp_update_$$_$Ustamp
fi
 
#  * Place list of comdecks and decks to be modified and/or extracted in
#  * file "decks.list" and compile a list of conditional definition 
#  * parameters (i.e. from lines beginning with *DF or %DF) in file 
#  * "condef_parameters".
#  *
#  * Also make first pass at changing update directives into a sed script
#  * to be used for applying the updates. This includes:
#  *
#  *   1) changing the leading character in front of CALL, IF, and ENDIF 
#  *      directives to #+#+# to avoid conflicts later on with the standard 
#  *      leading characters (these directives require special handling)
#  *   2) deleting any DECK and/or COMDECK definitions since these are 
#  *      handled separately in a following section.
#  *   3) doubling all backslashes in lines containing updates to code; also
#  *      adding a backslash to the end of all lines except those that begin
#  *      with a standard leading character (lc) and those just before a
#  *      line beginning with a standard lc. (this is done for all lines 
#  *      to be incorporated as changes to the original source code -- the
#  *      extra backslashes are needed because these lines are to processed 
#  *      later by the append/change sed commands)
#  *   4) translating the *D directive into an internal *K directive when
#  *      only deletion of lines is requested (*D will be interpreted as
#  *      deletion followed by replacement with other lines of code)
#  *   5) stripping out I directives that aren't followed by insertion lines.

#/^[%*]/{
#/^[%*][CcIiDd] /!y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
#}

sed -n '

h
s/^[*%][^ OoPpVv]\{1,\}[FfLlDd] //
s/^[*%]\///
/^[*%][^ OoPpVv]* \{1,\}\([^ .]*\).*/{
s//\1.\*dk/
/,.*\.\*dk$/s/,/.\*dk\
/g
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
w decks.list
}
g
s/^[%*]c /%C /
s/^[%*]i /%I /
s/^[%*]d /%D /
s/^[%*]id /%ID /
s/^[%*]if /%IF /
s/^[%*]def /%DEF /
s/^[%*]call /%CALL /
s/^[%*]deck /%DECK /
s/^[%*]comdeck /%COMDECK /

/^[*%]DF \{1,\}\([^ ]*\).*/{
s//\1/w condef_parameters
d
}

/^[*%][IEC][^ ]*[FL] \{0,1\}/s/^[*%]/#+#+#/

s/^[*%][^ ]*DECK/@+@+@/
/@+@+@/,/^[*%][^OoPpVv]/{
s/^[*%][OoPpVv]/eliminate/
/^[*%]/!d
}


s/\\/\\\\/g
s/^\([%*][OoPpVv]\)/\\\1/
s/\\/\\/g


$s/^[*%]D/\*K/

$!{

N

/\n[*%][IEC][^ ]*[FL] \{0,1\}/s/\n[*%]/\
#+#+#/

/^[*%]I .*\n[*%][^OoPpVv]/s//\
\*/

/^[*%]D .*\n[*%][^OoPpVv]/s/^[*%]D/\*K/

/^[^*%]/{
s/\n\([*%][OoPpVv]\)/\\\
\1/
s/\n\([^*%]\)/\\\
\1/
s/\n$/\\\
/
}

}

P
D

' $input_path/$input_name > sed_script1

cat sed_script1 | sed -n -e '/^[%*]/p' | sed -n -e '/^.*\./p' | sed -e 's/ *$//g' | sed -e 's/^.* //g' | sort | sed -e 's/^/Updt_xpndme /' > sed_script1_hold0
if [ -s "./sed_script1_hold0" ] ; then
 . ./sed_script1_hold0 | sort > sed_script1_hold1
fi
(\rm -f sed_script1_hold0 || : ) 

if [ -s "./sed_script1_hold1" ] ; then
 cat sed_script1_hold1 | uniq > sed_script1_hold2
 duplcts='no'
 diff sed_script1_hold1 sed_script1_hold2 >> /dev/null 2>>/dev/null && unset duplcts || duplcts='yes'
 if [ "$duplcts" = 'yes' ] ; then
  echo "\nupdate: Detected update directives affecting same targeted lines of:\n"
  diff -w sed_script1_hold1 sed_script1_hold2 | sed -n -e 's/^[<>] / --> /p'
  cd ..
  \rm -r tmp_update_$$_$Ustamp
  echo "\nupdate: Aborts due to operations targeting same lines!"
  exit 1
 fi
 (\rm -f sed_script1_hold2 || : )
fi
(\rm -f sed_script1_hold1 || : )

#  * Copy files of source code to be modified from the update library 
#  * directory using the list compiled in the file "decks.list". Since
#  * there may be multiple references to the same files in "decks.list",
#  * the list is processed with awk to remove the redundancy. 
 
decks_list=`awk '
                {
                  counter[$0] = ++counter[$0]
                  if ( counter[$0] == 1 ) print $0
                }'                                   decks.list | tr '\\012' '\\040'`
full_decks_list=`echo -n $decks_list | tr '\\012' '\\040'`
for file in $decks_list
 do
  if [ -d "$update_dir/MODULES/." ] ; then
#  cp $update_dir/MODULES/$file . 2>/dev/null
#  find -L $update_dir/MODULES -name "$file" -exec cp {} . \; -exec chmod u+w $file \; 2> /dev/null
   find -L $update_dir/MODULES -name "$file" -exec cp {} . \; 
   chmod u+w $file 2>/dev/null
  fi
# find -L $update_dir -name "$file" -exec cp {} . \; -exec chmod u+w $file \; 2> /dev/null
  cp $update_dir/$file . 2>/dev/null 
  chmod u+w $file 2>/dev/null
  if [ -n "$USRXBIN2" -a -d "$USRXBIN2/." ] ; then
#  find -L $USRXBIN2 -name "$file" -exec cp {} . \; -exec chmod u+w $file \; 2> /dev/null
   cp $USRXBIN2/$file . 2>/dev/null 
   chmod u+w $file 2>/dev/null
  fi
  if [ -n "$USRXBIN1" -a -d "$USRXBIN1/." ] ; then
#  find -L $USRXBIN1 -name "$file" -exec cp {} . \; -exec chmod u+w $file \; 2> /dev/null
   cp $USRXBIN1/$file . 2>/dev/null 
   chmod u+w $file 2>/dev/null
  fi
  if [ "$USRTSTR" = 'true' -a -n "$TSTRDIR" -a -d "$TSTRDIR/." ] ; then
#  find -L $TSTRDIR -name "$file" -exec cp {} . \; -exec chmod u+w $file \; 2> /dev/null
   cp $TSTRDIR/$file . 2>/dev/null 
   chmod u+w $file 2>/dev/null
  fi
  if [ -n "$extra_lib" -a -d "$extra_lib/." ] ; then
#  find -L $extra_lib -name "$file" -exec cp {} . \; -exec chmod u+w $file \; 2> /dev/null
   cp $extra_lib/$file . 2>/dev/null 
   chmod u+w $file 2>/dev/null
  fi
  if [ -n "$extra_lb2" -a -d "$extra_lb2/." ] ; then
#  find -L $extra_lb2 -name "$file" -exec cp {} . \; -exec chmod u+w $file \; 2> /dev/null
   cp $extra_lb2/$file . 2>/dev/null 
   chmod u+w $file 2>/dev/null
  fi
 done
if [ "$SITE_ID" = 'DrvlSC' ] ; then
 cd $CCRNTMP/tmp_update_$$_$Ustamp
else
 cd $HOME/tmp/tmp_update_$$_$Ustamp
fi
chmod u+w * 2>/dev/null

#  * Extract user defined decks from the input file. Decks with the same
#  * name as those copied over from the update library directory replace
#  * the copied versions.

$AWK '
     
     #  Turn off print flag if a standard leading character is encountered
     #  unless it is "*PDIR/*VDIR/*ODIR" or a CALL, IF, or ENDIF directive.
     #  Note: "*PDIR/*VDIR/*ODIR" arguments are left unchanged if the
     #        "D" second character in "*[PVO]DIR" is in lower case; otherwise
     #        all turned into upper case (ie. similar to "[*%]ID/[*%]id" 
     #        handling). 
     #        The conversion is done in "gcmsub.dk".
    
     $0 ~ /^[*%][^EeCcOoPpVv]/ && $0 !~ /^[*%][Ii][Ff]/ {
       flag = "false"
     }

     #  ensure COMPILE statements are bypassed as well.

     $0 ~ /^[*%][Cc][ ]/ || $0 ~ /^[*%][Cc][Oo][Mm]/ {
       flag = "false"
     }

     #  Extract the filename from the DECK or COMDECK definition and add
     #  the ".dk" or ".cdk" extension. Also remove the ",NOPROP" in the 
     #  filename, if it exists. Finally, set the print flag.
      
     /^[*%][^ PpVv]*[Dd][Ee][Cc][Kk]/ {
       close(filename)
       if ( $1 ~ /^[*%][Dd][Ee][Cc][Kk]/ ) {
         ext = ".dk"
       }
       else {
         ext = ".cdk"
       }
       sub (/,.*$/,"",$2)
       print $2 | "tr [A-Z] [a-z] > filenames"
       close("tr [A-Z] [a-z] > filenames")
       close("filenames")
       getline filename < "filenames"
       filename = filename ext
       flag = "true"
     }
     
     #  Print lines associated with the deck to the file of the same name.
     
     {
       if ( flag == "true" ) print $0 > filename
     }
'                                                 $input_path/$input_name 

#  * Make sure all the files needed for the updates modifications are
#  * available.

unset haltit
for file in $full_decks_list 
  do
  if [ "$file" != '-n' -a "$file" != ' ' ] ; then
   unset filex
#  filex=`expr $file : '\(.*\)\.\*dk'`
   filex=` echo $file | sed -n -e 's/\.dk//p' -e 's/\.cdk//p' -e 's/\.\*dk//p'`
   if [ -n "$filex" -a  ! -s "${filex}.dk" -a ! -s "${filex}.cdk" ] ; then
     echo "update: File for updating $filex deck is not available!"
#    echo "update: File for updating $file is not available!"
     haltit='haltit'
   fi
  fi
  done

if [ "$haltit" = 'haltit' ] ; then
 cd ..
 \rm -r tmp_update_$$_$Ustamp
 echo "update: aborts because of missing files or wrong directives"
 exit 1
fi

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

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

  cat <<'..endcat' > awk_script
       $1 ~ /^[*%][^ PpVv]*[Dd][Ee][Cc][Kk]/ {
         id = $2
         linenum = 1 
       }
       {
         stamp = id "." linenum
         # printf ( "%-82s%-15s\n",$0,stamp)
         printf ( "%-82s%s%-15s\n",$0," ",stamp)
         linenum = ++linenum 
       } 
..endcat

  file_list="*.dk *.cdk"
  for file in $file_list
  do
   if [ "$file" != '*.dk' -a "$file" != '*.cdk' ] ; then
    $AWK -f awk_script $file > tmpfile 2>/dev/null
    mv tmpfile $file
   fi
  done

fi

#  * Finish transforming update directives into a sed script to be used in 
#  * in making modifications to the extracted code. This includes:
#  *
#  *   1) replacing [*%]D directives with the sed "change" command
#  *   2) replacing [*%]K directives with the sed "delete" command
#  *   3) replacing [*%]I directives with the sed "append" command
#  *   4) removing all remaining directives since these are no longer
#  *      supported
#  *   5) changing "#+#+#" back to a standard lc after all modifications 
#  *      have been applied in preparation for the expansion of comdecks 
#  *      and conditional definitions.
#  *   6) protect leading blanks in modification lines with a backslash
#  *
#  * Note that each modification is addressed using the name of the deck to
#  * which the changes are targeted. This allows modifications to the same
#  * deck to be in any order in the input directives file. Modifications to 
#  * the same deck may even be interleaved with update directives to 
#  * other decks. 

cat <<'endcat' > sed_script

s/^[*%]D  *\([^.]*\)\.\([0-9]*\)\(,*[0-9]*\).*$/\/^[*%#][^ PpVv]*[Dd][Ee][Cc][Kk] \1[ \.]\/,\${\
\2\3c\\/

s/^\*K  *\([^.]*\)\.\([0-9]*\)\(,*[0-9]*\).*$/\/^[*%#][^ PpVv]*[Dd][Ee][Cc][Kk] \1[ \.]\/,\${\
\2\3d\
}/

s/^[*%]I  *\([^.]*\)\.\([0-9]*\).*$/\/^[*%#][^ PpVv]*[Dd][Ee][Cc][Kk] \1[ \.]\/,\${\
\2a\\/

endcat

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

  cat <<'..endcat' >> sed_script
  /^[*%][^OoPpVv]/{
  /^[*%]ID/!d
  }
..endcat

else
 
  cat <<'..endcat' >> sed_script
  /^[*%][^OoPpVv]/d
..endcat

fi

cat <<'endcat' >> sed_script

/^$/s// /


/^[^/*%]/{
/[^\\]$/a\
\}
}

/^[*%][OoPpVv]/{
s/^/\\/
}

s/^#+#+#/\*/

s/^ /\\ /

endcat

sed -f sed_script sed_script1 > sed_script2

#  * Apply modifications to source code, if there are any.

if [ -s sed_script2 ] ; then

  #  * Due to a limitation (undocumented) in sed where a memory fault occurs
  #  * if the number of append/change characters exceed about $sed_limit, an
  #  * alternate method must be used to handle these situations.  This may be
  #  * done by modifying the sed script to split out the append/change lines
  #  * to uniquely named temporary files and read them back in using the sed 
  #  * "read" command (an unlimited number of files may read in using sed, but
  #  * only a maximum of 10 files may be opened for writing). 
  #  *
  #  * This method is used only if the number of append/change lines in the 
  #  * modifications exceed $sed_limit. If the "list" option is enabled,
  #  * the expected number of characters must be estimated by multiplying
  #  * the number of lines in the sed script by the number of characters
  #  * per line (less than ~100) after the identification line numbers are 
  #  * attached.

  if [ "$list" = 'yes' ] ; then
    lines=`cat sed_script2 | wc -l`
    numchar=`expr $lines \* 100`
  else
    numchar=`cat sed_script2 | wc -c`
  fi

  if [ "$numchar" -gt "$sed_limit" ] ; then
  
    $AWK '
          BEGIN {
            "echo $list" | getline list
            id = "NO ID"
            linenum = 1
          }

          {

          if ( $0 ~ /\[Dd\]\[Ee\]\[Cc\]\[Kk\].*{$/ ) {
            
            #
            # If a deck definition line is encountered then prepare to extract 
            # the lines following it into a temporary file with a unique name. 
            # This file may be used later by sed to update the official version
            # of the deck. The sed_script used to do the updating for that deck
            # is also created with a unique name. 
            #
           
            # First, extract the name of the deck. 
           
            echo help
            close (filename)
            deck = $0
            sub (/.*\[Dd\]\[Ee\]\[Cc\]\[Kk\] */,"",deck)
            sub (/\[ \.\]/,"",deck)
            sub (/\/.*$/,"",deck)
            print deck | "tr [A-Z] [a-z] > filenames"
            close("tr [A-Z] [a-z] > filenames")
            close("filenames")
            getline deck < "filenames"

            # Create unique sed_script for the deck by copying the deck 
            # definition line into it, if the script doesnt already exist.

            close (sed_script)
            sed_script = deck "_sed_script"
            if ( system ( "test -f " sed_script ) != 0 ) {
              script_list[++i] = sed_script
              print $0 > sed_script
            }

            # Construct the name of the temporary file by concatenating the
            # deck name and part of the sed command line.
           
            getline
            sub (/\\ *$/,"")
            filename = deck $0
           
            # Replace the sed "append" and "change" command lines to sed 
            # "read" and "delete" commands. Write the edited lines out
            # to the appropriate sed_script.
            
            sub (/a$/,"r " filename)
            line = $0
            sub (/,[0-9]*/,"",line)
            if ( sub (/c$/,"r " filename,line) ) print line >> sed_script
            sub (/c$/,"d")
            print $0 >> sed_script

          }
          else if ( $1 ~ /^[*%]ID/ ) {

            # Reset the identification line number.

            id = $2
            linenum = 1

          }
          else if ( $0 !~ /^}/ ) {
           
            #
            # Write out modifications to the temporary file.
            #

            # First, undo changes regarding backslashes done in previous pass
            # through sed in order to prepare lines for inclusion with the
            # sed "read" command.
           
            sub (/^\\/,"")
            sub (/\\ *$/,"")
            gsub (/\\\\/,"\\")
            if ( list == "yes" ) {
              stamp = id "." linenum
              # printf ( "%-82s%-15s\n",$0,stamp) > filename
              printf ( "%-82s%s%-15s\n",$0," ",stamp) > filename
              linenum = ++linenum 
            }
            else {
              print $0 > filename
            }

          }

          }

          END {
            for ( j=1 ; j<=i ; ++j ) {
              print "}" >> script_list[j]
              close (script_list[j])
            }
          }'                                  sed_script2

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

    $AWK '{
            if ( $1 ~ /^[*%]ID/ ) {
              id=$2
              linenum = 1 
          } 
            else if ( flag == "true" ) {
              if ( $0 ~ /\\$/ ) {
               backslash = "\\"
              }
              else {
                backslash = "  "
              }
              stamp = id "." linenum backslash
              # printf ( "%-82s%15s\n",$0,stamp)
              printf ( "%-82s%s%15s\n",$0," ",stamp)
              linenum = ++linenum 
            } 
            else {
              print $0
            }
            if ( $0 ~ /\\$/ ) {
              flag = "true"
            }
            else {
              flag = "false"
            }
          }'                         sed_script2 > tmpfile 

    mv tmpfile sed_script2

  fi

  #  * Apply modifications to the extracted code by looping over all decks
  #  * and common decks.

# set -x
  if [ -s sed_script2 ] ; then

    file_list="*.dk *.cdk"
    for file in $file_list
    do
     if [ "$file" != '*.dk' -a "$file" != '*.cdk' ] ; then
      if [ "$numchar" -gt "$sed_limit" ] ; then
#       deck=`expr $file : '^\(.*\)\.c\{0,1\}dk'`
        deck=`expr $file : '\(.*\)\.c\{0,1\}dk'`
        if [ -s "${deck}_sed_script" ] ; then
#         sed -f ${deck}_sed_script $file > tmpfile 2>/dev/null
          cat $file | sed -n -e '/^[*%#][^ PpVv]*[Dd][Ee][Cc][Kk] .*[^ ]$/s/$/ /' -e '1,$p' | \
                      sed -f ${deck}_sed_script > tmpfile 2>/dev/null
          mv tmpfile $file
        fi
      else
#       sed -f sed_script2 $file > tmpfile 2>/dev/null
        cat $file | sed -n -e '/^[*%#][^ PpVv]*[Dd][Ee][Cc][Kk] .*[^ ]$/s/$/ /' -e '1,$p' | \
        sed -f sed_script2 > tmpfile 2>/dev/null
        mv tmpfile $file
      fi
     fi
    done

  fi
# set +x

fi

#
#  * Expand common decks unless specifically turned off.
#

if [ "$noexpd" != 'yes' ] ; then

# !!!!
# echo "Update: update_dir,USRXBIN2,USRXBIN1,USRTSTR,TSTRDIR,extra_lib,extra_lb2="
# echo "        $update_dir,$USRXBIN2,$USRXBIN1,$USRTSTR,$TSTRDIR,$extra_lib,$extra_lb2"
# !!!!

  #  * Generate awk script to in-line called comdecks.


  if [ -d "$update_dir/MODULES/." ] ; then
#  awklin00='filename = "'$update_dir/MODULES/'" filename'
   awklin00='"find -L '$update_dir/MODULES'  -name " filename " -print | tail -1 " | getline filename '
   cawklin00='close("find -L '$update_dir/MODULES'  -name " filename " -print | tail -1 ") '
  else
   awklin00='filename = "'$update_dir/'" filename'
   cawklin00='#'
  fi
  awkline='filename = "'$update_dir/'" filename'
# awkline='"find -L '$update_dir'  -name " filename " -print | tail -1 " | getline filename '
# cawkline='close("find -L '$update_dir'  -name " filename " -print | tail -1 ") '
  if [ -n "$USRXBIN2" -a -d "$USRXBIN2/." ] ; then
   awklin12='filename = "'$USRXBIN2/'" filename'
  else
   awklin12='filename = "'$update_dir/'" filename'
  fi
  if [ -n "$USRXBIN1" -a -d "$USRXBIN1/." ] ; then
   awklin11='filename = "'$USRXBIN1/'" filename'
   awklin20='filename = "'$USRXBIN1/'" filename'
  elif [ -n "$USRXBIN2" -a -d "$USRXBIN2/." ] ; then
   awklin11='filename = "'$USRXBIN2/'" filename'
   awklin20='filename = "'$USRXBIN2/'" filename'
  else
   awklin11='filename = "'$update_dir/'" filename'
   awklin20='filename = "'$update_dir/'" filename'
  fi
  if [ "$USRTSTR" = 'true' -a -n "$TSTRDIR" -a -d "$TSTRDIR/." ] ; then
   awklin20='filename = "'$TSTRDIR/'" filename'
#  awklin20='"find -L '$TSTRDIR'  -name " filename " -print | tail -1 " | getline filename '
#  cawklin20='close("find -L '$TSTRDIR'  -name " filename " -print | tail -1 " )'
  fi
  awklin2='filename = "'$extra_lib/'" filename'
# awklin2='"find -L '$extra_lib'  -name " filename " -print | tail -1 " | getline filename '
# cawklin2='close("find -L '$extra_lib'  -name " filename " -print | tail -1 ")'
  if [ -n "$extra_lb2" -a -d "$extra_lb2/." ] ; then
   awklin3='filename = "'$extra_lb2/'" filename'
#  awklin3='"find -L '$extra_lb2'  -name " filename " -print | tail -1 " | getline filename '
#  cawklin3='close("find -L '$extra_lb2'  -name " filename " -print | tail -1 ")'
  else
   awklin3='filename = "'$extra_lib/'" filename'
#  awklin3='"find -L '$extra_lib'  -name " filename " -print | tail -1 " | getline filename '
#  cawklin3='close("find -L '$extra_lib'  -name " filename " -print | tail -1 ")'
   

  fi

  cat <<..endcat > awk_script
     {
       if ( \$1 ~ /^[*%]CALL/ || \$0 ~ /^ *\. * [^ .]*\.cdk *$/ ) {

         #
         # If the CALL directive is encountered, or a file with a ".cdk"
         # extension is used by the "." command, then in-line the comdeck.
         #

         # First extract name of common deck and translate to lower case.
         # Then close any open files and pipes.
         # Check if the common deck is referenced via a parameter (ie. 
         # name contains 'cdlrs=$'), then make sure to substitute proper 
         # name first.
       
         origline = \$0
         if ( index(\$2,cdlrs) > 0 ) {
          mod_cmd = "eval echo " \$2  
          statl = mod_cmd | getline var2 
          close ( mod_cmd )
          # print "# origline=" origline ", mod_cmd=" mod_cmd ", statl=" statl ", var2=" var2
          print var2 | "tr [A-Z] [a-z] > filenames"
         }
         else {
          print \$2 | "tr [A-Z] [a-z] > filenames"
         }
         close("tr [A-Z] [a-z] > filenames")
         close("filenames")
         getline filename < "filenames"
        
         # Add ".cdk" extension to filename if it doesn't already exist.
        
         if ( \$2 !~ /\.cdk *$/ ) {
           filename = filename ".cdk"
         }
        
         # If the common deck does not exist in the current directory
         # (i.e. it wasn't modified through an update directive) then
         # add the path to the update library directory to the filename.

         file = filename

         if ( system ( "test -f " filename ) != 0 ) {
           $awklin3
#          $cawklin3
           if ( system ( "test -f " filename ) != 0 ) {
             $awklin2
#            $cawklin2
             if ( system ( "test -f " filename ) != 0 ) {
               filename = file
               $awklin20
#              $cawklin20
               if ( system ( "test -f " filename ) != 0 ) {
                 filename = file
                 $awklin11
                 if ( system ( "test -f " filename ) != 0 ) {
                   filename = file
                   $awklin12
                   if ( system ( "test -f " filename ) != 0 ) {
                     filename = file
                     $awkline
#                    $cawkline
                     if ( system ( "test -f " filename ) != 0 ) {
                       filename = file
                       $awklin00
                       $cawklin00
                       if ( system ( "test -f " filename ) != 0 ) {
                        filename = file
                       }
                     }
                   }
                 }
               }
             }
           }
           modified = "false"
         }        

         if ( system ( "test -f " filename ) != 0 ) {
          print "# filename = ", filename , " file =", file 
          print  "# Warning: Could not find code to expand : > " filename " < , skipped !"
          print  "echo  'Warning: Could not find code to expand : > " origline " < , skipped !'"
         }
         else {

#        {print "# filename = ", filename , " file =", file }
#         print "# Used --> ", filename , " <-- for '", file, "' call."  
        
         # Expand the call to the common deck by reading in every line
         # of the common deck. The line containing the comdeck definition
         # is ignored. Also set a flag to indicate that a comdeck was
         # indeed expanded.
        
         while ( getline < filename > 0 ) {
               if ( \$0 ~ /^[*%]CALL/ || \$0 ~ /^ *\. * [^ .]*\.cdk/ ) {
                 flag = "true"
               }
               if ( "$list" == "yes" && modified == "false" ) {
                 if ( \$0 ~ /^[*%#][^ PpVv]*[Dd][Ee][Cc][Kk]/ ) {
                   id = \$2
                   linenum = 1 
                 }
               else {
                   linenum = ++linenum 
                   stamp = id "." linenum
                   # printf ( "%-82s%-15s\n",\$0,stamp)
                   printf ( "%-82s%s%-15s\n",\$0," ",stamp)
                 } 
               }
               else {
                if ( \$0 !~ /^[*%#][^ PpVv]*[Dd][Ee][Cc][Kk]/ && \
                      \$0 !~ /end_of_data/ ) print \$0 
                }
          }
         }
         close (filename)
         modified = "true"

       }
       else {
     
             # Echo out each line of the deck except for one containing the 
             # deck definition.
     
             if ( \$1 !~ /^[*%#][^ PpVv]*[Dd][Ee][Cc][Kk]/ ) print \$0

       }
     }

     END {
   
       # If a common deck was not expanded during the present pass, then
       # generate a temporary file called "stop". This used for testing in
       # during the looping over all the decks and comdecks.
   
         if ( flag != "true" ) print "stop" > "stop"
     }
..endcat

  #  * For each common deck and deck, recursively in-line called common decks.
  #  * If a temporary file called "stop" is generated by a pass through awk,
  #  * then no further expansions are required and the loop is terminated for
  #  * that common deck or deck. 
  #  * 
  #  * Common decks are done first in order to minimize repetition when decks 
  #  * are processed. 

  file_list="*.cdk *.dk"
  if [ -n "$file_list_acc" ] ; then
    unset file_list_acc
  fi

  for file in $file_list
  do
     if [ "$file" != '*.dk' -a "$file" != '*.cdk' ] ; then
       file_list_acc="$file_list_acc $file"
     fi
  done
  if [ -n "$file_list_acc" ] ; then
    file_list=$file_list_acc
    unset file_list_acc
   for file in $file_list
   do
#!  if [ -f $file ] ; then
    while [ ! -f stop ]
    do
     if [ "$file" != '*.dk' -a "$file" != '*.cdk' ] ; then
      # $AWK -f awk_script $file > tmpfile 2>/dev/null
      $AWK -v cdlrs='$' -f awk_script $file > tmpfile 2>/dev/null
      mv tmpfile $file
     fi
    done
    \rm stop
#!  fi
   done
  fi
 
fi 

#
#  * Process all conditional definitions in all decks if requested.
#

#  * Generate awk script to do the processing.

exit_code=0

if [ "$def" = 'yes' ] ; then
  cat <<'..endcat' > awk_script
     BEGIN {
       
       # Set print flag. Also initialize the array "parameter" to the 
       # conditional definitions compiled in the file "condef_parameters".
       
       flag = "true"
       while ( getline parameter[++i] < "condef_parameters" > 0 ) { }

     }
    
     # If entering into a conditional block, increment level counter
     # to keep track of the number of nested blocks. 
     
     $1 ~ /^[*%]IF/ { level++ }
  
     {    

     if ( $1 ~ /^[*%]IF/ && flag == "true" ) {
       
       #
       # If an IF directive is encountered while echoing out lines, then
       # must determine if following lines are to be printed out or not.
       #
        
       ### The following "gsub" would fix the "...DEF,  ...." problem
       ### however it's better not to apply since that will lead to
       ### a change in behaviour from earlier implementation ...
       ### gsub(/, */,",",$0)
       ### However, such occurences are checked for and any matches are
       ### accumulated in "Updt_Illegal" file which would then get output along
       ### with an abort exit.

       if ( match($0,/, /) != 0 ) print $0 | "cat >> Updt_Illegal"
       
       # Split the individual items of the argument to the IF directive 
       # (based on commas as delimiters) into the array "item". Also get 
       # the number of items thereby obtained.
 
       number = split ($2,item,",")

       # Loop over all parameters in the list of items (every third item
       # starting with the second in the list) and set the corresponding
       # element in the array "value" to "true" if the parameter matches one
       # defined by the user in the input directives file.

       for ( j = 2; j <= number; j+=3 ) {
         value[j] = "false"
         for ( i in parameter ) {
           if ( item[j] == parameter[i] ) value[j] = "true"
         }
       }

       # Loop over all DEF's or -DEF's in the list of items (every third item
       # starting with the first in the list) and revise the elements of the
       # array "value" set by the previous loop based on whether or not
       # the parameters have been defined. 

       for ( i = 1 ; i < number; i+=3 ) {
         item[i] == "-DEF" && value[i+1] == "false" || \
         item[i] ==  "DEF" && value[i+1] == "true"  ?  \
           value[i+1] = "true" : value[i+1] = "false"
       }

       # Loop over all AND/OR operators in the list of items (every third item
       # starting with the third in the list). If the operator is "AND", 
       # then only true conditions on both sides of the AND are allowed to 
       # propagate through to the final evaluation of the IF statement.

       for ( i = 3; i < number; i+=3 ) { 
         if ( item[i] == "AND" ) {
           if ( value[i-1] != value[i+2] ) { 
             value[i-1] = "false"
             value[i+2] = "false"
           }
         }
       }
   
       # Scan over the elements in the array "value" and set the print
       # flag if one of the elements is set to "true".

       flag = "false"
       for ( i = 2; i <= number; i+=3 ) {
         if ( value[i] == "true" ) flag = "true" 
       }

       # If the print flag is set to "false", then store the level at which
       # this occurs so that printing may be resumed when the level counter
       # returns to this level. 

       if ( flag == "false" ) false_level = level

     }
     else if ( $1 ~ /^[*%]ENDIF/ ) {

       # If an ENDIF directive is encountered, decrement the level counter
       # and re-enable the printing if have ascended back to the level at
       # which printing was switched off.   
  
       if ( level-- == false_level ) flag = "true"  

     }
     else if ( flag == "true" ) {

       # Simply print out the line if printing has been switched on.

       print $0

     }

     }
..endcat

  #  * Loop over decks and expand the conditional definitions.

  file_list="*.dk"
  for file in $file_list
  do
   if [ "$file" != '*.dk' -a "$file" != '*.cdk' ] ; then
    (rm -f Updt_Illegal || : )
    touch Updt_Illegal
    $AWK -f awk_script $file > tmpfile
    mv tmpfile $file
    if [ -s "Updt_Illegal" ] ; then
     echo "\nUpdate: ***ERROR***-> Detected blank space(s) right after 'DEF,' conditional test, while compiling --> $file <-- module:\n"
     cat Updt_Illegal
     echo ""
     exit_code=3
    fi
   fi
  done

fi

if [ "$exit_code" = 0 ] ; then

  #  * Move updated decks back into directory from which the script is invoked.
  
  if [ "$cdk" != 'yes' ] ; then
    \rm *.cdk > /dev/null 2> /dev/null
  fi
  
  if [ -z "$output" ] ; then
    \rm '*.dk' 2> /dev/null
    \rm -f .update_chk_file
    cat *dk > .update_chk_file
    if [ -s ".update_chk_file" ] ; then
      mv *dk $output_path
    else
      echo " UPDATE: Error, empty output!. Check your update directives."
      exit_code=1 
    fi
  else
    cat $decks_list > $output_path/$output_name 2> /dev/null
    if [ ! -s "$output_path/$output_name" ] ; then
      echo " UPDATE: Error, empty output!. Check your update directives."
      exit_code=2
    fi
  fi 
else
 if [ "$exit_code" = '3' ] ; then
  echo "\nUpdate: ***ERROR***-> Please correct detected syntax errors ..."
 fi
fi

#  * Clean up files and remove temporary directory.

cd ..
\rm -r tmp_update_$$_$Ustamp

exit $exit_code
