-- MessageParse.mesa
-- Edited by Brotz, March 26, 1982 1:27 PM

DIRECTORY
vmD: FROM "VirtualMgrDefs" USING [CharIndex, ComposedMessagePtr, VirtualMessagePtr];

MessageParse: DEFINITIONS =

BEGIN

-- This interface provides a fast, simplified message parser. The functions supplied here do
-- not adhere to every nuance of the Arpa standard message header syntax. Instead, a
-- simple subset of that standard is supported. In almost all cases, this parser is sufficient
-- for field parsing, as long as complicated address fields are not used.

-- As in the Arpa standard, a carriage return followed by a blank or tab character is
-- considered to be white space and does not terminate a field body. The first character
-- of a field name must immediately follow a carriage return (or be the first character in
-- the message. After this first character, blanks and tabs are ignored until a colon is
-- encountered. The de-blanked text from the first character until (but not including)
-- the colon is considered the field name. Capitalization is irrelevent is field names.


ParseFault: ERROR [error: ParseError];
-- Raised by GetNextWord and GetNextNumber due to the exceptional condition indicated
-- by error. If raised with error = stringTooSmall, then the calling procedure may be
-- RETRY’ed with a larger string.

ParseError: TYPE = {stringTooSmall, illegalNumber};

FieldRec: TYPE = RECORD
[name: STRING,
bodyStart, bodyEnd: vmD.CharIndex,
found: CARDINAL];
FieldRecPtr: TYPE = POINTER TO FieldRec;
FieldRecDescriptor: TYPE = DESCRIPTOR FOR ARRAY OF FieldRec;

ParseMessage: PROCEDURE [vm: vmD.VirtualMessagePtr, fields: FieldRecDescriptor];
-- The message in vm is scanned for field names matching the set of names given in fields.
-- The number of times each field name is encountered in vm is set in the found field
-- corresponding to that field name. For any field whose found number is greater than
-- or equal to 1, the bodyStart field is set to the index of the first character following the
-- field name’s colon, and the bodyEnd field is set to the CharIndex of the first carriage
-- return (or end of message) that terminates that field body. If found = 0, then bodyStart
-- and bodyEnd are 0. vm is searched for fields from [0 .. MessageLength[vm]).


FieldListRec: TYPE = RECORD
[field: STRING,
start, valueStart, valueEnd: vmD.CharIndex,
next: FieldList];
FieldList: TYPE = POINTER TO FieldListRec;
FieldListPtr: TYPE = POINTER TO FieldList;


MakeFieldList: PROCEDURE [vm: vmD.VirtualMessagePtr] RETURNS [fieldList: FieldList];
-- Creates a complete list of fields contained in vm. The fields in the list are sorted by
-- position in vm.


FreeFieldList: PROCEDURE [fieldList: FieldList];
-- Frees all storage associated with fieldList.


LocateField: PROCEDURE [fieldList: FieldList, name: STRING]
RETURNS [field: FieldList, count: CARDINAL];
-- Searches fieldList for a FieldListRec matching name. Returns a pointer to the matched
-- FieldListRec and a count of how many matches actually occur in the list.


UpdateFieldList: PROCEDURE [fieldList: FieldList, delta: INTEGER];
-- Increments the CharIndex’s in the Field List starting at fieldList by delta. This procedure
-- should be used whenever editing causes modifications in field positions.


ReplaceOrAppendField: PROCEDURE
[cm: vmD.ComposedMessagePtr, fieldListPtr: MessageParse.FieldListPtr,
field, value: STRING, insertAtBeginning: BOOLEAN ← FALSE];


DeleteField: PROCEDURE
[cm: vmD.ComposedMessagePtr, fieldListPtr: MessageParse.FieldListPtr, name: STRING];


GetNumberFromField: PROCEDURE
[vm: vmD.VirtualMessagePtr, fieldList: FieldList, s: STRING] RETURNS [value: CARDINAL];


GetStringFromField: PROCEDURE
[vm: vmD.VirtualMessagePtr, fieldList: FieldList, field, value: STRING];
-- Returns in "value" the first word in the value portion of the "field" of "vm".


GetWholeField: PROCEDURE
[vm: vmD.VirtualMessagePtr, fieldList: FieldList, name, value: STRING];


GetNextWord: PROCEDURE [vm: vmD.VirtualMessagePtr, start, end: vmD.CharIndex,
s: STRING, includePlusAndMinus: BOOLEAN ← TRUE]
RETURNS [newStart: vmD.CharIndex];
-- Within vm[[start .. end)], the next word (run of non-whitespace characters) in vm is
-- copied into s. Leading whitespace characters are ignored. newStart is the CharIndex
-- suitable for passing into GetNextWord or GetNextNumber to get a subsequent word or
-- number.
-- IF includePlusAndMinus is TRUE, then + and - are treated as if they were alphanumeric.
-- May raise ParseFault[stringTooSmall] if the word to be copied into s is larger than
-- s.maxlength.


GetNextNumber: PROCEDURE [vm: vmD.VirtualMessagePtr, start, end: vmD.CharIndex,
s: STRING] RETURNS [newStart: vmD.CharIndex];
-- Within vm[[start .. end)], the next number (defined as [+/-]D*.D*[E[+/-]D*], where
-- [x] indicates an optional part, +/- indicates either a plus or minus sign, D* is 0 or
-- more digits, E is the letter E) in vm is copied into s. Examples: 10, -23, +.34, 2.1E-12,
-- 1E3, 0.2. Leading whitespace characters are ignored. newStart is the CharIndex
-- suitable for passing into GetNextWord or GetNextNumber to get a subsequent word
-- or number.
-- May raise ParseFault[stringTooSmall] if the number to be copied into s is larger than
-- s.maxlength. May raise ParseFault[illegalNumber] if no legal number occurs next in
-- vm.

END. -- of MessageParse --