#!/bin/bash set -eu -o pipefail PCP_DIR="$(dirname "$0")/pcp" if [ ! -d "${PCP_DIR}" ]; then echo Could not find PCP platform sources. >&2 exit 1 fi echo Scanning definitions in ${PCP_DIR} ... PCP_COLUMNS="${PCP_DIR}/columns" PCP_METERS="${PCP_DIR}/meters" PCP_SCREENS="${PCP_DIR}/screens" if [ ! -d "${PCP_COLUMNS}" ]; then echo Could not find PCP column definitions. >&2 exit 1 fi if [ ! -d "${PCP_METERS}" ]; then echo Could not find PCP meter definitions. >&2 exit 1 fi if [ ! -d "${PCP_SCREENS}" ]; then echo Could not find PCP screen definitions. >&2 exit 1 fi check_file() { f="$1" r="$2" echo "Processing $f ..." awk -v required_names_str="$2" ' BEGIN { # Define the required names split(required_names_str, required_names) section = "" } # Skip comment lines /^#/ { next } # Detect section headers /^\[.*\]$/ { if (section != "") { check_section() } section = $0 if (section in sections_seen) { print "Error: Duplicate section " section exit 1 } sections_seen[section] = 1 delete seen delete groups next } # Process name = value pairs with whitespace around the equals sign /^[^=]+ = [^=]+$/ { split($0, pair, " = ") name = trim(pair[1]) value = trim(pair[2]) group = "" known = 0 for (i in required_names) { rname = required_names[i] if (rname ~ /\?$/) { rname = substr(rname, 1, length(rname) - 1) } if (rname ~ /^\*\./) { rlname = substr(rname, 2, length(rname) - 1) if (substr(name, length(name) - length(rlname) + 1) == rlname) { group = substr(name, 1, length(name) - length(rlname) + 1) known = 1 break } } if (rname == name) { known = 1 break } } if (!known) { print "Error: Unknown name " name " in section " section exit 1 } if (name in seen) { print "Error: Duplicate name " name " in section " section exit 1 } seen[name] = 1 groups[group] = 1 if (name ~ /(^|\.)width$/) { if (!(value ~ /^-?[0-9]{1,3}$/)) { print "Error: Specified width " value " for " name " in section " section " is not an integer or out of range (-999..999)." exit 1 } } if (name ~ /(^|\.)type$/) { if (!(value ~ /^(bar|text|graph|led)$/)) { print "Error: Specified type " value " for " name " in section " section " is not recognized." exit 1 } } if (name ~ /(^|\.)color$/) { if (!(value ~ /^(black|blue|green|red|cyan|magenta|yellow|(dark)?gray|white)$/)) { print "Error: Specified color " value " for " name " in section " section " is not recognized." exit 1 } } next } # Function to trim whitespace function trim(s) { gsub(/^[ \t]+|[ \t]+$/, "", s) return s } # Function to check if all required names are present function check_section() { missing = "" for (i in required_names) { rname = required_names[i] if (rname ~ /\?$/) { continue } if (rname ~ /^\*\./) { rname = substr(rname, 3, length(rname) - 2) for (g in groups) { if (g == "") { continue } if (!(g rname in seen)) { missing = missing g rname " " } } continue } if (!(rname in seen)) { missing = missing rname " " } } if (missing != "") { print "Error: Missing " missing "in section " section exit 1 } } # End of file processing END { if (section != "") { check_section() } # Ensure the file ends with a single newline if (NR > 0 && length($0) < 1) { print "Error: Whitespace at EOF." exit 1 } } ' "$f" } error_occurred=0 for pcp_file in "${PCP_COLUMNS}"/*; do if ! check_file "$pcp_file" "heading caption? width metric description"; then echo "Error processing file: $pcp_file" >&2 error_occurred=1 fi done for pcp_file in "${PCP_METERS}"/*; do if ! check_file "$pcp_file" "caption description? type? *.metric *.color? *.label? *.suffix?"; then echo "Error processing file: $pcp_file" >&2 error_occurred=1 fi done for pcp_file in "${PCP_SCREENS}"/*; do if ! check_file "$pcp_file" "heading caption default? *.heading *.metric *.default? *.caption? *.format? *.instances? *.width?"; then echo "Error processing file: $pcp_file" >&2 error_occurred=1 fi done if [ $error_occurred -ne 0 ]; then echo "One or more files failed to process." >&2 exit 1 else echo "All files processed successfully." >&2 fi