#!/bin/bash
#
# make a changes file for a package upload
#
# $Log: dchanges,v $
# Revision 1.1  1995/11/08 02:56:53  root
# Initial revision
#
# these may be changed in getopt processing
#

PRIORITIES="Low Routine High Urgent"
DATE=`date -u "+%d %b %y %H:%M UT"`
FORCEFILE=""
PRI_S="Low"
PRI_E=""
CHA_S=""
CHA_E=""
TAR_FILES=""
DIFF_FILES=""
DEB_FILES=""
UNK_FILES=""
VERSION=""
PACKAGE=""
TAR_CNT=0
DIFF_CNT=0
DEB_CNT=0
UNK_CNT=0
NOPTION=FALSE

SUCCESS=0
FAILURE=1

function main
{
    PROG=`basename $0`
    for i in "$@"
    do
        case $i in
            -f)    shift 1; get_forcefile  $1 || exit $FAILURE; shift 1;;
            -n)    shift 1; NOPTION=TRUE;;
            -s)    shift 1; do_syntax $* || exit $FAILURE; exit $SUCCESS;;
            cs=*)  CHA_S=`echo $i | cut -d= -f2`; shift 1;;
            ce=*)  CHA_E=`echo $i | cut -d= -f2`; shift 1;;
            ps=*)  PRI_S=`echo $i | cut -d= -f2`; shift 1;;
            pe=*)  PRI_E=`echo $i | cut -d= -f2`; shift 1;;
            -\?)   do_usage; exit $SUCCESS;;
            -*)    stderr "ERROR:"  "$i not supported"; exit $FAILURE;;
        esac
    done

    RV=$FAILURE
    for i in $PRIORITIES
    do
        if [ $PRI_S = $i ]
        then
            RV=$SUCCESS
            break
        fi
    done
    if [ $RV = $FAILURE ]
    then
        stderr "ERROR:" "Priority must be one of { $PRIORITIES }"
        return $RV
    fi
    do_changes $* || exit $FAILURE
    if [ $NOPTION = FALSE ]
        then
            if ! do_edit $OUTFILE
            then
                stderr "ERROR:"  "Unable to edit $OUTFILE"
                return $FAILURE
            fi
    fi
    if ! do_syntax $OUTFILE
    then
        stderr "ERROR:" "$FILE has invalid syntax"
        return $FAILURE
    fi
    return $SUCCESS
}

function get_forcefile
{
    FORCEFILE=$1
    if [ X$FORCEFILE = X ]
    then
        stderr "ERROR:"  "-f option needs a filename"
        return $FAILURE
    fi
    if [ ! -r $FORCEFILE -a ! -L $FORCEFILE ]
    then
        stderr "ERROR:" "file $FORCEFILE missing or not readable"
        return $FAILURE
    fi
    return $SUCCESS
}

function do_usage
{
    echo "Usage: $PROG [options] [overrides] filenames"
    echo "Options:"
    echo "  -f file    # Take all changes info except date from file"
    echo "  -n         # No edit of the changes file"
    echo "  -s         # Just syntax-check the named changes files"
    echo "  -?         # Print this message"
    echo "Overrides:"
    echo "  cs=string, ce=file, ps=string, pe=file"
    echo "Type \"man $PROG\" for more info"
    return $SUCCESS
}

function do_changes
{
    if [ X$FORCEFILE != X ]
    then
        OUTFILE=$PROG.out
        >$OUTFILE
        echo "Date: "$DATE >>$OUTFILE
        cat $FORCEFILE >>$OUTFILE
        echo "Files:" >>$OUTFILE
        for FILE in $*
        do
            if [ ! -r $FILE -a ! -L $FILE ]
            then
                stderr "ERROR:" "file $FILE missing or not readable"
                RV=$FAILURE
            fi
        done
        if [ $RV != $FAILURE ]
        then
            do_ls $*
            do_sum $*
        fi
        return $RV
    fi

    collect_pkgfiles $* || return $FAILURE
    RV=$SUCCESS
    if [ $TAR_CNT != 1 ]
    then
        stderr "ERROR:" "exactly one .tar.gz file required"
        RV=$FAILURE
    fi
    if [ $DIFF_CNT != 1 ]
    then
        stderr "ERROR:" "exactly one .diff.gz file required"
        RV=$FAILURE
    fi
    if [ $DEB_CNT = 0 ]
    then
        stderr "ERROR:" "at least one .deb file required"
        RV=$FAILURE
    fi
    if [ $RV = $FAILURE ]
    then
        return $RV
    fi

    >$OUTFILE
    echo "Date: "$DATE >>$OUTFILE
    echo "Source: "$PACKAGE >>$OUTFILE
    echo -n "Binary: " >>$OUTFILE
    for i in $DEB_FILES
    do
        PKG=`echo $TOKENS | cut -d' ' -f1`
        echo -n $PKG" " >>$OUTFILE
        done
    echo >>$OUTFILE
    echo "Version: $VERSION" >>$OUTFILE
    echo "Description: " >>$OUTFILE
    for FILE in $DEB_FILES
    do
        PKG=`dpkg-deb --field $FILE package`
        echo -n " "$PKG": " >>$OUTFILE
        dpkg-deb --field $FILE description | head -1 >>$OUTFILE
    done
    echo "Priority: "$PRI_S >>$OUTFILE
    if [ X$PRI_E != X ]
    then
        sed -e 's/^/ /;s/^[ 	]*$/ ./' <$PRI_E | col -x >>$OUTFILE
    fi
    echo "Changes: "$CHA_S >>$OUTFILE
    if [ X$CHA_E != X ]
    then
        sed -e 's/^/ /;s/^[ 	]*$/ ./' <$CHA_E | col -x >>$OUTFILE
    fi
    echo "Files:" >>$OUTFILE
    do_ls $TAR_FILES $DIFF_FILES $DEB_FILES $UNK_FILES
    do_sum $TAR_FILES $DIFF_FILES $DEB_FILES $UNK_FILES
    return $SUCCESS
}

function do_ls
{
    for FILE in $*
    do
        echo -n " " >>$OUTFILE
        ls -lLd $FILE >>$OUTFILE
    done
}

function do_sum
{
    for FILE in $*
    do
        echo -n " " >>$OUTFILE
        md5sum $FILE >>$OUTFILE
    done
}

function collect_pkgfiles
{
    RV=$SUCCESS
    for FILE in $*
    do
        if [ ! -r $FILE -a ! -L $FILE ]
        then
            stderr "ERROR:" "file $FILE missing or not readable"
            RV=$FAILURE
        fi
        if [ `dirname $FILE` != . ]
        then
            stderr "ERROR:" "$FILE not in current directory"
            RV=$FAILURE
        fi
        #
        # filenames have the form <PKG>-<VER>-<REV>.<EXT>
        # PKG can contain anything
        # VER can contain alphanumerics and '.' chars
        # REV can contain alphanumerics
        # EXT can contain anything
        #
        TOKENS=`echo $FILE | \
            sed -e 's/\(.*\)-\([0-9a-zA-Z.]*\)-\([0-9a-zA-Z]*\)\.\(.*\)/\1 \2 \3 \4/'`
        PKG=`echo $TOKENS | cut -d' ' -f1`
        VER=`echo $TOKENS | cut -d' ' -f2`
        REV=`echo $TOKENS | cut -d' ' -f3`
        EXT=`echo $TOKENS | cut -d' ' -f4`
        if [ X$VERSION = X ]
        then
            VERSION=$VER-$REV
        fi
        if [ $VER-$REV != $VERSION ]
        then
            stderr "ERROR:" "version mismatch -- $FILE != $VERSION"
            RV=$FAILURE
        fi
        case $EXT in
            deb)     DEB_FILES=$DEB_FILES' '$FILE;
                     DEB_CNT=`expr $DEB_CNT + 1`;
                     ;;
            tar.gz)  TAR_FILES=$TAR_FILES' '$FILE;
                     TAR_CNT=`expr $TAR_CNT + 1`;
                     PACKAGE=`basename $PKG`;
                     ;;
            diff.gz) DIFF_FILES=$DIFF_FILES' '$FILE;
                     DIFF_CNT=`expr $DIFF_CNT + 1`;
                     ;;
            *)       UNK_FILES=$UNK_FILES' '$FILE;
                     UNK_CNT=`expr $UNK_CNT + 1`;
                     ;;
        esac
    done
    OUTFILE=$PACKAGE-$VERSION.changes
    return $RV
}

function stderr
{
    echo $* 1>&2
    return $SUCCESS
}

function do_syntax
{
    RETURN=0
    for FILE in $*
    do
        if [ ! -r $FILE -a ! -L $FILE ]
        then
            stderr "ERROR:" "file $FILE missing or not readable"
            continue
        fi
        gawk 'BEGIN {
             hits["Date:"] = 0
             hits["Source:"] = 0
             hits["Binary:"] = 0
             hits["Version:"] = 0
             hits["Description:"] = 0
             hits["Priority:"] = 0
             hits["Changes:"] = 0
             hits["Files:"] = 0
             err = malformed = misplaced = blanklines = 0
             infield = 0
        } {
             if (substr($0,1,1) == "#") next
             if ( length( $0 ) == 0 || NF == 0) { blanklines++; next } 
             if ( substr($0,1,1) == " " )
             {
                 if ( infield == 0) misplaced++
             } else {
                 if ( substr( $1, length( $1 ) )  != ":" ) { malformed++; next }
                 infield = 1
                 hits[$1]++
             }
        } END {
        #
        # all fields have a one-entry limit
        #
             for (field in hits)
             {
                 name = substr(field, 1, length(field) - 1)
                 if ( hits[field] != 1 )
                 {
                     err++
                     print hits[field]" "name" field lines" > "/dev/stderr"
                 }
             }
             if (blanklines != 0)
             {
                 err++
                 print blanklines" illegal blank lines" > "/dev/stderr"
             }
             if (misplaced != 0)
             {
                 err++
                 print misplaced" misplaced field extension lines" > "/dev/stderr"
             }
             if (malformed != 0)
             {
                 err++
                 print malformed" field summary lines missing \":\" after field name" > "/dev/stderr"
             }
             exit err
        }' $FILE
        ERRORS=$?
        if [ $ERRORS != 0 ]
        then
            RETURN=1
            stderr "ERROR:" "$ERRORS syntax problems in $FILE"
        fi
    done
    return $RETURN
}

function do_edit
{
    FILE=$1
    MY_EDITORS="vi emacs pico joe ee ed"
    if [ X$EDITOR != X ]
    then
        MY_EDITOR=$EDITOR
    else
        if [ X$VISUAL != X ]
        then
            MY_EDITOR=$VISUAL
        else
            for MY_EDITOR in $MY_EDITORS
            do
                type $MY_EDITOR >/dev/null 2>&1 && break
            done
        fi
    fi
    if ! type $MY_EDITOR >/dev/null 2>&1
    then
        stderr "ERROR:"  "Unable to find editor $MY_EDITOR"
        return $FAILURE
    fi
    $MY_EDITOR $FILE
    return $SUCCESS
}

main "$@"
