#!/bin/sh
#**************************************************************************
# Copyright 1994 - 2002 Rational Software Corporation. All Rights Reserved.
# This software contains proprietary and confidential information of
# Rational and its suppliers. Use, disclosure or reproduction is
# prohibited without the prior express written consent of Rational.
#**************************************************************************
#SOHT
#
#NAME
#     ss_fixup - Fix up imports, switches and other Rational Apex files.
#     ss_check - Check imports, switches and other Rational Apex files.
#
#SYNOPSIS
#     ss_fixup [<options>] [<cfg_file>]
#     ss_check [<options>] [<cfg_file>]
#
#DESCRIPTION
#     This script is used to fix up imports and switches that have
#     come from a customer or third party development.
#     Will search for missing imports and specific switch values and
#     prompt for replacement of each one.  Will replace the old values
#     with the new values in these files.  Will set the .Rational_Location
#     files and remodel each view.
#
#     Subsystem views are obtained from the <cfg_file>.  If this is
#     not specified on the command line, it will use the find command
#     to locate them from the current directory.
#
#OPTIONS
#     -a   Convert /sierra/products to /aloha/products.
#     -h   Show this message.
#     -v   Verbose mode: show diff output.
#     -c   Just check for potential problems and report stuff that is missing.
#     -m   Use the existing missing list from the last run.
#     -r   Remodel views, even if all appear to be okay.
#     -rm  Remove .old files.
#     -s <str1> <str2>
#          Substitute <str1> for <str2> in Apex files.
#     -ss  Search includes subsystem names, not just the base/<lang> dir.
#     -sv  Search includes subsystem view names, not just the base/<lang> dir.
#          The -ss and -sv options cannot both be used.
#     -w   Search for and fix up .wrk views.
#
#DEPENDENCIES
#     You must run ss_fixup from an Apex shell.
#
#ERROR CODES
#     1 = improper command usage
#     2 = no views in the current directory
#     3 = no subsystems in the current directory
#     4 = not in an Apex environment
#     5 = not a valid directory.
#     6 = errors in <cfg_file>
#     7 = subsystem views need fixup. (-c option)
#     8 = Apex command error.
#
#EOHT
#**************************************************************************

FILE=$0
CMD=`basename $0`
RATIONAL=$HOME/.Rational
DB=$RATIONAL/$CMD.db
SEDF=/tmp/$CMD.sedf.$$
MISSING=/tmp/$CMD.miss.$$
MISSING2=/tmp/$CMD.miss.2.$$
DIR=${PWD:-`pwd`}
VERBOSE=/dev/null
do_check=no
do_key=no
do_remodel=no
do_ss=no
do_view=no
rm_old=':'
rel=rel
use_miss=no
unset cfg_file
s_opt=false
Opt_a=false
Sierra_to_Aloha=no-do-not-do-this

case $CMD in
ss_check )
    do_check=yes
    ;;
esac

#------------------------------------------------------------------------
# Determine which echo command to use.
#------------------------------------------------------------------------
if echo "look for \c" | grep c >/dev/null
then
    ECHON="echo -n"
    NOCR=
else
    ECHON=echo
    NOCR='\c'
fi

case `uname -s` in
AIX|OSF1 ) sym_link='-L' ;;
       * ) sym_link='-h' ;;
esac

#------------------------------------------------------------------------
delim() {
#------------------------------------------------------------------------
echo "------------------------------------------------------------------------------"
}

#-----------------------------------------------------------------
Usage() {
#-----------------------------------------------------------------

    status=$1
    if [ "$status" = 0 ]
    then
        # Extract the text between #SOHT and #EOHT in this script
        sed -e '1,/^#SOHT/d' -e '/^#EOHT/,$d' -e 's/^#//' $FILE | more
    else
        echo "Run '$CMD -h' to get usage info."
    fi
    exit $status
}

#-----------------------------------------------------------------
log() {
#-----------------------------------------------------------------

    Date=`date '+%T'`
    case $1 in
          aux ) shift; echo "$Date ::: [$*]" >&2 ;;
          pos ) shift; echo "$Date +++ $*" >&2 ;;
          neg ) shift; echo "$Date ++* $*" >&2 ;;
         warn ) shift; echo "$Date !!! $*" >&2 ;;
          err ) shift; echo "$Date *** $*" >&2 ;;
         note ) shift; echo "$Date --- $*" >&2 ;;
         cont ) shift; echo "$Cont ... $*" >&2 ;;
    esac
    Cont="$Date"
}

#-----------------------------------------------------------------
get_result() {
#-----------------------------------------------------------------
#  Get input from the user, providing a prompt value.

    while true
    do
        echo
        if [ -n "$2" ]
        then
            if $Opt_a
            then
                echo "$1: $2"
                result=$2
                return
            fi
            $ECHON "$1: [$2] $NOCR"
        else
            $ECHON "$1: $NOCR"
        fi
        read result
        if [ -n "$result" ]
        then
            eval result=\"$result\"
            return
        elif [ -n "$2" ]
        then
            result=$2
            return
        else
            echo "You must enter a value."
        fi
    done
}

#-----------------------------------------------------------------
get_yn() {
#-----------------------------------------------------------------
#  Get and validate a yes/no answer.

    while true
    do
        get_result "$1" "$2"
        case $result in
            [Yy]* ) yn=yes; return ;;
            [Nn]* ) yn=no;  return ;;
                * ) echo "Please enter 'y' or 'n'." ;;
        esac
    done
}

#-----------------------------------------------------------------
get_new() {
#-----------------------------------------------------------------

    if [ -z "$1" ]
    then
        new=
    elif [ -d $1 ]
    then
        new=$1
    else
        new=
    fi

    if [ -z "$new" ]
    then
        case "$old" in
        /tmp_mnt/* )
            new=`echo $old | sed -e "s?^/tmp_mnt??"`
            test -d $new || unset new
            ;;
        esac
    fi

    echo
    echo "--------------------------------------------------------"
    echo "There are references to things like this:"
    grep $old $MISSING2 | head -1 | sed -e "s?^?         ?"
    echo
    echo "  Search for: $old"
    while true
    do
        get_result "Replace with" $new
        test -d "$result/." && break
        echo "$result not found."
    done
    new=$result
    echo
    echo "Okay, will change..."
    echo "this: $old"
    echo "  to: $new"
    echo
}

#-----------------------------------------------------------------
save_db_sedf() {
#-----------------------------------------------------------------

   /bin/rm -f $SEDF
   n=1
   while [ $n -le $N ]
   do
       eval old=\"\$old$n\"
       eval new=\"\$new$n\"
       echo "s?$old?$new?g" >> $SEDF
       if [ -f $DB ]
       then
           (
           grep -v "^$old " $DB 2>/dev/null
           echo "$old $new"
           ) | sort -r > $DB.new
           mv $DB.new $DB
       else
           echo "$old $new" > $DB
       fi
       n=`expr $n + 1`
   done

   if $s_opt
   then
       echo "$sed_opt" >> $SEDF
   fi
}

#------------------------------------------------------------------------
update_file() {
#------------------------------------------------------------------------

    file=$1
    type=$2

    test -s $SEDF || return

    sed -f $SEDF $file > $file.new
    if diff $file $file.new > $VERBOSE
    then
        echo "   $type is up-to-date."
        rm $file.new
        $rm_old $file.old
        return 1
    fi

    mv $file $file.old
    mv $file.new $file
    $rm_old $file.old
    echo "   $type updated."
    fix_up_done=yes
    return 0
}

#------------------------------------------------------------------------
echo_if_not_found() {
#------------------------------------------------------------------------

    if [ -d $1 ]
    then
        case $1 in
        /tmp_mnt/* )
            echo $1
            ;;
        $Sierra_to_Aloha )
            echo $1
            ;;
        esac
        return
    fi
    echo $1
}

#------------------------------------------------------------------------
report_if_not_found() {
#------------------------------------------------------------------------

    if [ -d $1 ]
    then
        case $1 in
        /tmp_mnt/* )
            echo "    $1 is a tmp_mnt"
            echo "    in $2"
            need_fixup=yes
            ;;
        esac
        return
    fi

    echo "    $1 not found"
    echo "    in $2"
    need_fixup=yes
}

#------------------------------------------------------------------------
echo_nal_not_found() {
#------------------------------------------------------------------------

    case $1 in
    -L%%* ) nal_switch=`echo $1 | sed -e 's?^-L??' -e 's?%%/.*?%%?` ;;
     -L/* ) nal_switch=`echo $1 | sed -e 's?-L??'` ;;
       /* ) nal_switch=$1 ;;
        * ) return ;;
    esac

    if [ -d $nal_switch ]
    then
        case $nal_switch in
        /tmp_mnt/* )
            echo $nal_switch
            ;;
        esac
        return
    fi
    echo $nal_switch
}

#------------------------------------------------------------------------
report_nal_not_found() {
#------------------------------------------------------------------------

    case $1 in
    -L%%* ) nal_switch=`echo $1 | sed -e 's?^-L??' -e 's?%%/.*?%%?` ;;
     -L/* ) nal_switch=`echo $1 | sed -e 's?-L??'` ;;
       /* ) nal_switch=$1 ;;
        * ) return ;;
    esac

    if [ -d $nal_switch ]
    then
        case $nal_switch in
        /tmp_mnt/* )
            echo "    $nal_switch is a tmp_mnt"
            echo "    in $2"
            need_fixup=yes
            ;;
        esac
    else
        echo "    $nal_switch not found"
        echo "    in $2"
        need_fixup=yes
    fi
}

#------------------------------------------------------------------------
ratl_loc_okay() {
#------------------------------------------------------------------------

    if [ $sym_link $ss/.Rational_Location ]
    then
        set -- `ls -ld $ss/.Rational_Location`
        shift `expr $# - 1`
        test "$1" = $ss && return 0
    fi
    return 1
}

#------------------------------------------------------------------------
grep_keys() {
#------------------------------------------------------------------------

    egrep "_KEY:|_KEY:|COMPILER_HOME:|COMPILER_TOOLS_PATH:" $ck |
        grep -v "<view'host_architecture>" |
        awk '{print $2}'
}

#------------------------------------------------------------------------
fix_up() {
#------------------------------------------------------------------------

    fix_up_done=no
    /bin/rm -f $view/.Rational_Location

    ck=$view/Policy/Switches
    if [ -f $ck ]
    then
        if [ "$do_check" = yes ]
        then
            for key in `grep_keys`
            do
                report_if_not_found $key $ck
            done
            set -- 1 `grep "^NON_ADA_LINKAGE:" $ck`
            shift
            if [ "$1" = "NON_ADA_LINKAGE:" ]
            then
                shift
                for nal in $*
                do
                    report_nal_not_found $nal $ck
                done
            fi
        else
            update_file $ck Switches
        fi
    fi

    ckt=$view/.Rational/Compilation/Compiler_Key.times
    if [ -f $ckt ]
    then
        if [ "$do_check" = yes ]
        then
            for key in `grep "/ada/keys/" $ckt`
            do
                report_if_not_found $key $ckt
            done
        else
            update_file $ckt Compiler_Key.times
        fi
    fi


    vp=$view/.Rational/View_Control/View_Properties
    if [ -f $vp.prop ]
    then
        vp=$vp.prop
        VP=View_Properties.prop
    else
        VP=View_Properties
    fi
    if [ "$do_check" = yes ]
    then
        model=`grep "^MODEL:" $vp | awk '{print $2}'`
        if [ -n "$model" ]
        then
            report_if_not_found $model $vp
        fi
    else
        update_file $vp $VP
    fi

     for cfg in \
        Imports/Description.cfg \
        Imports/Mutual_Description.cfg \
        .Rational/Imports_Control/Explicits.cfg \
        .Rational/Imports_Control/Mutual_Explicits.cfg \
        .Rational/Compilation/Compilation.cfg \
        .Rational/View_Control/Model_Description.cfg
     do
        im=$view/$cfg
        if [ -f $im ]
        then
            if [ "$do_check" = yes ]
            then
                for imp in `grep -v "^#" $im`
                do
                    report_if_not_found $imp $im
                done
            else
                update_file $im `basename $cfg`
            fi
        fi
    done

    if [ "$fix_up_done" = yes ]
    then
        view_list="$view_list $view"
    else
        echo "    Up-to_date."
    fi
}

#-----------------------------------------------------------------
check_ss_views() {
#-----------------------------------------------------------------

    for view in $views
    do
        name=`basename $view`
        ss=`echo $view | sed -e "s?\.ss/.*?.ss?g"`
        ss=`basename $ss`
        delim
        echo "Subsystem: $ss   View: $name"
        fix_up && echo "    Up-to-date"
    done
}

#-----------------------------------------------------------------
ss_prune() {
#-----------------------------------------------------------------
    sed -e "s?/? ?g" | while read line
    do
        if [ "$do_key" = yes ]
        then
            case "$line" in
            *key )
                echo "/$line" | sed -e "s? ?/?g"
                continue
                ;;
            esac
        fi

        set -- $line
        new_line=
        while [ $# -gt 0 ]
        do
            case $1 in
            *.ss )
                if [ "$do_ss" = yes ]
                then
                    new_line=$new_line/$1
                elif [ "$do_view" = yes ]
                then
                    new_line=$new_line/$1/$2
                fi
                break
                ;;
            ada|c++ )
                if [ "$2" = keys ]
                then
                    new_line=$new_line/$1/keys
                    break
                fi
                ;;
            %%* )
                if [ -z "$new_line" ]
                then
                    new_line=$1
                    shift
                    continue
                fi
                ;;
            esac
            new_line=$new_line/$1
            shift
        done
        echo $new_line
    done
}

#-----------------------------------------------------------------
# Get command line options, set flags.
#-----------------------------------------------------------------
while [ $# -gt 0 ]
do
    case $1 in
    -a )
        Opt_a=true
        Sierra_to_Aloha="/sierra/products/*"
        ;;
    -h* )
        Usage 0
        ;;
    -c )
        do_check=yes
        ;;
    -m )
        use_miss=yes
        ;;
    -r )
        do_remodel=yes
        ;;
    -rm )
        rm_old='/bin/rm -f'
        ;;
    -key )
        do_key=yes
        ;;
    -s )
        if $s_opt
        then
            sed_opt="${sed_opt}
s?$2?$3?g"
        else
            sed_opt="s?$2?$3?g"
        fi
        s_opt=true
        shift 2
        ;;
    -ss )
        do_ss=yes
        if [ "$do_view" = yes ]
        then
            echo "$CMD: the -ss option cannot be used with the -sv option."
            Usage 1
        fi
        ;;
    -sv )
        do_view=yes
        if [ "$do_ss" = yes ]
        then
            echo "$CMD: the -sv option cannot be used with the -ss option."
            Usage 1
        fi
        ;;
    -v )
        VERBOSE=
        ;;
    -w )
        rel=wrk
        ;;
    * )
        if [ -s $1 ]
        then
            cfg_file=$1
            break
        fi
        echo "$CMD: Option '$1' not recognized."
        Usage 1
        ;;
    esac
    shift
done

#-----------------------------------------------------------------
# Check if in Apex shell.
#-----------------------------------------------------------------
if [ $do_check = no  -a  -z "$APEX_MESSAGE_SERVER" ]
then
    echo "You must be an an Apex environment to run $CMD."
    Usage 4
fi

#------------------------------------------------------------------------
# Set the cannonical path to the current directory.
#------------------------------------------------------------------------
set_DIR() {
    cdir=`cpath $DIR`
    DIR=${cdir:-$DIR}
    get_result "Current directory" $DIR
    DIR=$result
    if [ ! -d $DIR ]
    then
        echo "$DIR not found."
        exit 1
    fi
    cd $DIR
}

#------------------------------------------------------------------------
# Find the views and subsystems.
#------------------------------------------------------------------------
exit_status=0
trap '/bin/rm -f $SEDF $MISSING $MISSING2; exit $exit_status' 1 2 3 4 5 15
if [ -z "$cfg_file" ]
then
    set_DIR
    in_dir=$DIR
    echo
    $ECHON "Looking for .$rel views in $DIR...$NOCR"
    views=`find $DIR -name \*.$rel -print -prune`
    set -- `echo "$views" | wc -l`
    N_views=$1
    echo found: $N_views
else
    in_dir=$cfg_file
    N_views=0
    echo
    $ECHON "Checking .$rel views in $cfg_file...$NOCR"
    views=
    errors=
    for v in `cat $cfg_file`
    do
        eval v=$v
        case $v in
        /* ) ;;
        * ) echo
            echo Error: $v must be fully qualified.
            errors=yes
            continue 
            ;;
        esac

        if [ -d $v ]
        then
            if [ -f $v/.Rational/View_Control/View_Properties.prop ]
            then
                views="$views $v"
                N_views=`expr $N_views + 1`
            elif [ -f $v/.Rational/View_Control/View_Properties ]
            then
                views="$views $v"
                N_views=`expr $N_views + 1`
            else
                echo
                echo Error: $v is not a view.
                errors=yes
            fi
        else
            echo
            echo Error: $v not found.
            errors=yes
        fi
    done

    test "$errors" = yes && exit 6

    echo okay: $N_views
fi

if [ -z "$views" ]
then
    echo "No .$rel views found in $in_dir."
    Usage 2
fi

subsystems=`(for v in $views
             do
                 echo $v
             done | sed -e "s?\.ss/.*?.ss?g" | sort -u)`

if [ -z "$subsystems" ]
then
    echo "No subsystems found in $in_dir."
    Usage 3
fi

#------------------------------------------------------------------------
# Look for invalid references.
#------------------------------------------------------------------------
if [ -s $MISSING -a "$use_miss" = yes ]
then
    set -- `cat $MISSING | wc -l`
    N=$1
else

    $ECHON "Looking for missing references in each view...$NOCR"
    (
    for view in $views
    do
        ck=$view/Policy/Switches
        for key in `grep_keys`
        do
            echo_if_not_found $key
        done

        set -- 1 `grep "^NON_ADA_LINKAGE:" $ck`
        shift
        if [ "$1" = "NON_ADA_LINKAGE:" ]
        then
            shift 1
            for nal in $*
            do
                echo_nal_not_found $nal
            done
        fi

        ckt=$view/.Rational/Compilation/Compiler_Key.times

        ckt=$view/.Rational/Compilation/Compiler_Key.times
        for key in `grep "/ada/keys/" $ckt`
        do
            echo_if_not_found $key
        done

        vp=$view/.Rational/View_Control/View_Properties
        if [ -f $vp.prop ]
        then
            vp=$vp.prop
        fi
        for model in `grep "^MODEL:" $vp | awk '{print $2}'`
        do
            echo_if_not_found $model
        done

        for cfg in \
            Imports/Description.cfg \
            Imports/Mutual_Description.cfg \
            .Rational/Imports_Control/Explicits.cfg \
            .Rational/Imports_Control/Mutual_Explicits.cfg \
            .Rational/Compilation/Compilation.cfg \
            .Rational/View_Control/Model_Description.cfg
        do
            im=$view/$cfg
            test -f $im || continue
            for imp in `grep -v "^#" $im`
            do
                echo_if_not_found $imp
            done
        done
    done
    ) > $MISSING2
    cat $MISSING2 | ss_prune | sort -ur > $MISSING
    set -- `cat $MISSING | wc -l`
    N=$1
    echo found $N:
    sed -e "s?^?    ?" $MISSING
fi

#------------------------------------------------------------------------
# Get new Switch or Import for corresponding missing one.
#------------------------------------------------------------------------
if [ "$do_check" = no ]
then
    n=1
    for old in `cat $MISSING`
    do
        eval old$n=$old
        set -- 1 `grep "^$old " $DB 2>/dev/null`
        eval set -- $*
        get_new $3
        eval new$n=$new
        n=`expr $n + 1`
    done
    save_db_sedf
fi

#------------------------------------------------------------------------
# Fix up each view.
#------------------------------------------------------------------------
view_list=
need_fixup=no
NN=0
for view in $views
do
    NN=`expr $NN + 1`
    name=`basename $view`
    ss=`echo $view | sed -e "s?\.ss/.*?.ss?g"`
    ss=`basename $ss`
    delim
    echo "Subsystem: $ss"
    echo "View $NN of $N_views: $name"
    test "$N" = 0 || fix_up
done

# If the -c option was specified just report potential problems.
if [ "$do_check" = yes ]
then
    delim
    if [ "$need_fixup" = yes ]
    then
        echo "Subsystem/views need to be fixed up."
        exit 7
    else
        echo "All subsystem/views up-to-date."
        exit 0
    fi
fi

#------------------------------------------------------------------------
# Fix up each subsystem.
#------------------------------------------------------------------------
delim
echo Checking .Rational_Location links...
for ss in $subsystems
do
    ss_name=`basename $ss`
    if ratl_loc_okay
    then
        echo "    Subsystem $ss_name: up-to-date."
    else
        apex set_location -replace $ss $ss
        echo "    Subsystem $ss_name: updated."
    fi
done

#------------------------------------------------------------------------
# Remodel views.
#------------------------------------------------------------------------
if [ -n "$view_list" ]
then
    delim
    if apex remodel -refresh -force $view_list
    then
        echo "`date +%T` +++ apex remodel completed successfully."
    else
        echo "`date +%T` *** apex remodel failed."
        exit_status=8
    fi

elif [ "$do_remodel" = yes ]
then
    delim
    if apex remodel -refresh -force $views
    then
        echo "`date +%T` +++ apex remodel completed successfully."
    else
        echo "`date +%T` *** apex remodel failed."
        exit_status=8
    fi
fi

delim

/bin/rm -f $SEDF $MISSING $MISSING2

exit $exit_status

# End of ss_fixup.
