#!/bin/bash
# check-select-string — ein `Select` auf einem ZEICHENKETTEN-AUSDRUCK, aus dem
# ein Case per ProcedureReturn/Break/Goto herausspringt, leckt.
#
# WARUM: `Select LCase(name)` legt den Vergleichswert in einer temporaeren
# Zeichenkette ab. Freigegeben wird sie erst von `EndSelect` — und genau dort
# kommt der Code nie an, wenn jeder Case per `ProcedureReturn` hinausspringt.
# Nachgemessen mit 2 Mio. Aufrufen, Hauptlauf UND Thread:
#
#     Select LCase(name)  + ProcedureReturn je Case   ->  94 MB   (47 B/Aufruf)
#     Protected n.s = LCase(name) : Select n          ->   0 kB
#
# Richtig ist also immer:
#
#     Protected n.s = LCase(name)
#     Select n
#       Case "..." : ProcedureReturn ...
#     EndSelect
#
# Die Signatur im Betrieb ist dieselbe wie bei HTTPLIB-122: mimalloc waechst
# langsam und stetig, kein Register waechst mit, der Bestandsbericht sieht
# nichts. In QPACK_Codec::_IsSensitiveHeader hat diese eine Zeile jede
# HTTP/3-Antwort sieben Header-NAMEN kosten lassen (~330 Byte je Anfrage);
# die Werte blieben sauber, weil sie nie durch ein solches Select laufen.
# Genau diese Asymmetrie — Namen lecken, Werte nicht — war die Spur.
#
# Die Pruefung ist bewusst eng: sie meldet nur Ausdruecke, die eine Zeichenkette
# ERZEUGEN (String-Funktion, Modul-Aufruf oder Verkettung). Ein `Select` auf
# einer Variablen oder einem Zahlenfeld ist in Ordnung und wird nicht gemeldet.
set -u
cd "$(dirname "$0")/.."

# Nur vorhandene Dateien an awk geben — lhs_lib hat keine .pbi im Wurzelverzeichnis,
# und ein leerer Glob liesse awk mit „kann nicht geoeffnet werden" abbrechen.
dateien=()
for f in http_lib/*.pbi net_lib/*.pbi lhs_lib/*.pbi lhs_lib/*/*.pbi inc/*.pbi wowa-edge.pb; do
    [ -e "$f" ] && dateien+=("$f")
done

awk '
function melde(datei, zeile, ausdruck) {
    printf "  LECK: %s:%d — Select %s, aus dem heraus gesprungen wird\n", datei, zeile, ausdruck
    fehler++
}
FNR == 1 { datei = FILENAME }
{
    zeile = $0
    sub(/;.*$/, "", zeile)                       # Kommentar ab
    if (offen > 0) {
        if (zeile ~ /^[ \t]*Select[ \t]+/)     tiefe++
        else if (zeile ~ /^[ \t]*EndSelect[ \t]*$/) {
            if (tiefe > 0) tiefe--
            else {
                if (raus) melde(datei, sel_zeile, sel_ausdruck)
                offen = 0
            }
        }
        else if (tiefe == 0 && zeile ~ /\<(ProcedureReturn|Goto|Break)\>/) raus = 1
        next
    }
    if (zeile ~ /^[ \t]*Select[ \t]+/) {
        a = zeile
        sub(/^[ \t]*Select[ \t]+/, "", a)
        gsub(/[ \t]+$/, "", a)
        # Erzeugt der Ausdruck eine Zeichenkette?
        if (a ~ /\<(LCase|UCase|Trim|LTrim|RTrim|Str|StrF|StrD|StrU|Hex|Bin|PeekS|Mid|Left|Right|ReplaceString|StringField|RSet|LSet|Space|Chr|FormatDate|GetFilePart|GetPathPart|GetExtensionPart)[ \t]*\(/ ||
            a ~ /::[A-Za-z_0-9]+[ \t]*\(/ ||
            a ~ /\+/) {
            offen = 1; tiefe = 0; raus = 0; sel_zeile = FNR; sel_ausdruck = a
        }
    }
}
END { exit (fehler > 0) }
' "${dateien[@]}"

if [ $? -ne 0 ]; then
    echo "  -> Vergleichswert in eine Variable legen. Siehe HTTPLIB-131."
    exit 1
fi
echo "  Select-auf-Zeichenkette-Pruefung: in Ordnung"
