#!/bin/sh set -eu base="${TMPDIR-/tmp}/mcpu-cpp-output-line-compaction-$$" mkdir -p "$base" trap 'rm -rf "$base"' EXIT HUP INT TERM # Seven invisible lines stay as seven ordinary newlines. The next visible # source line is line 9, and no corrective marker is needed. cat > "$base/gap7.c" <<'EOT' int a; // one #define A 1 #if 0 hidden #endif /* six */ int b; EOT "$MCPU_CPP" --no-config "$base/gap7.c" -o "$base/gap7.out" if grep -F "# 9 \"$base/gap7.c\"" "$base/gap7.out" >/dev/null; then echo "unexpected line marker for seven-line invisible gap" >&2 exit 1 fi gap7_count=`awk ' $0 == "int a;" { inside = 1; next } $0 == "int b;" { print count; exit } inside { ++count } ' "$base/gap7.out"` test "$gap7_count" -eq 7 # Eight invisible lines cross the GNU CPP threshold. They disappear from the # byte stream and are represented by a line marker for the next visible line. cat > "$base/gap8.c" <<'EOT' int a; // one #define A 1 #if 0 hidden #endif /* six */ // seven int b; EOT "$MCPU_CPP" --no-config "$base/gap8.c" -o "$base/gap8.out" grep -F "# 10 \"$base/gap8.c\"" "$base/gap8.out" >/dev/null awk ' /^# 10 "/ { getline; if( $0 == "int b;" ) ok = 1 } END { exit ok ? 0 : 1 } ' "$base/gap8.out" # A completely invisible header has no synthetic end-of-header marker. Only # the structural enter/return markers survive. A long invisible gap in the # parent is then represented by the parent's next visible source position. cat > "$base/silent.h" <<'EOT' #ifndef SILENT_H #define SILENT_H 1 #define H1 1 #define H2 2 #define H3 3 #define H4 4 #define H5 5 #define H6 6 #define H7 7 #define H8 8 #define H9 9 #endif EOT cat > "$base/include.c" <<'EOT' // leading comment #include "silent.h" // one #define P1 1 #if 0 hidden #endif // six // seven int visible; EOT "$MCPU_CPP" --no-config -I"$base" "$base/include.c" -o "$base/include.out" grep -F "# 1 \"$base/silent.h\" 1" "$base/include.out" >/dev/null grep -F "# 3 \"$base/include.c\" 2" "$base/include.out" >/dev/null grep -F "# 11 \"$base/include.c\"" "$base/include.out" >/dev/null if grep -E "^# (2|3|4|5|6|7|8|9|10|11|12) \"$base/silent.h\"" "$base/include.out" >/dev/null; then echo "silent header acquired a synthetic progress marker" >&2 exit 1 fi awk ' /\/silent\.h" 1$/ { getline; if( $0 ~ /\/include\.c" 2$/ ) adjacent = 1 } /^# 11 "/ { getline; if( $0 == "int visible;" ) visible = 1 } END { exit adjacent && visible ? 0 : 1 } ' "$base/include.out" # The threshold is based on source position, not on why the lines are # invisible. A long run of comments alone is compacted in exactly the same # way as directives or inactive conditional text. cat > "$base/comments.c" <<'EOT' int before; // 1 // 2 // 3 // 4 // 5 // 6 // 7 // 8 int after; EOT "$MCPU_CPP" --no-config "$base/comments.c" -o "$base/comments.out" grep -F "# 10 \"$base/comments.c\"" "$base/comments.out" >/dev/null # __LINE__ observes source coordinates, not the compacted output layout. cat > "$base/line.c" <<'EOT' int a = __LINE__; // 1 // 2 // 3 // 4 // 5 // 6 // 7 // 8 int b = __LINE__; EOT "$MCPU_CPP" --no-config "$base/line.c" -o "$base/line.out" grep -Fx 'int a = 1;' "$base/line.out" >/dev/null grep -Fx 'int b = 10;' "$base/line.out" >/dev/null grep -F "# 10 \"$base/line.c\"" "$base/line.out" >/dev/null