#!/bin/sh
#
# Shell script to create c4b patches for a current source tree
#
# usage:
#
# ./make-patches.sh [source tree base directory]
#

SRCBASE=/usr/src
PATCHDIR=`pwd`
C4BBASE=`pwd`/../..
BCKSFX=".org.c4b"



# Function to perform an edit operation on a file if some pattern does not exist
#
# First the original file specified as the 1st argument is searched for the
# pattern specified as the 2nd argument to this function. If the pattern already
# exists, the edit operation is considered to be already done and function
# execution terminates.
#
# Otherwise the edit operation must be performed. The original file is first
# renamed with the new suffix ${BCKSFX}. The sed is used to insert the content
# of the file specified as the 4th argument into the original file right after
# the line addressed by the pattern in the 3rd function argument. 
#
# $1 - The file to edit
# $2 - The pattern to search for; do not edit if it is found
# $3 - The pattern to insert the content of file $4 after
# $4 - A file name thats content is to be inserted before the pattern in $3.
#
edit-file()
{
   local bck_fname

   bck_fname="$1${BCKSFX}"
   
   # if the search pattern is found, we are ready and must not modify the file
   if [ -n "$2" ]; then
      if grep "$2" "$1" > /dev/null ; then
         echo "NOTICE: Edit operation already done for \"$1\""
         return 0
      fi
   fi
   
   echo "Perform edit operation on file \"$1\""
   
   # rename the original file so that it gets the suffix ${BCKSFX}
   mv -f "$1" "$bck_fname"
   
   # use sed to insert file $4 into $1 just before the position of $3
   sed -e "\#$3#r${PATCHDIR}/$4" < "${bck_fname}" > "$1"
   if [ $? -ne 0 ]; then
      echo "Edit operation on file \"$1\" failed"
      mv -f "$bck_fname" "$1"
      exit 1
   fi
   diff "$bck_fname" "$1" 2>&1 > /dev/null
   if [ $? -ne 1 ]; then
      echo "Edit operation on file \"$1\" failed, new and original version are the same after edit"
      mv -f "$bck_fname" "$1"
      exit 1
   fi
   
   return 0
} # edit-file



# Function to check a file for existence of two versions
#
# For some files automatic patch creation is not possible. So for these files
# the respective new version must be created "by hand". This function checks if
# there are two versions of the file specified as the argument, the original
# name and a version with the suffix ${BCKSFX}.
#
# $1 - The file name to check for existence of two versions
#
check-file()
{
   local pname
   pname="$1${BCKSFX}"
   
   if [ ! -f "$1" ]; then
      echo "ERROR: File \"$1\" does not exist, unable to create patch"
      echo "    The patch for this file cannot be created automatically"
      exit 1
   fi
   
   if [ ! -f "${pname}" ]; then
      echo "ERROR: Original file \"${pname}\" does not exist for \"$1\", unable to create patch"
      echo "    The patch for this file cannot be created automatically"
      exit 1
   fi
   
   return 0
} # check-file



# Function to create a patch for a set of files
#
# The patch file is first truncated to zero if it already exists. Then all
# arguments starting with the 2nd one are used to create a patch hunk for the
# patch file. Each hunk is created as a context diff. It is expected that the
# file name itself denotes the new file, whereas the file name with the suffix
# ${BCKSFX} represents the original file. The patch is created so that the file
# with the raw name is created out of the one with the suffix.
#
# $1 - The file name for the patch file
# $2... - All arguments starting with $2 define file names to create a context
#         diff for. All these diffs are appended to the patch file.
#
create-patch()
{
   # memorize the patch file name
   local pname
   pname="$1"
   
   # truncate the patch file to zero length
   : > "${pname}"
   
   # walk through all remaining arguments to create the patch
   shift
   while [ -n "$1" ]; do
      diff -u "$1${BCKSFX}" "$1" >> "${pname}"
      shift
   done
   
   echo "Patch file \"${pname}\" created"
   
   return 0
} # create-patch



# Evaluate command line parameters
while [ -n "$1" ]; do
   case "$1" in
      *)        SRCBASE="$1"; shift ;;
   esac
done



# Determine the full operating system name
t=`grep ^TYPE= "${SRCBASE}/sys/conf/newvers.sh"`
r=`grep ^REVISION= "${SRCBASE}/sys/conf/newvers.sh"`
b=`grep ^BRANCH= "${SRCBASE}/sys/conf/newvers.sh"`
if [ -z "$t" -o -z "$r" -o -z "$b" ]; then
   echo "ERROR: Failed to extract TYPE, REVISION and BRANCH from \"${SRCBASE}/sys/conf/newvers.h\""
   exit 1
fi
eval $t
eval $r
eval $b
# If the BRANCH is "Current", it must be newer than "Release". So in this
# case we just use "=" as the last separator instead of "-" for RELEASE.
case "$BRANCH" in
   [Cc][Uu][Rr][Rr][Ee][Nn][Tt])
      OSNAME="${TYPE}-${REVISION}=${BRANCH}" ;;
   
   *)
      OSNAME="${TYPE}-${REVISION}-${BRANCH}" ;;
esac
   


# Automatic patch file creation is not supported for os below 5.0-RELEASE
if [ "${OSNAME}" \< "FreeBSD-5.0-RELEASE" ]; then
   echo "Automatic patch file creation not supported for \"${OSNAME}\""
   exit 1
fi



# All patches are created from the source tree base directory
echo "Start creating patches for source tree \"${SRCBASE}\" for \"${OSNAME}\""
cd "${SRCBASE}"



# Modifications of kernel sources and header files

# Patch /usr/src/sys/sys/endian.h to be compilable for C++
if [ ${OSNAME} = "FreeBSD-5.1-RELEASE" ]; then
   check-file sys/sys/endian.h
   create-patch "${PATCHDIR}/patch-sys-sys" sys/sys/endian.h
fi

# Extend i4b header files for c4b
check-file sys/i386/include/i4b_ioctl.h
create-patch "${PATCHDIR}/patch-sys-i386-include" sys/i386/include/i4b_ioctl.h

# Extend i4b layer 4 for c4b
check-file sys/i4b/layer4/i4b_l4mgmt.c
create-patch "${PATCHDIR}/patch-sys-i4b-layer4" sys/i4b/layer4/i4b_l4mgmt.c



# Modifications under /usr/src/usr.sbin

# Extend the isdnd for c4b
check-file usr.sbin/i4b/isdnd/controller.c
create-patch "${PATCHDIR}/patch-usr.sbin-i4b-isdnd" usr.sbin/i4b/isdnd/controller.c
