##############################################################################
#
# Copyright Iowa State University 2009-2010.
#
# Permission is hereby granted, free of charge, to any person or organization
# obtaining a copy of the software and accompanying documentation covered by
# this license (the "Software") to use, reproduce, display, distribute,
# execute, and transmit the Software, and to prepare derivative works of the
# Software, and to permit third-parties to whom the Software is furnished to
# do so, all subject to the following:
#
# The copyright notices in the Software and this entire statement, including
# the above license grant, this restriction and the following disclaimer,
# must be included in all copies of the Software, in whole or in part, and
# all derivative works of the Software, unless such copies or derivative
# works are solely in the form of machine-executable object code generated by
# a source language processor.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
# SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
# FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
##############################################################################

# Try to find the Cppcheck tool.
#
# Cache variables:
#
#   CPPCHECK_EXECUTABLE
#
# Non-cache variables you might use in your CMakeLists.txt:
#
#   CPPCHECK_FOUND
#   CPPCHECK_UNUSEDFUNC_ARG
#   CPPCHECK_STYLE_ARG
#   CPPCHECK_QUIET_ARG
#   CPPCHECK_INCLUDEPATH_ARG
#   CPPCHECK_FAIL_REGULAR_EXPRESSION
#   CPPCHECK_WARN_REGULAR_EXPRESSION
#   CPPCHECK_MARK_AS_ADVANCED - whether to mark our variables as advanced even
#                               if we do not find this program.
#
# Requires these CMake modules:
#
#   FindPackageHandleStandardArgs (known to be included with CMake >= 2.6.2)
#
# Original author:
#
#   Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
#   http://academic.cleardefinition.com
#   Iowa State University HCI Graduate Program/VRAC

file( TO_CMAKE_PATH "${CPPCHECK_ROOT_DIR}" CPPCHECK_ROOT_DIR )
set( CPPCHECK_ROOT_DIR
  "${CPPCHECK_ROOT_DIR}"
  CACHE
  PATH
  "Path to search for Cppcheck" )
mark_as_advanced( CPPCHECK_ROOT_DIR )

# cppcheck app bundles on Mac OS X are GUI, we want command line only
set( _oldappbundlesetting ${CMAKE_FIND_APPBUNDLE} )
set( CMAKE_FIND_APPBUNDLE NEVER )

# If we have a custom path, look there first.
if( CPPCHECK_ROOT_DIR )
  find_program( CPPCHECK_EXECUTABLE
    NAMES
      cppcheck
      cli
    PATHS
      "${CPPCHECK_ROOT_DIR}"
    PATH_SUFFIXES
      cli
    NO_DEFAULT_PATH )
endif( CPPCHECK_ROOT_DIR )

find_program( CPPCHECK_EXECUTABLE NAMES cppcheck )

# Restore original setting for appbundle finding
set( CMAKE_FIND_APPBUNDLE ${_oldappbundlesetting} )

if( CPPCHECK_EXECUTABLE )
  # Find out where our test file is
  get_filename_component( _cppcheckmoddir ${CMAKE_CURRENT_LIST_FILE} PATH )
  set( _cppcheckdummyfile "${_cppcheckmoddir}/FindCppcheck.cxx" )

  # common to all version of cppcheck
  set( CPPCHECK_QUIET_ARG --quiet )
  set( CPPCHECK_FORCE_ARG --force )
  set( CPPCHECK_VERBOSE_ARG --verbose )
  set( CPPCHECK_INCLUDEPATH_ARG -I )
  set( CPPCHECK_DEFINITION_ARG -D )
  set( CPPCHECK_ALL_ARG --enable=all )

  # Check for the two types of command line arguments by just trying them
  execute_process( COMMAND
      ${CPPCHECK_EXECUTABLE}
      --enable=style
      ${CPPCHECK_QUIET_ARG}
      ${_cppcheckdummyfile}
    RESULT_VARIABLE
      _cppcheck_enable_style_result
    OUTPUT_QUIET
    ERROR_QUIET )

  if( "${_cppcheck_enable_style_result}" EQUAL 0 )
    set( CPPCHECK_STYLE_ARG --enable=style )

    # How to display errors and warnings:
    if( MSVC )
      set( CPPCHECK_TEMPLATE_ARG --template vs )
      set( CPPCHECK_FAIL_REGULAR_EXPRESSION "[(]error[)]" )
      set( CPPCHECK_WARN_REGULAR_EXPRESSION "[(]style[)]" )
    elseif( CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
      set( CPPCHECK_TEMPLATE_ARG --template gcc )
      set( CPPCHECK_FAIL_REGULAR_EXPRESSION " error: " )
      set( CPPCHECK_WARN_REGULAR_EXPRESSION " style: " )
    else( MSVC )
      message( STATUS
        "Warning: FindCppcheck does not know how to format error messages for your compiler." )
      set( CPPCHECK_TEMPLATE_ARG --template gcc )
      set( CPPCHECK_FAIL_REGULAR_EXPRESSION " error: " )
      set( CPPCHECK_WARN_REGULAR_EXPRESSION " style: " )
    endif( MSVC )
  else( "${_cppcheck_enable_style_result}" EQUAL 0 )
    message( "This file supports only version of Cppcheck is newer than 1.43." )
  endif( "${_cppcheck_enable_style_result}" EQUAL 0 )

  execute_process( COMMAND
      ${CPPCHECK_EXECUTABLE}
      --enable=unusedFunctions
      --check-config
      ${CPPCHECK_QUIET_ARG}
      ${_cppcheckdummyfile}
    RESULT_VARIABLE
      _cppcheck_enable_unused_functions_results
    OUTPUT_QUIET
    ERROR_QUIET )

  if( "${_cppcheck_enable_unused_functions_results}" EQUAL 0 )
    set( CPPCHECK_UNUSEDFUNC_ARG --enable=unusedFunctions )
  else( "${_cppcheck_enable_unused_functions_results}" EQUAL 0 )
    execute_process( COMMAND
      ${CPPCHECK_EXECUTABLE}
      --enable=unusedFunction
      ${CPPCHECK_QUIET_ARG}
      ${_cppcheckdummyfile}
    RESULT_VARIABLE
      _cppcheck_enable_unused_function_results
    OUTPUT_QUIET
    ERROR_QUIET )

    if( "${_cppcheck_enable_unused_function_results}" EQUAL 0 )
      set( CPPCHECK_UNUSEDFUNC_ARG --enable=unusedFunction )
    else( "${_cppcheck_enable_unused_function_results}" EQUAL 0 )
      set( CPPCHECK_UNUSEDFUNC_ARG )
    endif( "${_cppcheck_enable_unused_function_results}" EQUAL 0 )
  endif( "${_cppcheck_enable_unused_functions_results}" EQUAL 0 )

  execute_process( COMMAND
      ${CPPCHECK_EXECUTABLE}
      --enable=information
      ${CPPCHECK_QUIET_ARG}
      ${_cppcheckdummyfile}
    RESULT_VARIABLE
      _cppcheck_enable_information_results
    OUTPUT_QUIET
    ERROR_QUIET )

  if( "${_cppcheck_enable_information_results}" EQUAL 0 )
    set( CPPCHECK_INFORMATION_ARG --enable=information )
  else( "${_cppcheck_enable_information_results}" EQUAL 0 )
    set( CPPCHECK_INFORMATION_ARG )
  endif( "${_cppcheck_enable_information_results}" EQUAL 0 )

  execute_process( COMMAND
      ${CPPCHECK_EXECUTABLE}
      --enable=missingInclude
      ${CPPCHECK_QUIET_ARG}
      ${_cppcheckdummyfile}
    RESULT_VARIABLE
      _cppcheck_missingInclude_results
    OUTPUT_QUIET
    ERROR_QUIET )

  if( "${_cppcheck_missingInclude_results}" EQUAL 0 )
    set( CPPCHECK_MISSING_INCLUDE_ARG --enable=missingInclude )
  else( "${_cppcheck_missingInclude_results}" EQUAL 0 )
    set( CPPCHECK_MISSING_INCLUDE_ARG )
  endif( "${_cppcheck_missingInclude_results}" EQUAL 0 )
endif( CPPCHECK_EXECUTABLE )

set( CPPCHECK_ALL
"${CPPCHECK_EXECUTABLE} ${CPPCHECK_POSSIBLEERROR_ARG} ${CPPCHECK_UNUSEDFUNC_ARG} ${CPPCHECK_STYLE_ARG} ${CPPCHECK_QUIET_ARG} ${CPPCHECK_INCLUDEPATH_ARG} some/include/path" )

include( FindPackageHandleStandardArgs )
find_package_handle_standard_args( cppcheck
  DEFAULT_MSG
  CPPCHECK_ALL
  CPPCHECK_EXECUTABLE
  CPPCHECK_UNUSEDFUNC_ARG
  CPPCHECK_STYLE_ARG
  CPPCHECK_INFORMATION_ARG
  CPPCHECK_MISSING_INCLUDE_ARG
  CPPCHECK_ALL_ARG
  CPPCHECK_INCLUDEPATH_ARG
  CPPCHECK_DEFINITION_ARG
  CPPCHECK_QUIET_ARG
  CPPCHECK_FORCE_ARG
  CPPCHECK_VERBOSE_ARG )

if( CPPCHECK_FOUND OR CPPCHECK_MARK_AS_ADVANCED )
  mark_as_advanced( CPPCHECK_ROOT_DIR )
endif( CPPCHECK_FOUND OR CPPCHECK_MARK_AS_ADVANCED )

mark_as_advanced( CPPCHECK_EXECUTABLE )
