585 lines
20 KiB
Bash
Executable File
585 lines
20 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Author: Dirk Zimoch
|
|
|
|
version () {
|
|
echo '$Author: zimoch $' >&2
|
|
echo '$Date: 2018/07/06 12:06:44 $' >&2
|
|
echo '$Revision: 1.26 $' >&2
|
|
echo '$Source: /cvs/G/EPICS/App/scripts/externalLinks,v $' >&2
|
|
exit 1
|
|
}
|
|
|
|
usage () {
|
|
echo "usage: externalLinks [options] <substitutionFiles>" >&2
|
|
echo "returns list of link targets that are not resolved internally" >&2
|
|
echo "optionally returns list of required modules" >&2
|
|
echo "also does some plausibility checks" >&2
|
|
echo "options are:" >&2
|
|
echo " -h | -? | -help print this text and exit" >&2
|
|
echo " -v | -version print version and exit" >&2
|
|
echo " -d | -debug print additional debug messages" >&2
|
|
echo " -w | -where show record.link and target" >&2
|
|
echo " -r | -require show required modules" >&2
|
|
echo " -o | -overwrite don't warn about overwriting fields" >&2
|
|
echo " -f | -find record find links to record" >&2
|
|
echo " -I <dir> find templates in dir" >&2
|
|
echo " -3.13 use lastest EPICS 3.13 version (default for SLS)" >&2
|
|
echo " -3.14 use lastest EPICS 3.14 version (default for SwissFEL, HIPA)" >&2
|
|
echo " -3.x.x use specific EPICS version" >&2
|
|
echo " -- next argument is file, even if starting with -" >&2
|
|
exit 1
|
|
}
|
|
|
|
debug () {
|
|
test "$DEBUG" && echo "$@" > /dev/stderr
|
|
}
|
|
|
|
shopt -s nullglob
|
|
shopt -s extglob
|
|
|
|
export LANG=en_US.iso885915
|
|
INSTBASE=${INSTBASE%/}
|
|
INSTBASE=${INSTBASE#/import}
|
|
case "${INSTBASE}" in
|
|
( /work|/prod|/devl ) EPICS=3.13.10 ;;
|
|
( /hipa/* ) EPICS=3.14.12 ;;
|
|
( * ) EPICS=3.14.12 ;;
|
|
esac
|
|
|
|
while true
|
|
do
|
|
case "$1" in
|
|
( -h | -\? | ?(-)-help ) usage ;;
|
|
( -v | ?(-)-version ) version ;;
|
|
( -d | ?(-)-debug ) DEBUG=1 ;;
|
|
( -r | ?(-)-require ) REQUIRE=1 ;;
|
|
( -w | ?(-)-where ) WHERE=1 ;;
|
|
( -o | ?(-)-overwrite ) OVERWRITE=1 ;;
|
|
( -f | ?(-)-find ) FIND+=" $2"; shift ;;
|
|
( -f* ) FIND+=" ${1#-f}" ;;
|
|
( -I ) INCLUDES+=" -I $2"; shift ;;
|
|
( -I* ) INCLUDES+=" -I ${1#-I}" ;;
|
|
( ?(-)-[1-9]* )
|
|
VERSIONS=$(ls -1dvr /usr/local/epics/base$1*([.0-9]) | head -1)
|
|
EPICS=${VERSIONS##*-}
|
|
if [ "$EPICS" = "." ]
|
|
then
|
|
echo "No EPICS version ${1##*-} found" >&2
|
|
exit 1;
|
|
fi
|
|
;;
|
|
( -- | - ) shift; break ;;
|
|
( -* ) echo "Unknown option $1 ignored" >&2 ;;
|
|
( * ) break ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if [ $# = 0 ]
|
|
then
|
|
usage
|
|
fi
|
|
|
|
echo "Info: Using EPICS version $EPICS" >&2
|
|
|
|
function expandFile () {
|
|
if [ ! -r $1 ]
|
|
then
|
|
echo "can't read $1" >&2
|
|
return
|
|
fi
|
|
while read line
|
|
do
|
|
case $line in
|
|
( include* ) eval expandFile ${line#include} ;;
|
|
( * ) echo $line
|
|
esac
|
|
done < $1
|
|
}
|
|
|
|
{
|
|
SCAN=dbd/menuScan.dbd
|
|
if [ ! -r $SCAN ]
|
|
then
|
|
SCAN=dbd/scan.dbd
|
|
fi
|
|
if [ -r $SCAN ]
|
|
then
|
|
echo "# file $SCAN"
|
|
cat $SCAN
|
|
fi
|
|
CONVERT=dbd/slsConvert.dbd
|
|
if [ ! -r $CONVERT ]
|
|
then
|
|
CONVERT=$INSTBASE/epics/base/bin/R${EPICS}/slsConvert.dbd
|
|
fi
|
|
if [ -r $CONVERT ]
|
|
then
|
|
echo "# file $CONVERT"
|
|
cat $CONVERT
|
|
fi
|
|
MAINDBD=/usr/local/epics/base-${EPICS}/dbd/softIoc.dbd
|
|
if [ ! -r $MAINDBD ]
|
|
then
|
|
MAINDBD=$INSTBASE/iocBoot/R${EPICS}/dbd/base.dbd
|
|
fi
|
|
if [ ! -r $MAINDBD ]
|
|
then
|
|
echo "can't find base.dbd or softIoc.dbd" >&2
|
|
exit 1
|
|
fi
|
|
cat $MAINDBD
|
|
|
|
for dbd in dbd/*.dbd
|
|
do
|
|
case $dbd in
|
|
( */dbCommon.dbd ) ;;
|
|
( */*_conv.dbd ) ;;
|
|
( */slsConvert.dbd ) ;;
|
|
( */slsMain.dbd ) ;;
|
|
( */exampleApp.dbd ) ;;
|
|
( */menuScan.dbd ) ;;
|
|
( */scan.dbd ) ;;
|
|
( * ) echo "# file $dbd"; expandFile $dbd ;;
|
|
esac
|
|
done
|
|
|
|
echo $INSTBASE/iocBoot/R${EPICS}/dbd/+([^-]).dbd
|
|
|
|
for modulebase in ${EPICS_MODULES:=/ioc/modules}/*
|
|
do
|
|
debug modulebase: $modulebase > /dev/stderr
|
|
module=$(basename $modulebase)
|
|
if [ $module = base ]
|
|
then
|
|
continue
|
|
fi
|
|
debug module: $module > /dev/stderr
|
|
moduledir=$(ls -1rvd $modulebase/*.*.*/R${EPICS} | head -n 1)
|
|
[ $moduledir = "." ] && continue
|
|
debug moduledir: $moduledir > /dev/stderr
|
|
for dbd in $moduledir/dbd/*.dbd
|
|
do
|
|
debug dbd: $dbd > /dev/stderr
|
|
echo "# file $dbd $module"; cat $dbd
|
|
declare -A modules[$module]=$dbd
|
|
done
|
|
if [ -d $moduledir/db ]
|
|
then
|
|
debug includedir: $moduledir/db > /dev/stderr
|
|
INCLUDES+=" -I $moduledir/db"
|
|
fi
|
|
done
|
|
|
|
for dbd in $INSTBASE/iocBoot/R${EPICS}/dbd/+([^-]).dbd
|
|
do
|
|
if [ -L $dbd ]
|
|
then
|
|
module=$(basename $dbd)
|
|
module=${module%.dbd}
|
|
if [ "${modules[$module]}" = "" -a $module != base -a $module != slsMain -a $module != sls ]
|
|
then
|
|
echo "# file $dbd $module"; cat $dbd
|
|
fi
|
|
fi
|
|
done
|
|
|
|
for subs in $@
|
|
do
|
|
debug includes: $INCLUDES > /dev/stderr
|
|
echo "# file $subs"
|
|
dbLoadTemplate -L $INCLUDES -- $subs
|
|
done
|
|
} | awk \
|
|
-v where=$WHERE \
|
|
-v require=$REQUIRE \
|
|
-v debug=$DEBUG \
|
|
-v epics=$EPICS \
|
|
-v overwrite=$OVERWRITE \
|
|
-v findrecords="$FIND" \
|
|
-v epicsmodules=${EPICS_MODULES:=/ioc/modules} \
|
|
' BEGIN {
|
|
epics3_14ver=gensub(/^3\.14\./,"",1,epics)+0
|
|
split(findrecords, find, " ");
|
|
}
|
|
{line ++}
|
|
/# file / {
|
|
filename = $3
|
|
module = $4
|
|
if (!module && match(filename,epicsmodules)==1) {
|
|
/* happens for module templates only */
|
|
module = gensub(epicsmodules"/*([^/]*)/.*","\\1",1,filename)
|
|
if (debug) {
|
|
printf ("Using template %s requires \"%s\"\n", filename, module) > "/dev/stderr"
|
|
}
|
|
required[module] = 1
|
|
}
|
|
line = 0
|
|
if (debug) {
|
|
print "reading file " filename > "/dev/stderr"
|
|
print "module=" module > "/dev/stderr"
|
|
}
|
|
next
|
|
}
|
|
/# line / {
|
|
line = $3 -1
|
|
next
|
|
}
|
|
/^[ \t]*#/ { next }
|
|
/\{/ {context++}
|
|
/\}/ {context--}
|
|
/choice[ \t]*([ \t]*.*[ \t]*,[ \t]*".*"[ \t]*)/ {
|
|
if (valid) {
|
|
match($0,/\([ \t]*(.*)[ \t]*,[ \t]*"(.*)"/,a)
|
|
choice = a[2]
|
|
if (ischoice[menu,choice])
|
|
{
|
|
if (debug) {
|
|
printf("%s:%d\n\tduplicate choice %s for menu %s\n\t%s\n",
|
|
filename, line, choice, menu, definition[menu,choice]) > "/dev/stderr"
|
|
}
|
|
} else {
|
|
ischoice[menu,choice] = 1
|
|
enum[menu,choicenum[menu]++] = choice
|
|
choices[menu] = choices[menu] "\t\t\"" choice "\"\n"
|
|
modulename[menu,choice] = module
|
|
definition[menu,choice] = filename ":" line
|
|
}
|
|
}
|
|
}
|
|
/breaktable[ \t]*([ \t]*.*[ \t]*)/ {
|
|
if (valid) {
|
|
match($0,/\([ \t]*(.*)[ \t]*)/,a)
|
|
choice = a[1]
|
|
menu = "menuConvert"
|
|
if (ischoice[menu,choice])
|
|
{
|
|
if (debug) {
|
|
printf("%s:%d\n\tduplicate choice %s for menu %s\n\t%s\n",
|
|
filename, line, choice, menu, definition[menu,choice]) > "/dev/stderr"
|
|
}
|
|
} else {
|
|
ischoice[menu,choice] = 1
|
|
enum[menu,choicenum[menu]++] = choice
|
|
choices[menu] = choices[menu] "\""choice "\" "
|
|
modulename[menu,choice] = module
|
|
definition[menu,choice] = filename ":" line
|
|
}
|
|
}
|
|
}
|
|
/recordtype\(.*\)/ {
|
|
match($0,/\((.*)\)/,a)
|
|
rtype = a[1]
|
|
if (definition[rtype]) {
|
|
if (debug) {
|
|
printf("%s:%d\n\tduplicate recordtype %s\n\t%s\n",
|
|
filename, line, rtype, definition[rtype]) > "/dev/stderr"
|
|
}
|
|
if (modulename[rtype] !~ module) modulename[rtype] = modulename[rtype] "\" or \"" module
|
|
valid = 0
|
|
} else {
|
|
modulename[rtype] = module
|
|
definition[rtype] = filename ":" line
|
|
valid = 1
|
|
}
|
|
}
|
|
/field\(.*, *DBF_.*\)/ {if (!valid) next }
|
|
/field\(.*, *DBF_.*\)/ {
|
|
match($0,/\((.*),/,a)
|
|
field = a[1]
|
|
isfield[rtype,field] = 1
|
|
}
|
|
/field\(.*, *DBF_NOACCESS\)/ {
|
|
isnoaccess[rtype,field] = 1
|
|
next
|
|
}
|
|
/special\(SPC_DBADDR\)/ {
|
|
isnoaccess[rtype,field] = 0
|
|
next
|
|
}
|
|
/field\(.*, *DBF_.*\)/ {
|
|
if (field != "NAME") {
|
|
fields[rtype] = fields[rtype] "\t\t" field "\n"
|
|
}
|
|
}
|
|
/field\(.*, *DBF_.*LINK\)/ {
|
|
islink[rtype,field] = 1
|
|
next
|
|
}
|
|
/field\(.*, *DBF_STRING\)/ {
|
|
isstring[rtype,field] = 1
|
|
next
|
|
}
|
|
/field\(.*, *DBF_DEVICE\)/ {
|
|
isdevice[rtype,field] = 1
|
|
next
|
|
}
|
|
/field\(.*, *DBF_FLOAT\)/ {
|
|
isnumeric[rtype,field] = 1
|
|
next
|
|
}
|
|
/field\(.*, *DBF_DOUBLE\)/ {
|
|
isnumeric[rtype,field] = 1
|
|
next
|
|
}
|
|
/field\(.*, *DBF_ULONG\)/ {
|
|
isunsigned[rtype,field] = "ULONG"
|
|
range[rtype,field] = 0xffffffff
|
|
next
|
|
}
|
|
/field\(.*, *DBF_USHORT\)/ {
|
|
isunsigned[rtype,field] = "USHORT"
|
|
range[rtype,field] = 0xffff
|
|
next
|
|
}
|
|
/field\(.*, *DBF_UCHAR\)/ {
|
|
isunsigned[rtype,field] = "UCHAR"
|
|
range[rtype,field] = 0xff
|
|
next
|
|
}
|
|
/field\(.*, *DBF_LONG\)/ {
|
|
isinteger[rtype,field] = "LONG"
|
|
range[rtype,field] = 0x7fffffff
|
|
next
|
|
}
|
|
/field\(.*, *DBF_SHORT\)/ {
|
|
isinteger[rtype,field] = "SHORT"
|
|
range[rtype,field] = 0x7fff
|
|
next
|
|
}
|
|
/field\(.*, *DBF_CHAR\)/ {
|
|
isinteger[rtype,field] = "CHAR"
|
|
range[rtype,field] = 0x7f
|
|
next
|
|
}
|
|
/field\(.*, *DBF_ENUM\)/ {
|
|
isunsigned[rtype,field] = "ENUM"
|
|
range[rtype,field] = 0xffff
|
|
next
|
|
}
|
|
/menu\(.*\)/ {
|
|
if (context == 1) {
|
|
match($0,/\([ \t]*(.*)[ \t]*\)/,a)
|
|
menu = a[1]
|
|
if (choices[menu] != "") {
|
|
#printf("menu %s redefined\n", menu) > "/dev/stderr"
|
|
valid = 0
|
|
} else {
|
|
valid = 1
|
|
choicenum[menu] = 0
|
|
definition[menu] = filename ":" line
|
|
}
|
|
} else {
|
|
match($0,/\((.*)\)/,a)
|
|
menu = a[1]
|
|
menuname[rtype,field] = menu
|
|
}
|
|
}
|
|
/size\(.*\)/ {
|
|
if (valid) {
|
|
match($0,/\((.*)\)/,a)
|
|
stringsize[rtype,field] = a[1]-1
|
|
if (field == "NAME" && !maxNameLen) {
|
|
maxNameLen = stringsize[rtype,field]
|
|
}
|
|
}
|
|
}
|
|
/device[ \t]*\(.*\)/ {
|
|
match($0,/\([ \t]*(.*)[ \t]*,[ \t]*(.*)[ \t]*,.*,[ \t]*"(.*)"[ \t]*\)/,a)
|
|
rtype = a[1]
|
|
ltype = a[2]
|
|
dtype = a[3]
|
|
if (ltype == "CONSTANT") {
|
|
issoft[rtype,dtype] = 1 }
|
|
if (definition[rtype, dtype]) {
|
|
if (debug) {
|
|
printf("%s:%d\n\tduplicate device type \"%s\" for record type %s\n\t%s\n",
|
|
filename, line, dtype, rtype, definition[rtype, dtype]) > "/dev/stderr"
|
|
}
|
|
if (modulename[rtype] !~ module) modulename[rtype, dtype] = modulename[rtype, dtype] "\" or \"" module
|
|
} else {
|
|
modulename[rtype, dtype] = module
|
|
devices[rtype] = devices[rtype] "\t\t\"" dtype "\"\n"
|
|
definition[rtype, dtype] = filename ":" line
|
|
}
|
|
}
|
|
/record\(.*,".*"\)/ {
|
|
match($0,/\((.*),"(.*)"/,a)
|
|
rtype = a[1]
|
|
record = a[2]
|
|
if (recordtype[record] != "" && recordtype[record] != rtype) {
|
|
printf("%s:%d\n\trecord \"%s\" redefined with different type %s\n\tfirst defined as %s in %s\n",
|
|
filename, line, record, rtype, recordtype[record], definition[record]) > "/dev/stderr"
|
|
} else {
|
|
recordtype[record] = rtype
|
|
definition[record] = filename ":" line
|
|
if (modulename[rtype] && !required[modulename[rtype]]) {
|
|
if (debug) {
|
|
printf ("recordtype %s requires \"%s\"\n", rtype, modulename[rtype]) > "/dev/stderr"
|
|
}
|
|
required[modulename[rtype]] = 1
|
|
}
|
|
}
|
|
if (length(record)>maxNameLen && record !~ /\$\(.*\)/) {
|
|
printf("%s:%d\n\trecord name \"%s\" %d chars too long (max %d)\n\tmaybe this works with a higher EPICS version (this is %s)\n",
|
|
filename, line, record, length(record)-maxNameLen, maxNameLen, epics) > "/dev/stderr"
|
|
}
|
|
if (record ~ /[ \t.]/) {
|
|
printf("%s:%d\n\trecord \"%s\"\n\twhitespaces or dots are not allowed in record names\n",
|
|
filename, line, record) > "/dev/stderr"
|
|
}
|
|
soft = 1
|
|
}
|
|
/alias\(".*\",".*\")/ {
|
|
if (epics3_14ver < 11) {
|
|
printf ("%s:%d\n\t%s\n\trequires EPICS version >= 3.14.11 (this is %s)\n",
|
|
filename, line, $0, epics) > "/dev/stderr"
|
|
}
|
|
match($0,/\("(.*)","(.*)"/,a)
|
|
record = a[1]
|
|
aliasname = a[2]
|
|
if (recordtype[record] == "") {
|
|
printf ("%s:%d\n\talias \"%s\" undefined record \"%s\"\n",
|
|
filename, line, aliasname, record) > "/dev/stderr"
|
|
}
|
|
alias[aliasname] = record;
|
|
}
|
|
/field\(.*, ".*\")/ {
|
|
if (!stringsize[rtype,"NAME"]) next;
|
|
match($0,/\((.*), "(([^-+0-9\.][^\. ]*)?.*)"\)/,a)
|
|
field = a[1]
|
|
value = a[2]
|
|
menu = menuname[rtype,field]
|
|
|
|
if (fieldvalue[record,field] && fieldvalue[record,field] != value && !overwrite) {
|
|
printf("%s:%d\n\t%s record \"%s\" field %s\n\tWarning: value redefined from \"%s\" to \"%s\"\n\tfirst defined in %s\n",
|
|
filename, line, rtype, record, field, fieldvalue[record,field], value, definition[record,field]) > "/dev/stderr"
|
|
}
|
|
fieldvalue[record,field] = value
|
|
definition[record,field] = filename ":" line
|
|
if (value == "") next
|
|
knownproblem=known[filename,line,rtype,field,value]
|
|
known[filename,line,rtype,field,value]=1
|
|
if (!isfield[rtype,field] && !knownproblem) {
|
|
printf("%s:%d\n\t%s record \"%s\"\n\tUnknown field %s. Known fields:\n%s",
|
|
filename, line, rtype, record, field, fields[rtype]) > "/dev/stderr"
|
|
} else if (isnoaccess[rtype,field] && !knownproblem) {
|
|
printf("writing \"%s\" to NOACCESS field %s.%s\n",
|
|
value, record, field) > "/dev/stderr"
|
|
} else if (islink[rtype,field]) {
|
|
if (value !~ /^ *(\$\([^)]*\) *)*$/ && \
|
|
tolower(value) !~ /^ *[+-]?(0[0-7]*|0x[0-9a-f]+|[1-9][0-9]*|([0-9]+.?[0-9]*|[0-9]*.?[0-9]+)(e[-+]?[0-9]+)?|inf|nan) *$/ && \
|
|
((field != "INP" && field != "OUT") || soft)) {
|
|
reference[gensub(/ .*/,"",1,value)] = filename ":" line "\n\t" record "." field
|
|
}
|
|
if (field == "INP" || field == "OUT") {
|
|
iolink[record] = field
|
|
}
|
|
} else if (value ~ /\$\(.*\)/) {
|
|
} else if (isdevice[rtype,field]) {
|
|
if (iolink[record]) {
|
|
if (!dtyp[record] && !knownproblem) {
|
|
printf("%s defined after %s in record %s\n",
|
|
field, iolink[record], record) > "/dev/stderr"
|
|
}
|
|
}
|
|
if (!definition[rtype,value] && !knownproblem) {
|
|
printf("%s:%d\n\t%s record \"%s\" field %s\n\tUnknown device type \"%s\". Known types:\n%s",
|
|
filename, line, rtype, record, field, value, devices[rtype]) > "/dev/stderr"
|
|
} else {
|
|
if (modulename[rtype,value] && !required[modulename[rtype,value]]) {
|
|
if (debug && !knownproblem) {
|
|
printf ("%s \"%s\" for record type %s requires \"%s\"\n",
|
|
field, value, rtype, modulename[rtype,value]) > "/dev/stderr"
|
|
}
|
|
required[modulename[rtype,value]] = 1
|
|
}
|
|
}
|
|
soft = issoft[rtype,value]
|
|
dtyp[record] = value
|
|
} else if (knownproblem) {
|
|
next
|
|
} else if (menu != "") {
|
|
if (!ischoice[menu,value]) {
|
|
if (value != int(value) || value < 0)
|
|
{
|
|
printf("%s:%d\n\t%s record \"%s\" field %s\n\tUnknown %s choice \"%s\". Known choices:\n%s",
|
|
filename, line, rtype, record, field, menu, value, choices[menu]) > "/dev/stderr"
|
|
} else {
|
|
if (enum[menu,value] != "")
|
|
printf("%s:%d\n\t%s record \"%s\" field %s\n\tbetter use %s choice \"%s\" instead of number \"%s\"\n",
|
|
filename, line, rtype, record, field, menu, enum[menu,value], value) > "/dev/stderr"
|
|
}
|
|
}
|
|
} else if (isnumeric[rtype,field]) {
|
|
if (!match(tolower(value),/^ *[+-]?(0[0-7]*|0x[0-9a-f]+|[1-9][0-9]*|([0-9]+.?[0-9]*|[0-9]*.?[0-9]+)(e[-+]?[0-9]+)?|inf|nan) *$/)) {
|
|
printf("%s:%d\n\t%s record \"%s\" field %s\n\tvalue \"%s\" should be numeric\n",
|
|
filename, line, rtype, record, field, value) > "/dev/stderr"
|
|
}
|
|
} else if (isinteger[rtype,field]) {
|
|
if (!match(tolower(value),/^ *[+-]?(0[0-7]*|0x[0-9a-f]+|[1-9][0-9]*) *$/)) {
|
|
printf("%s:%d\n\t%s record \"%s\" field %s\n\tvalue \"%s\" should be %s (%d ... %d)\n",
|
|
filename, line, rtype, record, field, value, isinteger[rtype,field], -range[rtype,field]-1, range[rtype,field]) > "/dev/stderr"
|
|
}
|
|
if (value+0 > range[rtype,field] || value+1 < -range[rtype,field]) {
|
|
printf("%s:%d\n\t%s record \"%s\" field %s\n\tvalue %s is out of %s range %d ... %d\n",
|
|
filename, line, rtype, record, field, value, isinteger[rtype,field], -range[rtype,field]-1, range[rtype,field]) > "/dev/stderr"
|
|
}
|
|
} else if (isunsigned[rtype,field]) {
|
|
if (!match(tolower(value),/^ *+?(0[0-7]*|0x[0-9a-f]+|[1-9][0-9]*) *$/)) {
|
|
printf("%s:%d\n\t%s record \"%s\" field %s\n\tvalue \"%s\" should be %s (0 ... %d)\n",
|
|
filename, line, rtype, record, field, value, isunsigned[rtype,field], range[rtype,field]) > "/dev/stderr"
|
|
}
|
|
if (value+0 > range[rtype,field]) {
|
|
printf("%s:%d\n\t%s record \"%s\" field %s\n\tvalue %s is out of %s range 0 ... %d\n",
|
|
filename, line, rtype, record, field, value, isunsigned[rtype,field], range[rtype,field]) > "/dev/stderr"
|
|
}
|
|
} else if (isstring[rtype,field]) {
|
|
if (length(value)>stringsize[rtype,field]) {
|
|
printf("%s:%d\n\t%s record \"%s\" field %s\n\tstring \"%s\" is %d chars too long (max %d)\n",
|
|
filename, line, rtype, record, field, value,
|
|
length(value)-stringsize[rtype,field], stringsize[rtype,field]) > "/dev/stderr"
|
|
}
|
|
}
|
|
}
|
|
END {
|
|
for (target in reference) {
|
|
split(target,a,".")
|
|
record = a[1]
|
|
field = a[2]
|
|
if (alias[record] != "") { record = alias[record] }
|
|
for (r in find) {
|
|
if (record ~ find[r]) {print reference[target] " -> " target}
|
|
}
|
|
if (recordtype[record] == "") {
|
|
if (where) print reference[target] " -> " target
|
|
else print target
|
|
} else {
|
|
if (field == "") { field = "VAL" }
|
|
rtype = recordtype[record]
|
|
split (reference[target],a," ")
|
|
link = a[2]
|
|
if (!isfield[rtype,field]) {
|
|
if (!definition[rtype])
|
|
printf("%s:%d\n\tLink \"%s\"\n\tpoints to unknown record type %s.\n",
|
|
filename, line, link, rtype)
|
|
else
|
|
printf("%s:%d\n\tLink \"%s\"\n\tpoints to non-existing %s field \"%s.%s\". I only know:\n%s",
|
|
filename, line, link, rtype, record, field, fields[rtype]) > "/dev/stderr"
|
|
} else if (isnoaccess[rtype,field]) {
|
|
if (!(field == "TIME" && gensub(/.*\./,"",1,link) == "TSEL")) {
|
|
printf("%s:%d\n\tLink \"%s\" points to NOACCESS %s field \"%s.%s\"\n",
|
|
filename, line, link, rtype, record, field) > "/dev/stderr"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (require) {
|
|
for (module in required) {
|
|
printf ("require \"%s\"\n", module)
|
|
}
|
|
}
|
|
}
|
|
'
|