#!/bin/bash

HERE="$(dirname $0)"

declare -A tools

tools=(['arm']=arm-linux-gnueabihf-gcc)
tools+=(['aarch64']=aarch64-linux-gnu-gcc)
tools+=(['x86_64']=x86_64-linux-gnu-gcc)
tools+=(['i686']=i686-linux-gnu-gcc)

declare -A run

run=(['arm']=qemu-arm)
run+=(['aarch64']=qemu-aarch64)
run+=(['x86_64']=env)
run+=(['i686']=env)

declare -a arch
declare -a headers
declare -a structs

arch=(arm aarch64 x86_64 i686)
headers=(dirent errno fcntl ioctl mman poll resource signal syscall sysconf termios time wait)
structs=(fsid rlimit rlimit64 sigval siginfo winsize dirent64 itimerspec itimerval statfs statfs64 statx statx_timestamp termios timespec timeval timezone tms)

#arch=(x86_64)
#headers=()
#structs=(sigaction)

copyright() {
    cat <<\EOF
/*
 * SPDX-License-Identifier: BSD-3-Clause
 *
 * Copyright © 2026 Keith Packard
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials provided
 *    with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
EOF
}

wrap() {
    ARCH=$1
    HEADER=$2
    OUT=$3
    DIR=$(dirname ${OUT})
    mkdir -p $DIR
    CC="${tools[$ARCH]}"
    RUN="${run[$ARCH]}"
    UP=$(echo $HEADER | tr a-z A-Z)
    SOURCE="${HERE}"/make-${HEADER}.c
    EXEC=make-${HEADER}-${ARCH}

    echo "Building header $HEADER for $ARCH"

    "${CC}" -g ${SOURCE} -o ${EXEC} || exit 1
    (
    copyright
    
    DEF="_LINUX_${UP}_H_"
    echo "#ifndef ${DEF}"
    echo "#define ${DEF}"
    case "$HEADER" in
	errno|termios|signal|dirent|resource)
	    "${RUN}" ./${EXEC} || exit 1
	    ;;
	*)
	    "${RUN}" ./${EXEC} | sort -nk3 || exit 1
	    ;;
    esac
    rm "${EXEC}"
    echo "#endif /* ${DEF} */") > $OUT
    clang-format -i $OUT
}

wrap_struct() {
    ARCH=$1
    STRUCT=$2
    OUT=$3

    DIR=$(dirname ${OUT})
    mkdir -p $DIR
    CC="${tools[$ARCH]}"
    RUN="${run[$ARCH]}"

    UP=$(echo $STRUCT | tr a-z A-Z)
    JSON="${STRUCT}".json
    TYPE_HEADER="type-data.h"
    TYPE_OUT="type-results.h"
    TYPE_EXEC=make-type-${STRUCT}-${ARCH}
    STRUCT_HEADER="struct-data.h"
    STRUCT_EXEC=make-struct-${STRUCT}-${ARCH}

    echo "Building struct $STRUCT for $ARCH"

#    echo "$HERE"/make-struct "${HERE}"/"$JSON" --type="${TYPE_HEADER}" --struct="${STRUCT_HEADER}"
    "$HERE"/make-struct "${HERE}"/"$JSON" --type="${TYPE_HEADER}" --struct="${STRUCT_HEADER}" || exit 1

#    echo "${CC}" -g -I"${PWD}" "${HERE}"/type-analyze.c -o ${TYPE_EXEC}
    "${CC}" -g -D_FILE_OFFSET_BITS=64 -I"${PWD}" "${HERE}"/type-analyze.c -o ${TYPE_EXEC} || exit 1

#    echo "${RUN}" ./"${TYPE_EXEC}"
    "${RUN}" ./"${TYPE_EXEC}" > ${TYPE_OUT}

    rm "${TYPE_EXEC}"

#    echo "${CC}" -g -I"${PWD}" "${HERE}"/struct-analyze.c -o ${STRUCT_EXEC}
    "${CC}" -g -D_FILE_OFFSET_BITS=64 -I"${PWD}" "${HERE}"/struct-analyze.c -o ${STRUCT_EXEC} || exit 1
    (
    copyright
    
    DEF="_LINUX_${UP}_STRUCT_H_"
    echo
    echo "#ifndef ${DEF}"
    echo "#define ${DEF}"
    echo
    "${RUN}" ./${STRUCT_EXEC} ${TYPE_OUT} || exit 1
    rm "${STRUCT_EXEC}"
    rm "${TYPE_OUT}"
    echo
    echo "#endif /* ${DEF} */") > $OUT
    clang-format -i $OUT
}

make_x86() {
    NAME=$1
    OUT="machine/x86/linux/$BASE"
    (
	copyright
	echo "#ifdef __x86_64"
	echo "#include "'"'"../../x86_64/linux/${BASE}"'"'
	echo "#else"
	echo "#include "'"'"../../i686/linux/${BASE}"'"'
	echo "#endif") > "$OUT"
    clang-format -i "$OUT"
}


for s in "${structs[@]}"; do
    BASE="linux-$s-struct.h"
    for a in "${arch[@]}"; do
	OUT="machine/$a/linux/$BASE"
	wrap_struct $a $s $OUT || exit 1
    done
    make_x86 "${BASE}"
done

for h in "${headers[@]}"; do
    BASE=linux-$h.h
    for a in "${arch[@]}"; do
	OUT="machine/$a/linux/$BASE"
	wrap $a $h $OUT || exit 1
    done
    make_x86 "${BASE}"
done
