#! /bin/sh

#
# Function: usage
# Arguments: u_name - The name of this program
#
# Returns: None
#
usage ()
{
    u_name="$1"

    cat <<EOF
Usage:
$u_name: -d pkg_dir -O exist_order -o new_order -P exist_toc -p new_toc

  pkg_dir     - The directory containing the subset of packages
  exist_order - The existing (superset) order file
  new_order   - The new (subset) order file to be created
  exist_toc   - The existing (superset) packagetoc file
  new_toc     - The new (subset) packagetoc file to be created
  
EOF
}

#
# Function: subset_packagetoc
# Arguments: sp_old_toc sp_new_toc sp_pkgarch
#	sp_old_toc - The location of the superset packagetoc
#	sp_new_toc - The location of the subset packagetoc to be created
#	sp_pa_file - The file containing the subset package architecture list
#
# Returns: 0 - success
#          1 - failure (this routine prints its own error messages)
#
subset_packagetoc ()
{
    sp_old_toc="$1"
    sp_new_toc="$2"
    sp_pa_file="$3"

    # Validate the parameters
    if [ ! -r "$sp_old_toc" ] ; then
	echo "ERROR: Couldn't find superset packagetoc in $sp_old_toc" >&2
	return 1
    fi

    touch $sp_new_toc
    if [ $? != 0 ] ; then
	echo "ERROR: Couldn't open new packagetoc $sp_new_toc for writing" >&2
	return 1
    fi

    if [ ! -r "$sp_pa_file" ] ; then
	echo "ERROR: No packages to subset" >&2
	return 1
    fi

    # Generate the subset packagetoc
    (wc -l <$sp_pa_file ; cat $sp_pa_file ; cat $sp_old_toc) | \
			    nawk >$sp_new_toc -v "pkgs=$sp_pkgarch" '
	BEGIN	    {
			initial = 1;
			readingpa = 0;
		    }

	/^PKG=/	    {
			# We found a package.  Determine whether or not we are
			# interested in this one.  If so, the save flag is set.
			# This flag tells the generic reader to save all read
			# input.  We do this because we will not know if we want
			# this entry until we get to the ARCH line.  If we are
			# not interested in this package, we clear the flags.
			if (pkg[substr($0, 5)]) {
			    save=1;
			    output=0;
			    curstr = $0;
			    curpkg = substr($0, 5);
			} else {
			    output=0;
			    save=0;
			}
			next;
		    }

	/^ARCH=/    {
			# We are down to the ARCH line.  If the arch/name
			# combination is one that interests us, print the
			# lines that we have saved, and tell the generic reader
			# to immediately print any other lines it finds in
			# this package description.  We do this by turning
			# off save mode, and turning on output mode.
			if (output || save) {
			    curarch=substr($0, 6);
			    split(pkg[curpkg], arches);
			    for (i = 1; arches[i]; i++) {
				if (arches[i] = curarch) {
				    print curstr;
				    print;
				    save = 0;
				    output = 1;
				    next;
				}
			    }
			}
	    	    }

	{
	    # This is the generic reader.  It has three possible states:
	    #  1. Initial.  In this state, it it is about to read a number that
	    #     indicates the number of subset packages.  This number is used
	    #     to determine how long state 2 is to be run.
	    #  2. Package arch reader.  In this state, n package/architecture
	    #     pairs are read, where n is the number read in stage 1.
	    #  3. Packagetoc reader.  In this state, the packagetoc is read and
	    #     processed.
	    #
	    # The individual states are described more below

	    # State 1 - Initial
	    if (initial == 1) {
		numpa = $0;
		initial = 0;
		readingpa = 1;
		next;
	    }

	    # State 2 - Package arch reader 
	    if (readingpa == 1) {
		# We get a list of pairs of the form "pkg arch", where
		# pkg and arch describe a single package.  We need a
		# a package name and an architecture in order to pluck
		# and entry from a .packagetoc.  We build an array from
		# this list.  The indicies of this array are the package
		# names, and the values are the architectures supported
		# by the package.
		if (pkg[$1]) {
		    pkg[$1] = sprintf("%s %s", pkg[$1], $2);
		} else {
		    pkg[$1] = $2;
		}

		numpa--;

		if (numpa == 0) {
		    readingpa = 0;
		}
		next;
	    }

	    # State 3 - Packagetoc reader
	    #
	    # If we are interested in this line, either the save mode or the
	    # output mode will be turned on.  In the former, we do not know
	    # if we are going to eventually print this line, so we hold on to
	    # it.  In the latter, we immediately print the read line.
	    if (save == 1) {
		curstr = sprintf("%s\n%s", curstr, $0);
	    } else {
		if (output == 1) {
		    print;
		}
	    }
	}
    '

    return 0
}

#
# Function: subset_order
# Arguments: so_old_order so_new_order so_pkgs
#	so_old_order - The location of the superset order file
#	so_new_order - The location of the subset order file to be created
#	so_pa_file   - The file containing the subset package architecture list
#
# Returns: 0 - success
#	   1 - failure (this routine prints its own error messages)
#
subset_order ()
{
    so_old_order="$1"
    so_new_order="$2"
    so_pa_file="$3"

    # Validate the parameters
    if [ ! -r "$so_old_order" ] ; then
	echo "ERROR: Couldn't find superset order file in $so_old_order" >&2
	return 1
    fi

    touch $so_new_order
    if [ $? != 0 ] ; then
	echo "ERROR: Couldn't open new packagetoc $so_new_order for writing" >&2
	return 1
    fi

    if [ ! -r "$sp_pa_file" ] ; then
	echo "ERROR: No packages to subset" >&2
	return 1
    fi

    (wc -l <$sp_pa_file ; cat $sp_pa_file ; cat $so_old_order) | \
			    nawk >$so_new_order -v "pkgs=$so_pkgs" '
	BEGIN	{
		    initial = 1;
		    readingpa = 0;
		}

	{
	    # This is the generic reader.  It has three possible states:
	    #  1. Initial.  In this state, it it is about to read a number that
	    #     indicates the number of subset packages.  This number is used
	    #     to determine how long state 2 is to be run.
	    #  2. Package name reader.  In this state, n package/architecture
	    #     pairs are read, where n is the number read in stage 1.  We only
	    #  3. Order file reader.  In this state, the order file is read and
	    #     processed.
	    #
	    # The individual states are described more below

	    # State 1 - Initial
	    if (initial == 1) {
		numpa = $0;
		initial = 0;
		readingpa = 1;
		next;
	    }

	    # State 2 - Package arch reader 
	    if (readingpa == 1) {
		# We get a list of package/architecture pairs.  We need to
		# be able to answer the question "Is package x in the subset
		# list?"  We do not need to be able to answer "What are the
		# subset packages?"
		pkg[$1] = 1;

		numpa--;

		if (numpa == 0) {
		    readingpa = 0;
		}
		next;
	    }

	    # State 3 - Order file reader
	    #
	    # If the package being read from the order file is part of the
	    # subset package list, keep (print) it.
	    if (pkg[$0]) {
		print;
	    }
	}
    '

    return 0
}

#
# Main
#

# Read arguments
while getopts P:p:O:o:d: c ; do
    case $c in
	d)	# Subset package directory
		pkgdir=$OPTARG
		;;

	O)	# Existing order
		fullord=$OPTARG
		;;
	o)	# Subset order to be created
		neword=$OPTARG
		;;
    
	P)	# Existing packagetoc
		fulltoc=$OPTARG
		;;
	p)	# Subset packagetoc to be created
		newtoc=$OPTARG
		;;

	\?)
		usage "$0"
		exit 2
		;;
    esac
done

if [ "X$pkgdir" = "X" -o \
     "X$fullord" = "X" -o "X$neword" = "X" -o \
     "X$fulltoc" = "X" -o "X$newtoc" = "X" ] ; then
    usage "$0"
    exit 2
fi

pa_file=/tmp/subset_pa.$$

echo "Gathering names of subset packages"
for pkg in `ls $pkgdir/*/pkginfo` ; do
    name=`grep '^PKG=' $pkg |sed -e 's/^PKG=//g'`
    arch=`grep '^ARCH=' $pkg |sed -e 's/^ARCH=//g'`

    echo "$name $arch" >>$pa_file

    if [ "X$pkgs" = "X" ] ; then
	pkgs="$name"
    else
	pkgs="$pkgs $name"
    fi
done

echo "Creating subset packagetoc $newtoc"
subset_packagetoc $fulltoc $newtoc $pa_file || exit $?
echo "Creating subset order $neword"
subset_order $fullord $neword "$pkgs" || exit $?

#rm $pa_file
