git subrepo pull (merge) --force deps/libchdr
[pcsx_rearmed.git] / deps / libchdr / deps / zstd-1.5.5 / build / single_file_libs / combine.sh
diff --git a/deps/libchdr/deps/zstd-1.5.5/build/single_file_libs/combine.sh b/deps/libchdr/deps/zstd-1.5.5/build/single_file_libs/combine.sh
new file mode 100755 (executable)
index 0000000..222c2c3
--- /dev/null
@@ -0,0 +1,249 @@
+#!/bin/sh -e
+
+# Tool to bundle multiple C/C++ source files, inlining any includes.
+# 
+# TODO: ROOTS, FOUND, etc., as arrays (since they fail on paths with spaces)
+# 
+# Author: Carl Woffenden, Numfum GmbH (this script is released under a CC0 license/Public Domain)
+
+# Common file roots
+ROOTS="."
+
+# -x option excluded includes
+XINCS=""
+
+# -k option includes to keep as include directives
+KINCS=""
+
+# Files previously visited
+FOUND=""
+
+# Optional destination file (empty string to write to stdout)
+DESTN=""
+
+# Whether the "#pragma once" directives should be written to the output
+PONCE=0
+
+# Prints the script usage then exits
+usage() {
+  echo "Usage: $0 [-r <path>] [-x <header>] [-k <header>] [-o <outfile>] infile"
+  echo "  -r file root search path"
+  echo "  -x file to completely exclude from inlining"
+  echo "  -k file to exclude from inlining but keep the include directive"
+  echo "  -p keep any '#pragma once' directives (removed by default)"
+  echo "  -o output file (otherwise stdout)"
+  echo "Example: $0 -r ../my/path - r ../other/path -o out.c in.c"
+  exit 1
+}
+
+# Tests that the grep implementation works as expected (older OSX grep fails)
+test_deps() {
+  if ! echo '#include "foo"' | grep -Eq '^\s*#\s*include\s*".+"'; then
+    echo "Aborting: the grep implementation fails to parse include lines"
+    exit 1
+  fi
+  if ! echo '"foo.h"' | sed -E 's/"([^"]+)"/\1/' | grep -Eq '^foo\.h$'; then
+    echo "Aborting: sed is unavailable or non-functional"
+    exit 1
+  fi
+}
+
+# Test if glob pattern $1 matches subject $2 (see fnmatch(3))
+fnmatch() {
+  case "$2" in
+  $1)
+    return 0
+    ;;
+  esac
+  return 1
+}
+
+# Test if line $1 is local include directive
+is_include_line() {
+  fnmatch "*#*include*" "$1" || return 1
+  printf "%s\n" "$1" | grep -Eq '^\s*#\s*include\s*".+"'
+}
+
+# Test if line $1 is pragma once directive
+is_pragma_once_line() {
+  fnmatch "*#*pragma*once*" "$1" || return 1
+  printf "%s\n" "$1" | grep -Eq '^\s*#\s*pragma\s*once\s*'
+}
+
+# Tests if list $1 has item $2 (returning zero on a match)
+# (originally used grep -Eq "(^|\s*)$2(\$|\s*))
+readonly list_FS="$IFS"
+list_has_item() {
+  # Re: escaping glob pattern special characters in item string:
+  #
+  # bash (tested 3.2.57, 5.1.4), dash (tested 0.5.10.2), NetBSD /bin/sh
+  # (tested 8.2), and Solaris /bin/sh (tested 11.4) require escaping
+  # backslashes in a bracket expression despite POSIX specifying that
+  # backslash loses significance in a bracket expression.
+  #
+  # Conversely, neither FreeBSD /bin/sh (tested 12.2) nor OpenBSD /bin/sh
+  # (tested 7.1) obey backslash-escaping in case statement patterns even
+  # outside bracket expressions, so escape special characters using bracket
+  # expressions.
+  #
+  # Solaris /bin/sh (tested 11.4) requires vertical bar (|) to be escaped.
+  #
+  # All accommodations should behave as expected under strict POSIX semantics.
+  if fnmatch "*[\\*?[|]*" "$2"; then
+    set -- "$1" "$(printf '%s\n' "$2" | sed -e 's/[*?[|]/[&]/g; s/[\]/[\\&]/g')"
+  fi
+  for item_P in "*[$list_FS]$2[$list_FS]*" "*[$list_FS]$2" "$2[$list_FS]*" "$2"; do
+    fnmatch "${item_P}" "$1" && return 0
+  done
+  return 1
+}
+
+# Adds a new line with the supplied arguments to $DESTN (or stdout)
+write_line() {
+  if [ -n "$DESTN" ]; then
+    printf '%s\n' "$@" >> "$DESTN"
+  else
+    printf '%s\n' "$@"
+  fi
+}
+
+log_line() {
+  echo $@ >&2
+}
+
+# Find this file!
+resolve_include() {
+  local srcdir=$1
+  local inc=$2
+  for root in $srcdir $ROOTS; do
+    if [ -f "$root/$inc" ]; then
+      # Try to reduce the file path into a canonical form (so that multiple)
+      # includes of the same file are successfully deduplicated, even if they
+      # are expressed differently.
+      local relpath="$(realpath --relative-to . "$root/$inc" 2>/dev/null)"
+      if [ "$relpath" != "" ]; then # not all realpaths support --relative-to
+        echo "$relpath"
+        return 0
+      fi
+      local relpath="$(realpath "$root/$inc" 2>/dev/null)"
+      if [ "$relpath" != "" ]; then # not all distros have realpath...
+        echo "$relpath"
+        return 0
+      fi
+      # Fallback on Python to reduce the path if the above fails.
+      local relpath=$(python -c "import os,sys; print os.path.relpath(sys.argv[1])" "$root/$inc" 2>/dev/null)
+      if [ "$relpath" != "" ]; then # not all distros have realpath...
+        echo "$relpath"
+        return 0
+      fi
+      # Worst case, fall back to just the root + relative include path. The
+      # problem with this is that it is possible to emit multiple different
+      # resolved paths to the same file, depending on exactly how its included.
+      # Since the main loop below keeps a list of the resolved paths it's
+      # already included, in order to avoid repeated includes, this failure to
+      # produce a canonical/reduced path can lead to multiple inclusions of the
+      # same file. But it seems like the resulting single file library still
+      # works (hurray include guards!), so I guess it's ok.
+      echo "$root/$inc"
+      return 0
+    fi
+  done
+  return 1
+}
+
+# Adds the contents of $1 with any of its includes inlined
+add_file() {
+  local file=$1
+  if [ -n "$file" ]; then
+    log_line "Processing: $file"
+    # Get directory of the current so we can resolve relative includes
+    local srcdir="$(dirname "$file")"
+    # Read the file
+    local line=
+    while IFS= read -r line; do
+      if is_include_line "$line"; then
+        # We have an include directive so strip the (first) file
+        local inc=$(echo "$line" | grep -Eo '".*"' | sed -E 's/"([^"]+)"/\1/' | head -1)
+        local res_inc="$(resolve_include "$srcdir" "$inc")"
+        if list_has_item "$XINCS" "$inc"; then
+          # The file was excluded so error if the source attempts to use it
+          write_line "#error Using excluded file: $inc (re-amalgamate source to fix)"
+          log_line "Excluding: $inc"
+        else
+          if ! list_has_item "$FOUND" "$res_inc"; then
+            # The file was not previously encountered
+            FOUND="$FOUND $res_inc"
+            if list_has_item "$KINCS" "$inc"; then
+              # But the include was flagged to keep as included
+              write_line "/**** *NOT* inlining $inc ****/"
+              write_line "$line"
+              log_line "Not Inlining: $inc"
+            else
+              # The file was neither excluded nor seen before so inline it
+              write_line "/**** start inlining $inc ****/"
+              add_file "$res_inc"
+              write_line "/**** ended inlining $inc ****/"
+            fi
+          else
+            write_line "/**** skipping file: $inc ****/"
+          fi
+        fi
+      else
+        # Skip any 'pragma once' directives, otherwise write the source line
+        local write=$PONCE
+        if [ $write -eq 0 ]; then
+          if ! is_pragma_once_line "$line"; then
+            write=1
+          fi
+        fi
+        if [ $write -ne 0 ]; then
+          write_line "$line"
+        fi
+      fi
+    done < "$file"
+  else
+    write_line "#error Unable to find \"$1\""
+    log_line "Error: Unable to find: \"$1\""
+  fi
+}
+
+while getopts ":r:x:k:po:" opts; do
+  case $opts in
+  r)
+    ROOTS="$ROOTS $OPTARG"
+    ;;
+  x)
+    XINCS="$XINCS $OPTARG"
+    ;;
+  k)
+    KINCS="$KINCS $OPTARG"
+    ;;
+  p)
+    PONCE=1
+    ;;
+  o)
+    DESTN="$OPTARG"
+    ;;
+  *)
+    usage
+    ;;
+  esac
+done
+shift $((OPTIND-1))
+
+if [ -n "$1" ]; then
+  if [ -f "$1" ]; then
+    if [ -n "$DESTN" ]; then
+      printf "" > "$DESTN"
+    fi
+    test_deps
+    log_line "Processing using the slower shell script; this might take a while"
+    add_file "$1"
+  else
+    echo "Input file not found: \"$1\""
+    exit 1
+  fi
+else
+  usage
+fi
+exit 0