#!/bin/sh
#
# depgraph
# Morgan Deters, 27 October 2010
#
# Builds a graphviz graph of dependences between source and header files in CVC4.
#

progname=`basename "$0"`

postproc='sort -u'
mode=packages
target=

if [ $# -gt 0 ]; then
  if [ "$1" = "-a" ]; then
    postproc=cat
    mode=headers
    shift
  fi
  if [ $# -gt 0 -a "$1" != "-h" ]; then
    target="$1"
    shift
  fi
  if [ $# -gt 0 ]; then
    echo "usage: $progname [-a] [target]"
    echo "  -a ("all") produces _all_ headers in the source, with clusters for packages."
    echo "    the default behavior produces just package dependence information."
    echo "  with target, focus on dependences of that particular package (e.g. \"expr\")"
    exit 1
  fi
fi

cd "`dirname \"$0\"`/.."

if ! [ -d src -a -d test/unit ]; then
  echo "$progname: source directory malformed; is this CVC4 ?!" >&2
  exit 1
fi

echo "digraph G {"

paths=`find src -name '*.c' \
             -o -name '*.cc' \
             -o -name '*.cpp' \
             -o -name '*.C' \
             -o -name '*.h' \
             -o -name '*.hh' \
             -o -name '*.hpp' \
             -o -name '*.H' \
             -o -name '*.y' \
             -o -name '*.yy' \
             -o -name '*.ypp' \
             -o -name '*.Y' \
             -o -name '*.l' \
             -o -name '*.ll' \
             -o -name '*.lpp' \
             -o -name '*.L' \
             -o -name '*.g'`
if [ "$mode" = headers ]; then
  oldpackage=
  for path in $paths; do
    dir=`echo "$path" | sed 's,^\([^/]*\).*,\1,'`
    file=`echo "$path" | sed 's,^[^/]*/,,'`
    package=`echo "$file" | sed 's,^\(.*\)/.*,\1,'`
    file=`echo "$file" | sed 's,^.*/,,'`
    if [ -n "$target" -a "$target" != "$package" ]; then continue; fi
    if [ -n "$oldpackage" -a "$package" != "$oldpackage" ]; then
      echo '  }'
    fi
    if [ "$package" != "$oldpackage" ]; then
      echo "  subgraph \"cluster$package\" {"
      echo "    label=\"$package\";"
      oldpackage="$package"
    fi
    echo "    \"$package/$file\"[label=\"$file\"];"
  done
  if [ -n "$oldpackage" ]; then
    echo '  }'
  fi
fi
for path in $paths; do
    dir=`echo "$path" | sed 's,^\([^/]*\).*,\1,'`
    file=`echo "$path" | sed 's,^[^/]*/,,'`
    package=`echo "$file" | sed 's,^\(.*\)/.*,\1,'`
    file=`echo "$file" | sed 's,^.*/,,'`
    incs=`grep '^# *include *".*"' "$path" | sed 's,^# *include *"\(.*\)".*,\1,'`
    if [ -n "$target" -a "$target" != "$package" ]; then continue; fi
    for inc in $incs; do
      case "$inc" in
        base/tls.h) inc=base/tls.h.in ;;
        expr/expr.h) inc=expr/expr_template.h ;;
        expr/expr_manager.h) inc=expr/expr_manager_template.h ;;
        expr/kind.h) inc=expr/kind_template.h ;;
        expr/metakind.h) inc=expr/metakind_template.h ;;
        theory/theoryof_table.h) inc=theory/theoryof_table_template.h ;;
        util/integer.h) inc=util/integer.h.in ;;
        util/rational.h) inc=util/rational.h.in ;;
        cvc4autoconfig.h) inc=cvc4autoconfig.h.in ;;
      esac
      incpath=
      dirpackageparent="$dir/`dirname "$package"`"
      for incdir in "$dir" "$dir/include" "$dir/$package" . "$dirpackageparent"; do
        if [ -e "$incdir/$inc" ]; then incpath="$incdir/$inc"; break; fi
      done
      if [ -z "$incpath" ]; then
        echo "$progname: error: can't find include file '$inc' from source '$path'" >&2
        exit 1
      fi
      incpath=`echo "$incpath" | sed 's,^\./,,'`
      incpath=`echo "$incpath" | sed "s,^$dir/,,"`
      incdir=`echo "$incpath" | sed 's,^\([^/]*\).*,\1,'`
      incpackage=`echo "$incpath" | sed 's,^\(.*\)/.*,\1,'`
      incfile=`echo "$incpath" | sed 's,^.*/,,'`
      if [ "$mode" = packages ]; then
        if [ "$package" != "$incpackage" ]; then
          if [ -n "$target" ]; then
            echo "  \"$package\" -> \"$incpackage\"[label=\"$incfile\"];"
          else
            echo "  \"$package\" -> \"$incpackage\";"
          fi
        fi
      else
        if [ -n "$target" ]; then
          [ "$package" != "$incpackage" ] && echo "  \"$package/$file\" -> \"$incpackage\"[label=\"$incfile\"];"
        else
          echo "  \"$package/$file\" -> \"$incpath\";"
        fi
      fi
    done
  done | $postproc

echo "}"
