#!/bin/bash
##   BISMON  ---- simple analysis of the Msh shell
##   Copyright ©  2021 CEA (Commissariat à l'énergie atomique et aux énergies alternatives)
##   contributed by Basile Starynkevitch (working at CEA, LIST, France)
##   <basile@starynkevitch.net> or <basile.starynkevitch@cea.fr>
##
##   This program is free software: you can redistribute it and/or modify
##   it under the terms of the GNU General Public License as published by
##   the Free Software Foundation, either version 3 of the License, or
##   (at your option) any later version.
##
##   This program is distributed in the hope that it will be useful,
##   but WITHOUT ANY WARRANTY; without even the implied warranty of
##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##   GNU General Public License for more details.
##
##   You should have received a copy of the GNU General Public License
##   along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##   ----
##   Contact me (Basile Starynkevitch) by email
##   basile@starynkevitch.net and/or basile.starynkevitch@cea.fr
##   -----------

## The Msh shell is a tiny shell whose source code is downloadable
## from git@github.com:nerith/msh.git
## it requires some editline library (NOT from github.com/troglobit/editline)

#######
## to debug this script, consider using :
##    ./Msh-Analyze --bismon-debug-after-load --asm --bismon-web-base=localhost:8086
## or the equivalent
##    ./Msh-Analyze --bismon-debug-after-load --asm --bismon-web-base=_
#######
## the default source location of Msh could be overidden by the
## BISMON_MSH_SOURCE environment variable
if [ -z "$BISMON_MSH_SOURCE" ]; then
    export BISMON_MSH_SOURCE=/usr/src/Shell/msh/
fi


## BISMON_GCC is the GCC compiler compiling Bismon
if [ -z "$BISMON_GCC" ]; then
    export BISMON_GCC=/usr/bin/gcc-10
fi

## BISMON_WEB_BASE is for the URL interfacing Bismon while it is running
if [ -z "$BISMON_WEB_BASE" ]; then
    export BISMON_WEB_BASE=localhost:8086
fi

## BISMON_MSH_PROJECT is the name of the project for Msh, as known to Bismon
## and to GCC metaplugins
if [ -z "$BISMON_MSH_PROJECT" ]; then
    export BISMON_MSH_PROJECT=msh_bismon_project
fi


## if given, BISMON_COOKIE_FILE would contain the HTTP cookie
if [ -z "$BISMON_COOKIE_FILE" ]; then
    export BISMON_COOKIE_FILE=/tmp/bismon_msh_{$$}_cookie
fi

## BISMON_MSH_SOURCE should contain a git clone of
## git@github.com:nerith/msh.git
if [ ! -d "$BISMON_MSH_SOURCE" ]; then
    printf "%s: invalid MSH source directory for Bismon %s\n" "$0" "$BISMON_MSH_SOURCE" > /dev/stderr
    exit 1
fi

## BISMON_GCC_PLUGIN is the shared object for our plugin
if [ -z "$BISMON_GCC_PLUGIN" ]; then
    export BISMON_GCC_PLUGIN=$(realpath gccplugins/gcc10_metaplugin_BMGCC.so)
fi


################################################################
### checking that BISMON_MSH_SOURCE is valid.....
if [ ! -f "$BISMON_MSH_SOURCE/src/builtins.c" ]; then
    printf "%s: invalid MSH source for Bismon %s without src/builtins.c\n" "$0" "$BISMON_MSH_SOURCE" > /dev/stderr
    exit 1
fi

if [ ! -f "$BISMON_MSH_SOURCE/src/shellFunctions.c" ]; then
    printf "%s: invalid MSH source for Bismon %s without src/shellFunctions.c\n" "$0" "$BISMON_MSH_SOURCE" > /dev/stderr
    exit 1
fi


if [ ! -f "$BISMON_MSH_SOURCE/include/shellFunctions.h" ]; then
    printf "%s: invalid MSH source for Bismon %s without include/shellFunctions.h\n" "$0" "$BISMON_MSH_SOURCE" > /dev/stderr
    exit 1
fi


################################################################
### build bismon if it does not exist, and check that it was built and
### newer than source files
if [ ! -x bismon ]; then
    ./Build
fi

if [ ! -x bismon ]; then
    printf "%s: missing bismon executable in %s\n" "$0" $(pwd) > /dev/stderr
    exit 1
fi


for f in *.[ch] ; do
    if [ "$f" -nt bismon ]; then
	printf "%s: source file %s newer than bismon executable in %s\n" "$0" "$f" $(pwd) > /dev/stderr
	printf "... consider running the Build script in %s\n" $(pwd) > /dev/stderr
	exit 1
    fi
done

declare -a bismon_msh_args

for f in "$@"; do
    case "$f" in
	--bismon*) bismon_msh_args=($bismon_msh_args $f);;
	--msh-source=*) export BISMON_MSH_SOURCE=$(echo $f | /bin/sed -e s/--msh-source=//);;
	--asm) export BISMON_PLUGIN_ASMOUT=/tmp/gcc10_metaplugin_BMGCC.s;;
	--gcc=*) export BISMON_GCC=$(echo $f | /bin/sed -e s/--gcc=//);;
    esac
done

# https://serverfault.com/a/477506
if [ ${#bismon_msh_args[@]} -eq 0 ]; then
    bismon_msh_args=( --bismon-web-base=$BISMON_WEB_BASE --bismon-project-name=$BISMON_MSH_PROJECT --bismon-pid-file=/tmp/_bismon_msh.pid )
fi

echo "$0:" bismon arguments $bismon_msh_args in $(pwd) > /dev/stderr

echo "$0:" msh source $BISMON_MSH_SOURCE > /dev/stderr



#### check existence of needed files

if [ ! -d gccplugins/ ]; then
    echo "$0:" missing gccplugins/ directory in $(pwd) > /dev/stderr
    exit 1
fi

if [ ! -f gccplugins/gcc10_metaplugin_BMGCC.cc ]; then
    echo  "$0:" missing gccplugins/gcc10_metaplugin_BMGCC.cc in $(pwd) > /dev/stderr
    exit 1
fi

if [ ! -f gccplugins/gcc10_metaplugin_BMGCC.hh ]; then
    echo  "$0:" missing gccplugins/gcc10_metaplugin_BMGCC.hh in $(pwd) > /dev/stderr
    exit 1
fi

if [ ! -x gccplugins/build-gcc10-metaplugin.sh ]; then
    echo  "$0:" missing or bad gccplugins/build-gcc10-metaplugin.sh script in $(pwd) > /dev/stderr
    exit 1
fi


### notice that the ./build-gcc10-metaplugin.sh may use the
### BISMON_PLUGIN_ASMOUT environment variable. For example, set it
### with export BISMON_PLUGIN_ASMOUT=/tmp/gcc10_metaplugin_BMGCC.s

### on some Debian, there is a bug: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=980609
pushd gccplugins
### Notice: the build-gcc10-metaplugin.sh script cares about a BISMON_PLUGIN_ASMOUT shell variable...
./build-gcc10-metaplugin.sh
popd 

if [ ! -f "$BISMON_GCC_PLUGIN" ]; then
    printf "%s: missing GCC plugin for Bismon (maybe set %s shell variable)\n" "$0" 'BISMON_GCC_PLUGIN' > /dev/stderr
    exit 1
fi

export BISMON_GCC_NAME_PLUGIN=$(basename "$BISMON_GCC_PLUGIN" .so)

## kill any running bismon
pkill --exact --full --signal=SIGTERM bismon || true

printf "\n\n\n ==== %s: starting Bismon ======\n\n" "$0"
echo '#° ./bismon' $bismon_msh_args
## start a fresh bismon
./bismon $bismon_msh_args &

export BISMON_PID=$!

sleep 0.8

printf "\n%s: Bismon pid is %s\n" $0 $BISMON_PID

ps $BISMON_PID

sleep 0.2

for src in $BISMON_MSH_SOURCE/src/*.c ; do
    sleep 0.2
    printf "\n\n%s: **** compiling %s ****\n" $0 $src
    ## plugin arguments should be passed with -fplugin-arg-$BISMON_GCC_NAME_PLUGIN-<argname>
    echo "#§ " $BISMON_GCC -v -fplugin="$BISMON_GCC_PLUGIN" \
	 -fplugin-arg-$BISMON_GCC_NAME_PLUGIN-bismon-url=$BISMON_WEB_BASE \
	 -fplugin-arg-$BISMON_GCC_NAME_PLUGIN-bismon-pid=$BISMON_PID \
	 -fplugin-arg-$BISMON_GCC_NAME_PLUGIN-bismon-project=$BISMON_MSH_PROJECT \
	 -Wall -Wextra  -std=gnu11 -g -O -c -c -I$BISMON_MSH_SOURCE  $src
    time $BISMON_GCC -v -fplugin="$BISMON_GCC_PLUGIN" \
	 -fplugin-arg-$BISMON_GCC_NAME_PLUGIN-bismon-url=$BISMON_WEB_BASE \
	 -fplugin-arg-$BISMON_GCC_NAME_PLUGIN-bismon-pid=$BISMON_PID \
	 -fplugin-arg-$BISMON_GCC_NAME_PLUGIN-bismon-project=$BISMON_MSH_PROJECT \
	 -Wall -Wextra  -std=gnu11 -g -O -c -c -I$BISMON_MSH_SOURCE  $src
    if [ $? -gt 0 ]; then
	printf "\n%s: failed to compile %s with BISMON_GCC=%s\n" $0 $src $BISMON_GCC > /dev/stderr
	exit 1
    fi
    echo
    sleep 0.1
done

sleep 0.3

ps -l -p $BISMON_PID

kill -TERM $BISMON_PID

sleep 0.1

printf "\n%s: *** ended successfully ***\n\n" $0 
########################################
