Files
wasm-simulator/generate-linuxcnc-switchkins-remap-table.sh
cnc 1498d9830d 继续推进:浏览器批量验证LinuxCNC配置入口
结论:浏览器 WASM smoke 已读取 LinuxCNC 生成的 64 个 switchkins 配置用例,覆盖 config/MACHINE/KINEMATICS/HALFILE 入口;native 与 source-link 验证通过。
2026-05-30 10:19:32 +08:00

322 lines
9.3 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
linuxcnc_root=${LINUXCNC_ROOT:-../linuxcnc}
mode=table
if [[ "${1:-}" == "--config-cases" ]]; then
mode=config-cases
shift
elif [[ "${1:-}" == "--json-cases" ]]; then
mode=json-cases
shift
fi
manifest=${1:-linuxcnc-kinematics-source-files.txt}
if [[ ! -d "$linuxcnc_root" ]]; then
echo "missing LinuxCNC root: $linuxcnc_root" >&2
exit 1
fi
if [[ ! -f "$manifest" ]]; then
echo "missing kinematics manifest: $manifest" >&2
exit 1
fi
linuxcnc_root=$(cd "$linuxcnc_root" && pwd)
normalize_alias() {
tr '[:upper:]' '[:lower:]' | tr -d '[:space:]'
}
trim_value() {
sed 's/[[:space:]]*[#;].*$//; s/^[[:space:]]*//; s/[[:space:]]*$//'
}
ini_value() {
local file=$1
local key=$2
sed -n "s/^[[:space:]]*$key[[:space:]]*=[[:space:]]*//Ip" "$file" | head -n 1 | trim_value
}
ini_values() {
local file=$1
local key=$2
sed -n "s/^[[:space:]]*$key[[:space:]]*=[[:space:]]*//Ip" "$file" | trim_value
}
remap_ngc_name() {
local file=$1
local mcode=$2
sed -n "s/.*REMAP[[:space:]]*=[[:space:]]*M$mcode[[:space:]][^#;]*ngc[[:space:]]*=[[:space:]]*\\([^[:space:]#;]*\\).*/\\1/Ip" "$file" |
head -n 1
}
resolve_config_path() {
local config_dir=$1
local path=$2
if [[ "$path" = /* ]]; then
printf '%s\n' "$path"
else
printf '%s\n' "$config_dir/$path"
fi
}
relative_linuxcnc_path() {
local path=$1
path=$(cd "$(dirname "$path")" && pwd)/$(basename "$path")
printf '%s\n' "${path#"$linuxcnc_root/"}"
}
remap_source_for_mcode() {
local config=$1
local mcode=$2
local ngc_name
ngc_name=$(remap_ngc_name "$config" "$mcode")
if [[ -z "$ngc_name" ]]; then
return 1
fi
if [[ "$ngc_name" != *.ngc ]]; then
ngc_name="$ngc_name.ngc"
fi
local config_dir
config_dir=$(cd "$(dirname "$config")" && pwd)
local subroutine_paths
subroutine_paths=$(ini_values "$config" "SUBROUTINE_PATH")
if [[ -z "$subroutine_paths" ]]; then
subroutine_paths="."
fi
local subroutine_path
while IFS= read -r subroutine_path; do
[[ -n "$subroutine_path" ]] || continue
local path_part
IFS=: read -ra path_parts <<<"$subroutine_path"
for path_part in "${path_parts[@]}"; do
[[ -n "$path_part" ]] || continue
local candidate_dir
candidate_dir=$(resolve_config_path "$config_dir" "$path_part")
if [[ -f "$candidate_dir/$ngc_name" ]]; then
relative_linuxcnc_path "$candidate_dir/$ngc_name"
return 0
fi
done
done <<<"$subroutine_paths"
return 1
}
kinstype_for_mcode() {
local config=$1
local mcode=$2
local source
if ! source=$(remap_source_for_mcode "$config" "$mcode"); then
printf '%s\n' "-1"
return 0
fi
sed -n 's/^[[:space:]]*#<kinstype>[[:space:]]*=[[:space:]]*\([0-9][0-9]*\).*/\1/p' \
"$linuxcnc_root/$source" |
head -n 1
}
json_compact_string() {
local value=$1
printf '%s' "$value" | normalize_alias | sed 's/\\/\\\\/g; s/"/\\"/g'
}
cpp_string() {
local value=$1
printf '%s' "$value" | sed 's/\\/\\\\/g; s/"/\\"/g'
}
declare -A seen_aliases=()
declare -A seen_cases=()
entries=()
case_entries=()
json_case_entries=()
add_alias() {
local alias=$1
local m428=$2
local m429=$3
local m430=$4
alias=$(json_compact_string "$alias")
[[ -n "$alias" ]] || return 0
local types="$m428,$m429,$m430"
if [[ -n "${seen_aliases[$alias]:-}" ]]; then
if [[ "${seen_aliases[$alias]}" != "$types" ]]; then
echo "ambiguous switchkins alias '$alias': ${seen_aliases[$alias]} and $types" >&2
exit 1
fi
return 0
fi
seen_aliases[$alias]=$types
entries+=(" {\"$alias\", $m428, $m429, $m430},")
}
add_case() {
local field=$1
local value=$2
local m428=$3
local m429=$4
local m430=$5
[[ -n "$value" ]] || return 0
local types="$m428,$m429,$m430"
local key="$field|$value|$types"
[[ -z "${seen_cases[$key]:-}" ]] || return 0
seen_cases[$key]=1
local cpp_field
local cpp_value
cpp_field=$(cpp_string "$field")
cpp_value=$(cpp_string "$value")
case_entries+=(" {\"$cpp_field\", \"$cpp_value\", $m428, $m429, $m430},")
json_case_entries+=("{\"field\":\"$cpp_field\",\"value\":\"$cpp_value\",\"m428\":$m428,\"m429\":$m429,\"m430\":$m430}")
}
add_machine_aliases() {
local machine=$1
local m428=$2
local m429=$3
local m430=$4
[[ -n "$machine" ]] || return 0
add_alias "$machine" "$m428" "$m429" "$m430"
add_alias "${machine%%(*}" "$m428" "$m429" "$m430"
}
add_kinematics_aliases() {
local kinematics=$1
local m428=$2
local m429=$3
local m430=$4
[[ -n "$kinematics" ]] || return 0
add_alias "$kinematics" "$m428" "$m429" "$m430"
local first_word=${kinematics%%[[:space:]]*}
add_alias "$first_word" "$m428" "$m429" "$m430"
add_alias "${first_word%_kins}" "$m428" "$m429" "$m430"
add_alias "${first_word%-kins}" "$m428" "$m429" "$m430"
add_alias "$(printf '%s' "$first_word" | tr '_' '-')" "$m428" "$m429" "$m430"
add_alias "$(printf '%s' "${first_word%_kins}" | tr '_' '-')" "$m428" "$m429" "$m430"
add_alias "$(printf '%s' "${first_word%-kins}" | tr '_' '-')" "$m428" "$m429" "$m430"
}
add_halfile_aliases() {
local halfile=$1
local m428=$2
local m429=$3
local m430=$4
[[ -n "$halfile" ]] || return 0
[[ "$halfile" == LIB:* ]] && return 0
add_alias "$halfile" "$m428" "$m429" "$m430"
local hal_base=${halfile##*/}
add_alias "$hal_base" "$m428" "$m429" "$m430"
add_alias "${hal_base%.hal}" "$m428" "$m429" "$m430"
}
add_halfile_cases() {
local halfile=$1
local m428=$2
local m429=$3
local m430=$4
[[ -n "$halfile" ]] || return 0
[[ "$halfile" == LIB:* ]] && return 0
local hal_base=${halfile##*/}
local hal_stem=${hal_base%.hal}
add_case "halfile" "$halfile" "$m428" "$m429" "$m430"
add_case "halfile" "$hal_base" "$m428" "$m429" "$m430"
add_case "halfile" "$hal_stem" "$m428" "$m429" "$m430"
add_case "hal_file" "$halfile" "$m428" "$m429" "$m430"
add_case "hal_file" "$hal_base" "$m428" "$m429" "$m430"
add_case "hal_file" "$hal_stem" "$m428" "$m429" "$m430"
}
while IFS=: read -r group path _note; do
[[ "$group" == "config" && "$path" == *.ini ]] || continue
config="$linuxcnc_root/$path"
[[ -f "$config" ]] || {
echo "missing LinuxCNC config source: $path" >&2
exit 1
}
if ! grep -Eiq 'REMAP[[:space:]]*=[[:space:]]*M(428|429|430)([^0-9]|$)' "$config"; then
continue
fi
m428=$(kinstype_for_mcode "$config" 428)
m429=$(kinstype_for_mcode "$config" 429)
m430=$(kinstype_for_mcode "$config" 430)
[[ -n "$m428" ]] || m428=-1
[[ -n "$m429" ]] || m429=-1
[[ -n "$m430" ]] || m430=-1
machine=$(ini_value "$config" "MACHINE")
kinematics=$(ini_value "$config" "KINEMATICS")
halfiles=$(ini_values "$config" "HALFILE")
config_dir=${path%/*}
config_base=${path##*/}
config_stem=${config_base%.ini}
add_case "config" "$path" "$m428" "$m429" "$m430"
add_case "machine" "$machine" "$m428" "$m429" "$m430"
add_case "kinematics" "$kinematics" "$m428" "$m429" "$m430"
add_alias "$path" "$m428" "$m429" "$m430"
add_alias "$config_dir" "$m428" "$m429" "$m430"
add_alias "${config_dir##*/}" "$m428" "$m429" "$m430"
add_alias "$config_stem" "$m428" "$m429" "$m430"
add_machine_aliases "$machine" "$m428" "$m429" "$m430"
add_kinematics_aliases "$kinematics" "$m428" "$m429" "$m430"
while IFS= read -r halfile; do
add_halfile_cases "$halfile" "$m428" "$m429" "$m430"
add_halfile_aliases "$halfile" "$m428" "$m429" "$m430"
done <<<"$halfiles"
for mcode in 428 429 430; do
if remap_source=$(remap_source_for_mcode "$config" "$mcode"); then
remap_dir=${remap_source%/*}
add_alias "$remap_dir" "$m428" "$m429" "$m430"
add_alias "${remap_dir%/*}" "$m428" "$m429" "$m430"
add_alias "${remap_dir%/remap_subs}" "$m428" "$m429" "$m430"
remap_parent=${remap_dir%/remap_subs}
add_alias "${remap_parent##*/}" "$m428" "$m429" "$m430"
fi
done
done <"$manifest"
if [[ "$mode" == table ]]; then
cat <<'EOF'
// Generated by ./generate-linuxcnc-switchkins-remap-table.sh.
// Source: LinuxCNC INI MACHINE/KINEMATICS/HALFILE/SUBROUTINE_PATH/REMAP entries and
// adjacent remap_subs/{428,429,430}remap.ngc #<kinstype> assignments.
EOF
printf '%s\n' "${entries[@]}"
elif [[ "$mode" == config-cases ]]; then
cat <<'EOF'
// Generated by ./generate-linuxcnc-switchkins-remap-table.sh --config-cases.
// Source: LinuxCNC INI config path, MACHINE, KINEMATICS, and non-LIB HALFILE entries
// for M428/M429/M430 remap #<kinstype> assignments.
EOF
printf '%s\n' "${case_entries[@]}"
elif [[ "$mode" == json-cases ]]; then
printf '[\n'
for i in "${!json_case_entries[@]}"; do
suffix=,
if [[ "$i" == "$((${#json_case_entries[@]} - 1))" ]]; then
suffix=
fi
printf ' %s%s\n' "${json_case_entries[$i]}" "$suffix"
done
printf ']\n'
else
echo "unknown switchkins remap table generator mode: $mode" >&2
exit 1
fi