format-code: simplify exclusion filter for clang

The clang-format linter calls have a custom ignore list.  Write
a python script for reusable git-ignore-like filtering and switch
the clang-format linter call to use it.

Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I788c0e3de55fae592318a997b676c73a7f13e74c
diff --git a/config/lib/ignore-filter b/config/lib/ignore-filter
new file mode 100755
index 0000000..3373588
--- /dev/null
+++ b/config/lib/ignore-filter
@@ -0,0 +1,47 @@
+#!/usr/bin/env python3
+
+import argparse
+import fnmatch
+import itertools
+import os
+import pathlib
+import sys
+
+parser = argparse.ArgumentParser(
+    "ignore-filter",
+    description="Filter files from stdin using a .gitignore-style filter file",
+)
+parser.add_argument("filename", nargs="+", help="The filter file", type=str)
+
+args = parser.parse_args()
+
+ignore_patterns = list()
+for f in args.filename:
+    if not os.path.exists(f):
+        raise RuntimeError(f"File {args.filename} does not exist.")
+    with open(f, "r") as ignore_file:
+        for line in [i.strip() for i in ignore_file.readlines()]:
+            # Ignore comments.
+            if line.startswith("#"):
+                continue
+
+            # Drop leading "/" or "./" ( this isn't 100% correct for
+            # .gitignore format) .
+            if line.startswith("/"):
+                line = line[1:]
+            elif line.startswith("./"):
+                line = line[2:]
+
+            ignore_patterns.append(line)
+
+for c in sys.stdin:
+    candidate = c.strip()
+    match = False
+    for seg in itertools.accumulate(
+        pathlib.PurePath(candidate).parts, os.path.join
+    ):
+        if any(fnmatch.fnmatch(seg, i) for i in ignore_patterns):
+            match = True
+            break
+    if not match:
+        print(candidate)
diff --git a/scripts/format-code.sh b/scripts/format-code.sh
index 7fdbc52..83fbcd5 100755
--- a/scripts/format-code.sh
+++ b/scripts/format-code.sh
@@ -159,59 +159,17 @@
 
 LINTER_REQUIRE+=([clang_format]="clang-format;.clang-format")
 do_clang_format() {
-    IGNORE_FILE=".clang-ignore"
-    declare -a IGNORE_LIST
-
-    if [[ -f "${IGNORE_FILE}" ]]; then
-        readarray -t IGNORE_LIST < "${IGNORE_FILE}"
-    fi
-
-    ignorepaths=""
-    ignorefiles=""
-
-    for path in "${IGNORE_LIST[@]}"; do
-        # Check for comment, line starting with space, or zero-length string.
-        # Checking for [[:space:]] checks all options.
-        if [[ -z "${path}" ]] || [[ "${path}" =~ ^(#|[[:space:]]).*$ ]]; then
-            continue
-        fi
-
-        # All paths must start with ./ for find's path prune expectation.
-        if [[ "${path}" =~ ^\.\/.+$ ]]; then
-            ignorepaths+=" ${path}"
-        else
-            ignorefiles+=" ${path}"
-        fi
-    done
-
-    searchfiles=""
-    while read -r path; do
-        # skip ignorefiles
-        if [[ $ignorefiles == *"$(basename "${path}")"* ]]; then
-            continue
-        fi
-
-        skip=false
-        #skip paths in ingorepaths
-        for pathname in $ignorepaths; do
-            if [[ "./${path}" == "${pathname}"* ]]; then
-                skip=true
-                break
-            fi
-        done
-
-        if [ "$skip" = true ]; then
-            continue
-        fi
-        # shellcheck disable=2089
-        searchfiles+="\"./${path}\" "
-
-        # Get C and C++ files managed by git and skip the mako files
-    done <<<"$(git ls-files | grep -e '\.[ch]pp$' -e '\.[ch]$' | grep -v '\.mako\.')"
 
     echo -e "    ${BLUE}Running clang-format${NORMAL}"
-    # shellcheck disable=SC2090 disable=SC2086
-    echo ${searchfiles} | xargs "${CLANG_FORMAT}" -i
+    files=$(git ls-files | \
+        grep -e '\.[ch]pp$' -e '\.[ch]$' | \
+        grep -v '\.mako\.')
+
+    if [ -e .clang-ignore ]; then
+        files=$("${CONFIG_PATH}/lib/ignore-filter" .clang-ignore <<< "${files}")
+    fi
+
+    xargs "${CLANG_FORMAT}" -i <<< "${files}"
 }
 
 function check_linter()