#!/bin/sh -f
# USB.h contains #pragma's that are not compatible with GCC on MacOS through 10.14
# patch this file if found to provide the correct #pragma for the correct compiler

DIFF=${DIFF:-/usr/bin/diff}
ECHO=${ECHO:-/bin/echo}
GREP=${GREP:-/usr/bin/grep}
HEAD=${HEAD:-/usr/bin/head}
MKDIR=${MKDIR:-/bin/mkdir}
RM=${RM:-/bin/rm}
SED=${SED:-/usr/bin/sed}
WC=${WC:-/usr/bin/wc}

HEADER_FILE="USB.h"
FRAMEWORK_HEADER_DIR="IOKit/usb"
DESTDIR=${DESTDIR:-"include"}

# remove trailing '/' from DESTDIR, if it exists
DESTDIR=$(${ECHO} "${DESTDIR}" | ${SED} -e "s@/\$@@") 

# create the destination directory and new file with path to it
FILE_DIR="${DESTDIR}/${FRAMEWORK_HEADER_DIR}"
NEW_USB_H_FILE="${FILE_DIR}/${HEADER_FILE}"

# just in case SED needs these ...
LANG=C
LC_CTYPE=C
LC_ALL=C

# if "xcode-select" exists, then use it to find the current developer path
XCODE_SELECT=$(which xcode-select)
if [ -z "${XCODE_SELECT}" ]; then
    # does not exist, which happens in Xcode for 10.4; assume default install
    DEV_DIR=/Developer
else
    DEV_DIR=$(${XCODE_SELECT} -print-path)
fi

PLATFORM=$(uname -r | sed -ne 's/\([0-9][0-9]*\)\..*/\1/p')
MACOS_MINOR=$(expr ${PLATFORM} - 4)
echo "MACOS_MINOR is '${MACOS_MINOR}'"
MACOS_MAJOR=10
if [ "${MACOS_MINOR}" == "16" ]; then
    MACOS_MAJOR=11
fi
echo "MACOS_MAJOR is '${MACOS_MAJOR}"
MACOS_MAJOR_MINOR=${MACOS_MAJOR}.${MACOS_MINOR}
echo "MACOS_MAJOR_MINOR 1 is '${MACOS_MAJOR_MINOR}"
# special for 10.4 ... use "10.4u"
if [ "${MACOS_MINOR}" == "4" ]; then
    MACOS_MAJOR_MINOR=${MACOS_MAJOR_MINOR}u
fi
echo "MACOS_MAJOR_MINOR 2 is '${MACOS_MAJOR_MINOR}"

# find the SDK directory
# typically either $(DEV_DIR)/SDKs or $(DEV_DIR)/Platforms/MacOSX.platform/Developer/SDKs
SDK_PARENT_DIR="${DEV_DIR}/SDKs"
if [ ! -d "${SDK_PARENT_DIR}" ]; then
    SDK_PARENT_DIR="${DEV_DIR}/Platforms/MacOSX.platform/Developer/SDKs"
    if [ ! -d "${SDK_PARENT_DIR}" ]; then
	echo "Unable to find parent SDK directory"
	exit -1
    fi
fi
echo "Found SDK parent directory '${SDK_PARENT_DIR}'"

# find the correct SDK within DEV_DIR_2
# typically either $(SDK_PARENT_DIR)/MacOS$(MACOS_MAJOR_MINOR).sdk
# or $(SDK_PARENT_DIR)/MacOS.sdk for more recent MacOS
SDK_DIR="${SDK_PARENT_DIR}/MacOSX.sdk"
if [ ! -d "${SDK_DIR}" ]; then
    SDK_DIR="${SDK_PARENT_DIR}/MacOSX${MACOS_MAJOR_MINOR}.sdk"
    if [ ! -d "${SDK_DIR}" ]; then
	echo "Unable to find MacOSX SDK directory"
	exit -2
    fi
fi
echo "Found SDK directory '${SDK_DIR}'"

# make sure the header exists; it should -always- be
# $(SDK_DIR)/System/Library/Frameworks/IOKit.framework/Headers/usb/USB.h 
USB_H_FILE="${SDK_DIR}/System/Library/Frameworks/IOKit.framework/Headers/usb/USB.h"
if [ ! -f "${USB_H_FILE}" ]; then
    echo "Unable to find header '${HEADER_FILE}'"
    exit -3
fi
echo "Found USB header file as '${USB_H_FILE}'"

# we have the file; check to see if it needs patching
HAS_PRAGMAS=$(${GREP} -E "^#pragma options align=reset" "${USB_H_FILE}")
if [ -z "${HAS_PRAGMAS}" ]; then
    echo "IOKit '${HEADER_FILE}' header seems to not contain the faulty #pragma directives"
    exit 0
fi

# yes: needs patching

# if the file exists, delete it
if [ -f "${NEW_USB_H_FILE}" ]; then
    echo "File '${NEW_USB_H_FILE}' exists; deleting it."
    ${RM} "${NEW_USB_H_FILE}"
else
    # make the destination directory, if it doesn't exist
    if [ ! -d "${FILE_DIR}" ]; then
	echo "Making patched USB header directory '${FILE_DIR}'"
	$(${MKDIR} -p "${FILE_DIR}")
    fi
fi

# create the patched version of the header
echo "Creating patched '${HEADER_FILE}' header file"
$(${SED} -e "s@^#pragma options align=reset@#if defined(__clang__) || defined(__llvm__)\\
    #pragma options align=reset\\
#else\\
    #pragma pack()\\
#endif@g" < "${USB_H_FILE}" > "${NEW_USB_H_FILE}")

# verify patched version as best we can
# (1) verify file exists
if [ ! -f "${NEW_USB_H_FILE}" ]; then
    echo "File '${NEW_USB_H_FILE}' not created!"
    exit -4
fi
echo "Found created file '${NEW_USB_H_FILE}'; verifying changes."

# (2) looking at the "diff", make sure the ratio of lines starting with '-' to those starting with '+' is 1:5
WC_MINUS_DIFF=$(${DIFF} -u "${USB_H_FILE}" "${NEW_USB_H_FILE}" | ${GREP} -E "^-" | ${GREP} -vE "^---" | ${WC} -l | ${SED} -e "s/^[ \t]*//")
WC_PLUS_DIFF=$(${DIFF} -u "${USB_H_FILE}" "${NEW_USB_H_FILE}" | ${GREP} -E "^\\+" | ${GREP} -vE "^\\+\\+\\+" | ${WC} -l | ${SED} -e "s/^[ \t]*//")
WC_MINUS_DIFF_TIMES_5=$(expr ${WC_MINUS_DIFF} * 5)
if [ "${WC_MINUS_DIFF_TIMES_5}" != "${WC_PLUS_DIFF}" ]; then
    echo "Number of '#pragma' changes isn't 1:5 from original; new header might not work as desired."
    exit -5
fi
echo "Found correct ratio of '#pragma' changes; verifying first."
# compare just the first entry
GREP_OPTIONS_1=$(${GREP} "\#pragma options" "${NEW_USB_H_FILE}" | ${HEAD} -1)
if [ "${GREP_OPTIONS_1}" != "    #pragma options align=reset" ]; then
    echo "Pragma changes do not seem correct; expecting '    #pragma options align=reset' but got '${GREP_OPTIONS_1}'"
    exit -6
fi

# success
echo "Success!"
exit 0
