#!/bin/bash
# mkpatch 3.1
# 
# Copyright (C) 1998-2005, David Cheatham <david@mush.cx> Vadiv@M*U*S*H
# This software is provided "as is" without express or implied warranty.
# This software is placed in the public domain.
#
# If you can't run this script, try using 'bash mkpatch'
# It works under mingw, because mingw's /bin/sh is bash, which is all 
# well and good, but they stupidly didn't put a link from /bin/bash.
# So first type: ln -s /bin/sh.exe /bin/bash
# (You could just change the line at the top, but lots of things need
# /bin/bash, so symlinking it is best.)

show_help_basic () {
  cat <<STOP>>$STDERR
 1. Download pennmush. Untar it, compile it.
 2. Edit it. Make sure it works. It won't, so fix it. Repeat.
 3. Start in the pennmush root. It's probably named pennmush/
    You do not want to be in src/

 4. Locate the pennmush-VERSION.tar.gz you downloaded in step 1.
    If you haven't moved it around, it will be in .. and that's good.

    If you can't find that file, don't worry...I'll download it for you.
    This will suck over dialup, and wastes Javelin's bandwidth.

 5. Run mkpatch setup with: mkpatch -s

 6. Edit mkpatch.save and mkpatch.desc. You don't actually have to
    make any changes in there, just look around. Notice especially
    the first two blocks. Don't screw up the quotes.

 7. Actually make a patch, with: mkpatch filename versionnumber

 8. Open the patch in an editor and make sure the stuff at the top is
    sane. Then scan the rest of the patch to make sure you didn't
    screw up.

 For more info, run mkpatch -h
STOP
}

show_help_commands () {
  cat <<STOP>>$STDERR
Usage: mkpatch [-s] [-d] [-v] [-DNAME] [version] [filename]

-v | --verbose:  Shows exactly what's going on.

-s | --setup: What you do first. Make mkpatch.save and mkpatch.desc,
   which you can edit later.

* Patch options *

filename: The patch filename. If left out, it uses the one in mkpatch.save.

version: The patch version. If you forget, you can edit the patch and
  put it in manually. Leaving it out entirely will just confuse people.

-d | --dst: Patches *local*.dst files instead of *local*.c files.
   You edit the .c files like normal, but the patch will apply to
   other people's .dst files.

-DNAME: Really neat option useful for quick hacks. Puts the #DEFINEs in
   for you. Don't give me credit for that trick, diff does all the work.
STOP
}

stderr() {
    echo "$1">>$STDERR
}

level_comp() {
  plevel ./
  T=$PLEVEL
  pennmush_test $CLEAN
  plevel $CLEAN

  if [ '$T' == '$PLEVEL' ]; then
    stderr "ERROR: Patchlevels differ, aborting."
    exit
  fi
}

pennmush_test() {
  if [ ! -d $1 ] || [ ! -f $1'options.h.dist' ] ; then
    stderr "ERROR: $1 is not the root of any PennMUSH source."
    exit
  fi
}

plevel() {
  PLEVEL=`grep -v 'Do not' $1Patchlevel | cut -d" " -f4`
}

update_output() {
  if [ $1 -eq 1 ]; then
    if [ $VERBOSE ]; then
      stderr "$2 altered."
    fi
    ALTERED="$ALTERED $2"
  elif [ $VERBOSE ]; then
    stderr "$2 identical."
  fi
  DIFFED="$DIFFED $2"
}

run_diff_source() {
  if [ $MAKE_IFDEF ]; then
    diff $CLEAN/$1 $2 -D$MAKE_IFDEF|diff -cN $3 -L- -L${4:-$2} $CLEAN/$1 - >>mkpatch.out
  else
    diff -cdN $3 -L- -L${4:-$2} $CLEAN/$1 $2 >>mkpatch.out
  fi
  update_output $? $2
}

run_diff() {
  diff -cdN -L- $CLEAN/$1 $1 >>mkpatch.out
  update_output $? $2
}

diff_header() {

#  Template is from 
#  ftp://ftp.pennmush.org/pub/PennMUSH/Source/contrib/README-FOR-CONTRIBUTORS

  cat <<STOP >> mkpatch.out
# Patch name: $PATCH_NAME
# Patch version: $PATCH_VERSION
# Author's name: $NAME
# Author's email: $EMAIL
# Version of PennMUSH: `grep -v 'Do not' Patchlevel | cut -d" " -f4`
# Date patch made: `date`
# Author is willing to support (yes/no): $SUPPORT
# Created by: mkpatch 3.1
# Patch format: Context
#
#
# This is a contributed PennMUSH patch. Its use is subject to the
# same restrictions found in PennMUSH's hdrs/copyrite.h file.
#
# No warranty is given for this patch. It is not necessarily going
# to work on your system, with any version of PennMUSH other than
# the one above, etc.
#
# If the author given above was willing to support the patch, you
# should write to the author if you have any questions or problems. Do
# *NOT* send email messages to Javelin or any PennMUSH mailing list about
# this patch!
#
# Below this line is the author's description of the patch,
# followed by the patch itself. If the patch is in context diff
# format, you'll probably apply it by typing: patch < patchfile
# in your top-level MUSH directory, unless instructed otherwise
# below.
#
STOP
  sed s/^/'# '/ <mkpatch.desc >>mkpatch.out

  echo '# '>>mkpatch.out
}

save_settings () {
  cat <<STOP > ./mkpatch.save
# We pulled the defaults here from config.sh.
export NAME='${NAME:=$cf_name}'
export EMAIL='${EMAIL:=$cf_email}'

# This will show in @version if you stick it in patches/
export PATCH_NAME='${PATCH_NAME:=No name given}'
export SUPPORT='${SUPPORT:="no"}'

# This is where the file is written to if you don't specify
# a location on the command line. Changing this would be a clever
# idea if you keep making different versions of the same patch
export FILENAME=

# This the list of C files in MANIFEST that will *not* be diffed.
# If you find this is excluding somethings you want, you can comment it 
# out and all that will be excluded is 'announce.c', which isn't a 
# PennMUSH source file in the first place.
export C_EXCLUDE='(switchinc|comp|malloc|my|tables|announce|shs|strdup)'

# Where to output messages. Might be useful for some automated systems to
# send elsewhere.
export STDERR=/dev/stderr

# This is the location of a clear tree to diff against.
export CLEAN='mkpatch.clean/pennmush/'

STOP
}

do_setup() {
  echo "PennMUSH $PLEVEL detected."
  echo "If you didn't mean to run setup, hit Ctrl-C before the end."

  if [ -f config.sh ]; then
    grep cf_ config.sh>mkpatch.sh
    source mkpatch.sh
    rm -f mkpatch.sh
  fi

  if [ ! -d mkpatch.clean ]; then
    if [ -f ../pennmush-$PLEVEL.tar.gz ]; then
      TAR=../pennmush-$PLEVEL.tar.gz
    elif [ -f pennmush-$PLEVEL.tar.gz ]; then
        TAR=pennmush-$PLEVEL.tar.gz
    fi

    if [ ! $TAR ]; then
      echo "I can't find pennmush-$PLEVEL.tar.gz. I'll just download it real quick."
      echo "If you have this file somewhere, you need to either stick it here or in .."
      echo
      read -ep "Hit enter for download or Ctrl+C to exit" T
      echo Please wait...
      wget --user-agent "mkpatch 3.1" -c http://download.pennmush.org/Source/pennmush-$PLEVEL.tar.gz
      TAR=pennmush-$PLEVEL.tar.gz
    fi
    rm -fr mkpatch.clean
    mkdir mkpatch.clean
    cd mkpatch.clean
    tar -xz -f ../$TAR
    cd ..
  fi

  ALL=`cat $CLEAN\MANIFEST`

  for i in `cat $CLEAN\MANIFEST`
  {
    if [ ! -f $CLEAN$i ];then
      echo "$i is missing!"
      MANIFEST_ERROR=1
    fi
  }

  if [ $MANIFEST_ERROR ]; then
    echo
    echo "Your 'clean' directory is missing some files."
    echo "This could be PennMUSH's fault, if it is just one or two files."
    echo "To fix, you can edit the MANIFEST file in $CLEAN and delete the lines"
    echo
    echo "If it is *not* just one or two files, it is very likely that something"
    echo "went wrong either getting the tarball, or untarring it."
    echo "Please delete $CLEAN and try again."
    if [ $TAR ]; then
      echo
      echo "In addition, since we automatically untarred it for you, you'll"
      echo "want to delete $TAR, as that was apparently bad."
      echo "If you do, we'll download it again for you."
    fi
    exit
  fi  

  level_comp

  echo "Using $cf_name as author's name."
  echo "Using $cf_email as author's email."
  echo "If my guesses were wrong, you can edit mkpatch.save later"
  read -ep "Patch name: " PATCH_NAME
  read -ep 'Author is willing to support (yes/[no]):' SUPPORT

  save_settings

########
  cat <<STOP
-----------------------------------------------------

Now type a short description of this patch. You can use enter and
tab, although it may look weird. Don't worry, you can easily  
edit this later. Hit Control-D to stop.

-----------------------------------------------------
STOP
##########
  cat >>./mkpatch.desc
  echo To edit any of the above information later, edit mkpatch.save
  echo To edit the description, edit mkpatch.desc
  echo
  echo To make a patch, of course, just run without -s

}


#########################################################################
#########################################################################
#########################################################################
#### Program starts here 

export STDERR=/dev/stderr

pennmush_test `pwd`/

plevel ./

while [ $1 ]; do 
  case "$1" in
  -d|--dst)
    DIFF_DST=1
    ;;
  -v|--verbose)
    VERBOSE=1
    ;;
  -h|--help)
    show_help_commands
    exit
    ;;
  -s|--setup)
    do_setup
    exit
    ;;
  -D*)
    MAKE_IFDEF=`echo $1|sed s/-D//|tr [:lower:] [:upper:]`
    ;;
  [0-9]*)
    PATCH_VERSION=$1
    ;;
  *)
    OUTPUT=$1
    ;;
  esac
  shift
done

plevel ./ 


if [ ! -f ./mkpatch.save ]; then
  show_help_basic
  exit
fi

. ./mkpatch.save

level_comp


if [ ! $OUTPUT ]; then
  OUTPUT=$FILENAME
fi

rm -f mkpatch.out

if [ ! -f src/cmdlocal.c ]; then
  stderr "WARNING: This source tree was never compiled."
  echo "# WARNING WARNING WARNING: Source tree apparently never compiled.">>mkpatch.out
fi

diff_header

for i in `grep src/ MANIFEST|grep \.dst`
{
  if [ -f `echo $i|sed s/\.dst/\.c/` ];then
    run_diff_source $i `echo $i|sed s/\.dst/\.c/` -p ${DIFF_DST:+$i}
  fi
}

for i in `egrep 'src/.*\.c' MANIFEST|egrep -v ${C_EXCLUDE:='announce'}`
{
  run_diff_source $i $i -p
}

# check the headers
for i in `grep hdrs/ MANIFEST|grep -v version.h`
{
  run_diff_source $i $i -H
}

# And finally, other stuff you may have changed...
for i in `echo Configure options.h.dist Makefile.SH game/mushcnf.dst src/Makefile.SH MANIFEST`
{
  run_diff $i $i
}

stderr "`echo $DIFFED|wc -w` files diffed."

if [ ! "$ALTERED" ]; then
   stderr "No files altered. Not making a patch."
else
  stderr "`echo $ALTERED|wc -w` files altered:$ALTERED"
  if [ $OUTPUT ]; then
    mv -f mkpatch.out $OUTPUT
  else
    cat mkpatch.out
    rm -f mkpatch.out
  fi
fi
