#!/bin/bash

SRC_DIR=~/src/glibc/

pushd $SRC_DIR &> /dev/null \
|| { echo Unable to enter directory $SRC_DIR 1>&2; exit 1; }

let blkl=0
let good=0
let main=0
let spln=0
let incl=0
let sedf=0
let fixd=0

for f in $(find . -regex '.*t[e]?st-.*\.c'); do

  # Ignore tests that are known to break upon making this change.
  blacklist=()
  blacklist+=("./stdlib/tst-bsearch.c") # 'struct entry' conflicts with search.h
  blacklist+=("./elf/tst-initorder2.c") # conditionally compiled based on -DNAME
  blacklist+=("./elf/tst-array4.c") # sets up .fini_array causing spurious output
                                    # from the skeleton's parent process
  blacklist+=("./libio/tst-fopenloc.c") # fails with skeleton due to fputws bug
  blacklist+=("./nptl/tst-fini1.c") # defines a destructor that causes a SIGSEGV
                                    # on the skeletons' parent process
  blacklist+=("./sysdeps/pthread/tst-timer.c") # killed by skeleton's timeout
  blacklist+=("./stdio-common/tst-fseek.c") # killed by skeleton's timeout
  blacklist+=("./stdlib/gen-tst-strtod-round.c") # tst-strtod-round's generator

  if grep -q $f <(echo "${blacklist[@]}"); then
    echo BLKL: $f 1>&2
    let blkl+=1
    continue
  fi

  # Ignore tests that already use the skeleton:
  if grep -q 'include.*test-skeleton\.c' $f; then
    echo GOOD: $f
    let good+=1
    continue
  fi

  # Report tests that do not have a 'main' function as broken;
  # we cannot generate code to fix them:
  if ! grep -Pzq 'int\s+main\s*\(\s*void\s*\)\s*{' $f; then
    echo MAIN: $f 1>&2
    let main+=1
    continue
  fi

  # Now that we have a sane test that does not use the skeleton,
  # we want to do three things:
  #
  # 1. Change 'int main (void)' to 'static int do_test (void)';
  # 2. Define 'TEST_FUNCTION' as 'do_test ()';
  # 3. Include test-skeleton.c.
  #
  # But first, we want to make sure of a few more things:

  special_names=()

  # The test file doesn't already use names we will add to it:
  special_names+=("do_test" "TEST_FUNCTION" "PREPARE")

  # The test doesn't do special things that might interfere with
  # the set-up done by the skeleton, causing spurious PASS in future:
  special_names+=("kill\s*\(" "signal\s*\(" "sigaction\s*\(" "mallopt\s*\(" \
    "setbuf\s*\(" "setvbuf\s*\(" "atexit\s*\(" "fork\s*\(" "setrlimit\s*\(" \
    "alarm\s*\(")

  for n in ${special_names[@]}; do
    if grep -Pzq "$n" $f; then
      echo SPLN: "($n)" $f 1>&2
      let spln+=1
      continue 2
    fi
  done

  # The test file isn't being #include'ed in another test:
  if grep -qrI "#\s*include.*$(basename $f)" $(dirname $f); then
    echo INCL: $f 1>&2
    let incl+=1
    continue
  fi

  # Finally, we can try and apply the fix:
  sed -i '/int/{$!{N;s/int[\s\n]\+main\s*(\s*void\s*)/static int\ndo_test (void)/;ty;P;D;:y}}' $f
  # HINT: sed magic comes from here: http://unix.stackexchange.com/a/26290

  # If unfortunately, sed does not succeed, we report it and move on:
  if ! grep -Pzq 'static\sint\sdo_test\s\(void\)' $f; then
    echo SEDF: $f 1>&2
    let sedf+=1
    continue
  fi

  # We want './sysdeps/x86_64/tst-audit10.c' to include '../../test-skeleton.c':
  prefix=$(echo $f | sed 's|^./||' | sed 's|[^/]||g' | sed 's|/|../|g')
  echo -e "\n#define TEST_FUNCTION do_test ()\n#include \"${prefix}test-skeleton.c\"" >> $f

  echo FIXD: $f
  let fixd+=1
done

echo Total BLKL: $blkl 1>&2
echo Total GOOD: $good
echo Total MAIN: $main 1>&2
echo Total SPLN: $spln 1>&2
echo Total INCL: $incl 1>&2
echo Total SEDF: $sedf 1>&2
echo Total FIXD: $fixd
echo '----------  ---'
echo Total TEST: $((blkl+good+main+spln+incl+sedf+fixd))