// DLSConfig.bcpl -- Alto DLS configuration file reader
// Last modified June 20, 1982 10:46 AM by Taft
// Last modified January 15, 1985 11:11 AM by Diebert
get "DLSDriver.decl"
get "Pup.decl"
get "DLSControl.decl"
get "DLSConfig.decl"
// Syntax of DLS configuration file:
// One or more entries, each terminated by return.
// <entry> ::= <line> <description> | // <comment>
// <line> ::= <octal line number of line being described>
// <description> ::= <attribute> | <description> <attribute>
// <attribute> ::= <lineType> | <controlLine> | <defaultHost> |
// <baudRate> | <terminalType> | <length> | <width> |
// <diallerInfo> | <stopBits> | <loopLine> | <otherAttribute>
// <lineType> ::= Unused | Hardwired | DataSet | Telenet | Log | <diallerStuff>
// <diallerStuff> ::= Dialler <diallerSignal> <diallerType> | Dialler <diallerSignal>
// <controlLine> ::= Control <line>
// <defaultHost> ::= Host <hostName>
// <baudRate> ::= Baud <decimal number>
// <terminalType> ::= Type <decimal number> // Tenex terminal type
// <length> ::= Length <decimal number> // Lines/page
// <width> ::= Width <decimal number> // Chars/line
// <diallerInfo> ::= DialOut <decimal number> <decimal number>
// <stopBits> ::= Stop 1 | Stop 2
// <loopLine> ::= Loop <line> // Implemented only in ChollaDLS
// <diallerSignal> ::= CRQ | DP | NB1 | NB2 | NB4 | NB8
// <diallerType> ::= DiallerType <decimal number>
// <otherAttribute> ::= DialOutOnly | NoPad | 8Bit
// Each entry must contain a <lineType>, and entries with <lineType> of
// DataSet or Telenet must contain a <ControlLine>.
// If a <baudRate> is specified, the line will run at that fixed rate.
// Normally <baudRate> is omitted, and speed determination is performed
// at connection time.
// Dial-out lines, as well as having a <controlLine> attribute, also
// have a <diallerInfo> attribute with two arguments:
// Modem address, i.e., Vadic card cage slot number (1-16) in the
// cage that has the dialler.
// Modem type: 1 = 103-compatible modem, 0 = Vadic modem
// 3 = 103/212 compatible modem, 2 = illegal
// There are 6 lines that control the dialler itself; each is declared by
// a "Dialler <diallerSignal>" entry, where the argument is the name
// of the output signal being controlled. Some of the lines also have
// input signals connected to them; the correspondence is:
// output: CRQ DP NB1 NB2 NB4 NB8
// input: PND ACR DSS -- -- --
// Each dialler has an associated DiallerType; declared by a
// a "DiallerType <decimal number>" entry, wher the number is
// 1 for a Vadic VA811 dialler and 0 for any other types
// You must code one "Log" line
// DialOutOnly means that the line is controlled exclusively from the network
// side; input from the line is ignored when the line is idle.
external
[
// Outgoing procedures
ReadDLSConfig
// Incoming procedures
OpenFile; Closes; Gets; FilePos; SetFilePos; ReadUserCmItem
Zero; CallSwat; Allocate; MoveBlock
ReturnFrom
]
static [ file; char; startPos; uniqueStringList = 0 ]
structure UniqueStr:
[
next word
string @String
]
// ---------------------------------------------------------------------------
let ReadDLSConfig(dlsConfig, zone) be
// ---------------------------------------------------------------------------
// Reads DLS configuration file and loads data into dlsConfig.
// Calls Swat if the file is malformed.
[
Zero(dlsConfig, lenDLSConfig)
let parsed = false
// First look for [DLS] section in User.cm
let userCm = OpenFile("User.cm", ksTypeReadOnly, charItem)
if userCm ne 0 then
[
let token = vec 127
let inDLSSection = false
switchon ReadUserCmItem(userCm, token) into
[ // repeat
case $N:
inDLSSection = StringEq(token, "DLS")
endcase
case $L:
if inDLSSection then
test StringEq(token, "Indirect") ifso
[ // Indirect: fileName
ReadUserCmItem(userCm, token)
ParseDLSConfig(dlsConfig, token, zone)
parsed = true
]
ifnot test StringEq(token, "Name") ifso
[ // Name: name
ReadUserCmItem(userCm, token)
dlsConfig>>DLSConfig.name = MakeUniqueString(token, zone)
]
ifnot test StringEq(token, "Registry") ifso
[ // Registry: reg
ReadUserCmItem(userCm, token)
dlsConfig>>DLSConfig.thisRegistry = MakeUniqueString(token, zone)
]
ifnot test StringEq(token, "AuthorizationList") ifso
[ // AuthorizationList: list
ReadUserCmItem(userCm, token)
dlsConfig>>DLSConfig.thisOutList = MakeUniqueString(token, zone)
]
ifnot test StringEq(token, "InAuthorizationList") ifso
[ // AuthorizationList: list
ReadUserCmItem(userCm, token)
dlsConfig>>DLSConfig.thisInList = MakeUniqueString(token, zone)
]
ifnot test StringEq(token, "WizardList") ifso
[ // WizardList: list
ReadUserCmItem(userCm, token)
dlsConfig>>DLSConfig.thisWizardList = MakeUniqueString(token, zone)
]
ifnot CallSwat("[ReadDLSConfig] Undefined User.cm item:", token)
endcase
case $E:
break
] repeat
Closes(userCm)
]
// If nothing found in User.cm, assume correct name is DLS.config.
unless parsed do ParseDLSConfig(dlsConfig, "DLS.config", zone)
if dlsConfig>>DLSConfig.name eq 0 then
dlsConfig>>DLSConfig.name = MakeUniqueString("DLS", zone)
if dlsConfig>>DLSConfig.thisRegistry eq 0 then
dlsConfig>>DLSConfig.thisRegistry = MakeUniqueString("PA", zone)
if dlsConfig>>DLSConfig.thisWizardList eq 0 then
dlsConfig>>DLSConfig.thisWizardList = MakeUniqueString("DLSWizards↑.PA", zone)
]
// ---------------------------------------------------------------------------
and ParseDLSConfig(dlsConfig, fileName, zone) be
// ---------------------------------------------------------------------------
[
file = OpenFile(fileName, ksTypeReadOnly, charItem)
if file eq 0 then CallSwat("[ReadDLSConfig] Can't find configuration file:", fileName)
let MyStreamError(file, ec) be [ Closes(file); ReturnFrom(ParseDLSConfig) ]
file>>ST.error = MyStreamError
[ //repeat
char = Gets(file) repeatwhile char eq $*n % char eq $*s % char eq $*t % char eq $*014
if char eq $; % char eq $/ then
[ char = Gets(file) repeatuntil char eq $*n; loop ]
startPos = FilePos(file)-1
let line = ReadLineNumber(file)
let lc = lv dlsConfig>>DLSConfig.lc↑line
if lc>>LC.lineType ne ltUnused then
Malformed("[ReadDLSConfig] Duplicate line entry")
let string = vec 127
until char eq $*n do
[
ReadToken(file, string)
test StringEq(string, "Baud") ifso
lc>>LC.data.constantBaud = ReadNumber(file)
ifnot test StringEq(string, "Control") ifso
[
let otherLine = ReadLineNumber(file)
lc>>LC.otherLine = otherLine
dlsConfig>>DLSConfig.lc↑otherLine.lineType = ltControl
dlsConfig>>DLSConfig.lc↑otherLine.otherLine = line
]
ifnot test StringEq(string, "DataSet") ifso
lc>>LC.lineType = ltDataSet
ifnot test StringEq(string, "Log") ifso
lc>>LC.lineType = ltLog
ifnot test StringEq(string, "Dialler") ifso
[
lc>>LC.lineType = ltDialler
ReadToken(file, string)
lc>>LC.dialler.signalIndex =
StringEq(string, "CRQ")? 0, StringEq(string, "DP")? 1,
StringEq(string, "NB1")? 2, StringEq(string, "NB2")? 3,
StringEq(string, "NB4")? 4, StringEq(string, "NB8")? 5, Malformed()
]
ifnot test StringEq(string, "DiallerType") ifso
lc>>LC.data.diallerType = ReadRangeCheckedNumber(file, 10, 0, 1)
ifnot test StringEq(string, "DialOut") ifso
[
lc>>LC.dialOut = true
lc>>LC.data.modemAddress = ReadRangeCheckedNumber(file, 10, 1, 15)-1
lc>>LC.data.modemType = ReadRangeCheckedNumber(file, 10, 0, 3)
]
ifnot test StringEq(string, "DialOutOnly") ifso
lc>>LC.data.dialOutOnly = true
ifnot test StringEq(string, "Hardwired") ifso
lc>>LC.lineType = ltHardwired
ifnot test StringEq(string, "Host") ifso
lc>>LC.data.host = ReadUniqueString(file, zone)
ifnot test StringEq(string, "Length") ifso
lc>>LC.data.terminalLength = ReadNumber(file)
ifnot test StringEq(string, "Loop") ifso
lc>>LC.otherLine = ReadLineNumber(file)
ifnot test StringEq(string, "NoPad") ifso
lc>>LC.data.noPad = true
// ParseDLSConfig(dlsConfig, fileName, zone) continued
ifnot test StringEq(string, "8Bit") ifso
lc>>LC.data.eightBit = true
ifnot test StringEq(string, "Stop") ifso
lc>>LC.data.stopBits = ReadRangeCheckedNumber(file, 10, 1, 2)
ifnot test StringEq(string, "Telenet") ifso
lc>>LC.lineType = ltTelenet
ifnot test StringEq(string, "Type") ifso
lc>>LC.data.terminalType = ReadNumber(file)
ifnot test StringEq(string, "Unused") ifso
lc>>LC.lineType = ltUnused
ifnot test StringEq(string, "Width") ifso
lc>>LC.data.terminalWidth = ReadNumber(file)
ifnot Malformed("[ReadDLSConfig] Undefined attribute")
]
] repeat
]
// ---------------------------------------------------------------------------
and ReadLineNumber(file) = ReadRangeCheckedNumber(file, 8, 0, numLines-1)
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
and ReadRangeCheckedNumber(file, radix, min, max) = valof
// ---------------------------------------------------------------------------
[
let num = ReadNumber(file, radix)
if num ls min % num gr max then
Malformed("[ReadDLSConfig] Number out of range")
resultis num
]
// ---------------------------------------------------------------------------
and ReadNumber(file, radix; numargs na) = valof
// ---------------------------------------------------------------------------
[
if na ls 2 then radix = 10
let string = vec 127
let length = ReadToken(file, string)
let num = 0
for i = 1 to length do
[
let digit = string>>String.char↑i - $0
if digit ls 0 % digit ge radix then Malformed()
num = radix*num + digit
]
resultis num
]
// ---------------------------------------------------------------------------
and ReadUniqueString(file, zone) = valof
// ---------------------------------------------------------------------------
[
let string = vec 127
ReadToken(file, string)
resultis MakeUniqueString(string, zone)
]
// ---------------------------------------------------------------------------
and MakeUniqueString(string, zone) = valof
// ---------------------------------------------------------------------------
[
let uniqueStr = uniqueStringList
while uniqueStr ne 0 do
[
if StringEq(string, lv uniqueStr>>UniqueStr.string) then
resultis lv uniqueStr>>UniqueStr.string
uniqueStr = uniqueStr>>UniqueStr.next
]
let len = string>>String.length rshift 1 +1
uniqueStr = Allocate(zone, len + offset UniqueStr.string/16)
MoveBlock(lv uniqueStr>>UniqueStr.string, string, len)
uniqueStr>>UniqueStr.next = uniqueStringList
uniqueStringList = uniqueStr
resultis lv uniqueStr>>UniqueStr.string
]
// ---------------------------------------------------------------------------
and ReadToken(file, string) = valof
// ---------------------------------------------------------------------------
[
let length = 0
while char eq $*s % char eq $*t do char = Gets(file)
if char eq $*n then Malformed()
[
length = length+1
string>>String.char↑length = char
char = Gets(file)
] repeatuntil char eq $*s % char eq $*t % char eq $*n % char eq $;
string>>String.length = length
while char eq $*s % char eq $*t do char = Gets(file)
if char eq $/ then until char eq $*n do char = Gets(file)
resultis length
]
// ---------------------------------------------------------------------------
and StringEq(str1, str2) = valof
// ---------------------------------------------------------------------------
[
if str1>>String.length ne str2>>String.length resultis false
for i = 1 to str1>>String.length do
[
let c1 = str1>>String.char↑i
if c1 ge $a & c1 le $z then c1 = c1-($a-$A)
let c2 = str2>>String.char↑i
if c2 ge $a & c2 le $z then c2 = c2-($a-$A)
if c1 ne c2 resultis false
]
resultis true
]
// ---------------------------------------------------------------------------
and Malformed(message; numargs na) be
// ---------------------------------------------------------------------------
[
if na eq 0 then message = "[ReadDLSConfig] Configuration file malformed"
let text = vec 127
SetFilePos(file, 0, startPos)
for i = 1 to 255 do
[
text>>String.char↑i = Gets(file)
text>>String.length = i
if text>>String.char↑i eq $*n break
]
CallSwat(message, text)
]