Skip to content
Snippets Groups Projects
check-headers.sh 6.82 KiB
#!/bin/sh
##########################################################################
#                                                                        #
#  This file is part of Frama-C.                                         #
#                                                                        #
#  Copyright (C) 2007-2020                                               #
#    CEA (Commissariat à l'énergie atomique et aux énergies              #
#         alternatives)                                                  #
#                                                                        #
#  All rights reserved.                                                  #
#  Contact CEA LIST for licensing.                                       #
#                                                                        #
##########################################################################


APPLINAME="$0"
echo $0 $@
Usage() {
  APPLI=$(basename $APPLINAME)
  echo "Usage: $APPLI <options> <files>"
  echo "  $APPLI [--update] --spec-files <spec-files>"
  echo "    1. Checks entries of <spec-files>"
  echo "    --update: updates <spec-files> by removing comments and multiple entries"
  echo "  $APPLI [--update] [--no-headers <header-file>]* <spec-file> ([--files-from] <file>]*"
  echo "    1. Checks entries of <spec-file>"
  echo "    --update: updates <spec-file> by removing comments and multiple entries"
  echo "    2. Checks that every <files> have an entry into the <spec-file>"
  echo "    3. Checks that all the <files> are not attributed to <header-file> in <spec-file>"
  echo "    --no-headers <header-file>: cumulative option"
  exit 0
}

Requires () {
  for File in "$@" 
  do
    where=$(which $File)
    if [ "$?" != "0" ] ; then
      echo "Error: executable not found: $File"
      exit 1
    fi
  done
}

RegExp=""
Checking () {

  Requires sort tr grep diff sed

  if [ "$SpecFilesOpt" != "" ] &&  [ "$HeadersOpt" != "" ] ; then
    echo "Error: given options are exclusives"
    exit 1
  fi

  if [ "$1" = "" ] ; then
    echo "Error: missing argument"
    exit 1
  fi

  if [ ! -f "$1" ] ; then
    echo "Error: file not found: $file"
    exit 1
  fi

  if [ "$SpecFilesOpt" != "" ] ; then
    shift
    for file in $@ ; do
       if [ "$file" != "--files-from" ] && [ ! -f $file ] ; then
          echo "Error: file not found: $file"
        exit 1
       fi
    done
  fi

  if [ "$HeadersOpt" != "" ] ; then
    RegExp="("
    for file in $HeadersOpt ; do
      SyntaxOk=$(echo "$file" | tr -d "._[:alnum:]")
      if [ "$SyntaxOk" != "" ] ; then
        echo "Error: invalid header filename: $file"
        exit 1
      fi
      if [ "$RegExp" != "(" ] ; then
        RegExp="${RegExp}|"
      fi
      RegExp="${RegExp}$(echo $file | sed -e 's:\.:\\.:')"
    done
      RegExp="^${RegExp}):"
  fi
}

Result="0"
Check () {
  Warn=""
  cat $1 \
    | tr "[:blank:]" " " \
    | sed -e 's:  *: :g' \
    | sed -e 's:^ ::g' \
    | sed -e 's: $::g' \
    | sed -e 's/ :/:/g' \
    | sed -e 's/:\([^ ]\)/: \1/g' \
    > $1.$$
  TMP1=$1.$$
  if [ "$?" != "0" ] && [ "$2" = "-step-1" ] ; then
    echo "  Warning: some blank characters can be cleaned:"
    diff $1 $TMP1 | grep "^> "
    Warn="Ok"
  fi
  grep -v "^#" $TMP1 > ${TMP1}.$$
  TMP2=${TMP1}.$$
  LC_ALL=C sort -k2 -k1 $TMP2 > $TMP1
  diff -q $TMP1 $TMP2 > /dev/null
  if [ "$?" != "0" ] && [ "$2" = "-step-1" ] ; then
    echo "  Warning: some entries are unsorted:"
    diff $TMP1 $TMP2 | grep "^> "
    Warn="Ok"
  fi
  LC_ALL=C sort -u -k2 -k1 $TMP1 > $TMP2
  diff -q $TMP2 $TMP1 > /dev/null
  if [ "$?" != "0" ] ; then
    if [ "$2" = "-step-1" ] ; then
      echo "  Warning: some entries are duplicated:"
    else
      echo "  Warning: the following given files are duplicated:"
    fi
    diff $TMP2 $TMP1 | sed -n -e "s/^> ~no-entry-for:/  /p"
    Warn="Ok"
  fi
  LC_ALL=C sort -u -k2 $TMP2 > $TMP1
  if [ "$3" != "" ] ; then
    diff $TMP1 $3 > /dev/null
    if [ "$?" != "0" ] ; then
      echo "  Error: some files have no entry:"
      diff $3 $TMP1 |  sed -n -e "s/^> ~no-entry-for:/  /p"
      Warn="OkOk"
      Result="1"
    fi
  else
    diff -q $TMP1 $TMP2 > /dev/null
    if [ "$?" != "0" ] ; then
      if [ "$2" = "-step-1" ] ; then
        echo "  Error: some entries are duplicated."
        echo "  removed entries:"
      else
        echo "  Error: some checked entries have unwanted headers:"
      fi
      diff $TMP1 $TMP2 | grep "^> "
      Warn="OkOk"
      Result="1"
    fi
  fi
}

CheckSpecFile () {
  echo " Checking specification file $1..."
  Check "$1" "-step-1"
  if [ "$Warn" = "OkOk" ] ; then
    if [ "$UpdateOpt" != "--update" ] ; then
      rm $TMP1 $TMP2 
      echo " Use --update option to update $1 file"
      exit 1
    fi
  fi
  if [ "$UpdateOpt" = "--update" ] ; then
    if [ "$Warn" = "" ] ; then
      diff -q $TMP1 $1 > /dev/null
      if [ "$?" != "0" ] ; then
         Warn="Ok"
      fi
    fi
    if [ "$Warn" = "" ] ; then
       echo "Warning: already up to date"
    else
       echo " Updating file $1"
       mv $TMP1 $1
    fi
  fi
}

UpdateOpt=""
HeadersOpt=""
SpecFilesOpt=""
while [ "$1" != "" ] ; do
  case "$1" in
    -h)     Usage;;
    -help)  Usage;;
    --help) Usage;;
    --update) UpdateOpt="$1";;
    --spec-files) SpecFilesOpt="$1";;
    --no-headers) shift; HeadersOpt="${Headers} $1";;
    --files-from) break;;
    --*) echo "Unknown option $1"; exit 1;;
    *) break;;
  esac
  shift
done

Checking $@

BuildTmpFile() {
  TmpFile="$1"
  shift
  Str="$1"
  shift
  while [ "$1" != "" ]; do
    if [ "$1" = "--files-from" ] ; then
      shift
      cat $1 \
        | tr "[:blank:]" " " \
        | sed -e 's:  *: :g' \
        | sed -e 's:^ ::g' \
        | sed -e 's: $::g' \
        | egrep -v '^#' \
        | sed -e "s#^#${Str}: #" >> $TMP
      else
        echo "${Str}: $1" >> $TMP
      fi
    shift
  done
}

if [ "$SpecFilesOpt" = "" ] ; then
#  echo "Step 1..."
  SpecFile=$1
  shift
  CheckSpecFile $SpecFile
#  echo " Removing temporary files"
  mv $TMP2 $TMP1
  RefStep2=$TMP1

  if [ "$1" != "" ]; then
#    echo "Step 2..."
    echo " Checking that all given files have an entry..."
    cat $RefStep2 > $RefStep2.$$
    TMP=$RefStep2.$$
    BuildTmpFile $TMP "~no-entry-for" $@
    Check $TMP "-step-2" $RefStep2
#    echo " Removing temporary files"
    rm -f $TMP $TMP1 $TMP2 
  fi
  rm -f $RefStep2

  if [ "$RegExp" != "" ] && [ "$1" != "" ]; then
#    echo "Step 3..."
    echo " Checking for files having unwanted headers..." 
    egrep -e "$RegExp" $SpecFile > $SpecFile.$$
    TMP=$SpecFile.$$
    BuildTmpFile $TMP "./looking-for" $@
    Check $TMP "-step-3"
#    echo " Removing temporary files"
    rm -f $TMP $TMP1 $TMP2 
  fi

  if test $Result -eq 0; then
    echo "No issue detected. Great!"
  fi
  exit $Result

else
#  echo "Step 1..."
  for file in $@ ; do
    CheckSpecFile $file
#    echo " Removing temporary files"
    rm -f $TMP1 $TMP2 
  done
fi