#!/bin/bash # # clang-format-all: a tool to run clang-format on an entire project # Copyright (C) 2016 Evan Klitzke # # 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 . function usage { echo "Usage: $0 DIR..." exit 1 } if [ $# -eq 0 ]; then usage fi # Variable that will hold the name of the clang-format command FMT="" # Some distros just call it clang-format. Others (e.g. Ubuntu) are insistent # that the version number be part of the command. We prefer clang-format if # that's present, otherwise we work backwards from highest version to lowest # version. for clangfmt in clang-format{,-{4,3}.{9,8,7,6,5,4,3,2,1,0}}; do if which "$clangfmt" &>/dev/null; then FMT="$clangfmt" break fi done # Check if we found a working clang-format if [ -z "$FMT" ]; then echo "failed to find clang-format" exit 1 fi # Check all of the arguments first to make sure they're all directories for dir in "$@"; do if [ ! -d "${dir}" ]; then echo "${dir} is not a directory" usage fi done # Find a dominating file, starting from a given directory and going up. find-dominating-file() { if [ -r "$1"/"$2" ]; then return 0 fi if [ "$1" = "/" ]; then return 1 fi find-dominating-file "$(realpath "$1"/..)" "$2" return $? } # Run clang-format -i on all of the things for dir in "$@"; do pushd "${dir}" &>/dev/null if ! find-dominating-file . _clang-format; then echo "Failed to find dominating .clang-format starting at $PWD" continue fi find . \ \( -name '*.c' \ -o -name '*.cc' \ -o -name '*.cpp' \ -o -name '*.h' \ -o -name '*.hh' \ -o -name '*.hpp' \) \ -exec "${FMT}" -i -verbose '{}' \; popd &>/dev/null done