Copyright Ó 1983, 1985 , 1992by Xerox Corporation. All rights reserved.
File: AdobeToolContextImplB.mesa
MXF   6-May-83 10:30:26
RSF   4-Apr-86 14:06:00
JCS  10-Oct-85 10:58:23
Philip James, February 21, 1991 11:32 am PST
Christian Jacobi, April 7, 1992 5:44 pm PDT
DIRECTORY
AdobeOps USING [
EnumeratedSequence, FieldList, KeyedPossibilities],
AdobeToolContext,
ARAccess USING [--AppendChar, --ARStorage, DataTable],
Ascii USING [CR, SP],
Date USING [Packed, PackedToString, StringToPacked, Unintelligible],
Rope USING [Equal, ROPE];
String USING [
AppendChar, AppendLongDecimal, AppendStringAndGrow, Copy,
CopyToNewString, EmptyString,
Equivalent, MakeString, Replace, StringBoundsFault,
StringToLongNumber],
Stream USING [
Block, CompletionCode, defaultObject, DeleteProcedure,
EndOfStream, GetProcedure, Handle, Object, PutProcedure,
SubSequenceType],
Time USING [Current, defaultTime];
AdobeToolContextImplB: CEDAR MONITOR --LOCKS LOOPHOLE[sH, MyStreamHandle].lock USING sH: Stream.Handle
IMPORTS --AdobeOps, Date,-- Rope --, Stream, String, Time
EXPORTS AdobeToolContext = BEGIN
DataTableHandle: TYPE = REF DataTable;
DataTable: TYPE = RECORD [
index: CARDINAL,
fieldValueSeq: SEQUENCE length: CARDINAL OF DataPair];
DataPair: TYPE = RECORD[
fieldName: Rope.ROPE ¬ NIL,
value: Rope.ROPE ¬ NIL];
BufferHandle: TYPE = REF PACKED ARRAY [0..0) OF CHARACTER;
PutStateType: TYPE = {normal, wasQuote, wasCR, wasColon};
GetStateType: TYPE = {
normal, needsDoubleCR, needsColonSpace};
FieldStateType: TYPE = {
normal, endOfFieldName, noValueField, endOfValue, noValueFieldAndendOfData,
endOfData};
FieldType: TYPE = {fieldName, fieldValue};
nextPosInGetBlockType: TYPE = RECORD [
indexInSeq: CARDINAL ¬ 0,
fieldType: FieldType ¬ fieldName,
indexInString: CARDINAL ¬ 0];
ClientData: TYPE = REF Data;
Data: TYPE = RECORD [
data: DataTableHandle ¬ NIL,
dataTableIsDirty: BOOLEAN ¬ FALSE,
dataString: Rope.ROPE ¬ NIL,
prevPutBufState: PutStateType ¬ normal,
prevGetBufState: GetStateType ¬ normal,
fieldState: FieldStateType ¬ normal,
wasSpecialChar: BOOLEAN ¬ FALSE,
cachedField: Rope.ROPE ¬ NIL,
nextPosInGetBlock: nextPosInGetBlockType ¬ []];
MyStreamHandle: TYPE = REF MyStreamObject;
MyStreamObject: TYPE = RECORD [
lock: MONITORLOCK,
stream: Stream.Object ← Stream.defaultObject];
BlockTooSmall: PUBLIC ERROR = CODE;
StreamError: PUBLIC ERROR [type: AdobeToolContext.Type] = CODE;
EndOfBuffer: ERROR [bytesTransferred: CARDINAL, state: GetStateType] = CODE;
EnumError: PUBLIC ERROR [
why: AdobeToolContext.EnumProblemType]= CODE;
quoteChar: CHARACTER = '';
crChar: CHARACTER = Ascii.CR;
spaceChar: CHARACTER = Ascii.SP;
colonChar: CHARACTER = ':;
AllocateStreamObject: PROCEDURE RETURNS[handle: LONG POINTER] =
Loopholes MyStreamObject into StreamObject so can have a MONITOR LOCK
{RETURN [z.NEW[MyStreamObject ← []]]};
AllocateDataTable: PROCEDURE[fL: AdobeOps.FieldList] RETURNS[data: ARAccess.ARStorage] =
{
allocate the table
data ¬ NEW[ARAccess.DataTable[fL.length]];
FOR i: CARDINAL IN [0..data.length) DO
data[i] ¬ [fL[i].name, NIL];
ENDLOOP;
};
CreateStream: PUBLIC PROCEDURE [fL: AdobeOps.FieldList]
RETURNS [handle: ARAccess.ARStorage] = {
handle ← AllocateStreamObject[];
handle ¬ AllocateDataTable[fL: fL];
handle.clientData ← NEW[Data ← [data: AllocateDataTable[fL: fL]]];
handle.put ← MyPutProc;
handle.get ← MyGetProc;
handle.delete ← MyDeleteProc;
};
MyDeleteProc: Stream.DeleteProcedure =
BEGIN
myStreamHandle: MyStreamHandle ← LOOPHOLE[sH];
DeleteStream[sH];
z.FREE[@myStreamHandle];
END;
DeleteStream: ENTRY PROCEDURE [sH: Stream.Handle] =
BEGIN
ENABLE UNWIND => NULL;
myClientData: ClientData ← sH.clientData;
z.FREE[@myClientData.dataString];
z.FREE[@myClientData.cachedField];
FOR i: CARDINAL IN [0..myClientData.data.length) DO
z.FREE[@myClientData.data[i].fieldName];
z.FREE[@myClientData.data[i].value];
ENDLOOP;
z.FREE[@sH.clientData];
END;
MyPutProc: ENTRY Stream.PutProcedure =
BEGIN
ENABLE UNWIND => NULL;
IF block.stopIndexPlusOne # 0 THEN
BuildDataTable[block, sH.clientData];
else no more data to put into table
END;
MyGetProc: ENTRY Stream.GetProcedure =
BEGIN
ENABLE UNWIND => NULL;
[bytesTransferred, why, sst] ← PutDataTableIntoBlock[block, sH.clientData];
IF options.signalEndOfStream AND why = endOfStream THEN
SIGNAL Stream.EndOfStream[bytesTransferred];
END;
HandleLastBuffersSpecialCharOnGet: PROCEDURE [
buff: BufferHandle, index: CARDINAL, sData: ClientData]
RETURNS [newIndex: CARDINAL ← 0] =
BEGIN
SELECT sData.fieldState FROM
endOfFieldName =>
IF sData.prevGetBufState = needsColonSpace
THEN index ← AppendSpecialChars[buff, index, needsColonSpace]
ELSE ERROR StreamError[badFieldNameField];
endOfValue, noValueField, noValueFieldAndendOfData =>
IF sData.prevGetBufState = needsDoubleCR
THEN index ← AppendSpecialChars[buff, index, needsDoubleCR]
ELSE ERROR StreamError[badValueField];
ENDCASE;
sData.prevGetBufState ← normal;
RETURN [index];
END;
RequiresQuote: PROCEDURE[char: CHARACTER, sData: ClientData]
RETURNS[itDoes: BOOLEAN ¬ FALSE] = INLINE
BEGIN
IF sData.wasSpecialChar THEN RETURN [sData.wasSpecialChar ¬ FALSE]
ELSE SELECT char FROM
quoteChar, colonChar, crChar => RETURN[sData.wasSpecialChar ¬ TRUE]
ENDCASE => RETURN[FALSE];
END;
GetCharFromData: PROCEDURE [sData: ClientData]
RETURNS [char: CHARACTER, state: FieldStateType] =
BEGIN OPEN nP: sData.nextPosInGetBlock;
SELECT nP.fieldType FROM
fieldName =>
BEGIN
char ← sData.data[nP.indexInSeq].fieldName[nP.indexInString];
IF ~RequiresQuote[char, sData] THEN
IF nP.indexInString + 1 < sData.data[nP.indexInSeq].fieldName.length THEN {
nP.indexInString ← nP.indexInString + 1; RETURN[char, normal]}
ELSE {nP ← [nP.indexInSeq, fieldValue, 0]; RETURN[char, endOfFieldName]}
ELSE RETURN[quoteChar, normal];
END;
fieldValue =>
BEGIN
IF (nP.indexInString = 0) AND (sData.data[nP.indexInSeq].value = NIL OR sData.data[nP.indexInSeq].value.length = 0) THEN
IF nP.indexInSeq + 1 < sData.data.length THEN {
nP ← [nP.indexInSeq + 1, fieldName, 0]; RETURN[NULL, noValueField]}
ELSE {nP ← [0, fieldName, 0]; RETURN[NULL, noValueFieldAndendOfData]};
char ← sData.data[nP.indexInSeq].value[nP.indexInString];
IF ~RequiresQuote[char, sData] THEN
IF nP.indexInString + 1 < sData.data[nP.indexInSeq].value.length THEN {
nP.indexInString ← nP.indexInString + 1; RETURN[char, normal]}
ELSE
IF nP.indexInSeq + 1 < sData.data.length THEN {
nP ← [nP.indexInSeq + 1, fieldName, 0]; RETURN[char, endOfValue]}
ELSE {nP ← [0, fieldName, 0]; RETURN[char, endOfData]}
ELSE RETURN[quoteChar, normal];
END;
ENDCASE;
END;
PutDataTableIntoBlock: PROCEDURE [block: Stream.Block, streamData: ClientData]
RETURNS [
charsTransferred: CARDINAL ← 0, why: Stream.CompletionCode,
sst: Stream.SubSequenceType] =
BEGIN
minBufSize: CARDINAL = 2;
buff: BufferHandle ← LOOPHOLE[block.blockPointer];
buffIndex: CARDINAL ← block.startIndex;
IF block.stopIndexPlusOne - buffIndex < minBufSize THEN ERROR BlockTooSmall;
IF streamData.prevGetBufState # normal THEN
SELECT streamData.fieldState FROM
endOfFieldName, endOfValue, noValueField =>
buffIndex ← HandleLastBuffersSpecialCharOnGet[
buff, buffIndex, streamData];
noValueFieldAndendOfData =>
RETURN[
HandleLastBuffersSpecialCharOnGet[buff, buffIndex, streamData],
endOfStream, 0];
ENDCASE;
WHILE buffIndex < block.stopIndexPlusOne DO
char: CHARACTERNULL;
numOfSpecialChars: CARDINAL = 2;
[char, streamData.fieldState] ← GetCharFromData[streamData];
IF (streamData.fieldState # noValueField)
AND (streamData.fieldState # noValueFieldAndendOfData)
THEN buffIndex ← CharToBuffer[char, buff, buffIndex];
SELECT streamData.fieldState FROM
normal => NULL;
endOfFieldName =>
BEGIN
IF WillFit[numOfSpecialChars, buffIndex, block.stopIndexPlusOne]
THEN buffIndex ← AppendSpecialChars[buff, buffIndex, needsColonSpace]
ELSE {
streamData.prevGetBufState ← needsColonSpace;
RETURN[buffIndex, normal, 0]};
END;
endOfValue =>
BEGIN
IF WillFit[numOfSpecialChars, buffIndex, block.stopIndexPlusOne]
THEN buffIndex ← AppendSpecialChars[buff, buffIndex, needsDoubleCR]
ELSE {
streamData.prevGetBufState ← needsDoubleCR;
RETURN[buffIndex, normal, 0]};
END;
noValueField =>
IF WillFit[numOfSpecialChars, buffIndex, block.stopIndexPlusOne]
THEN buffIndex ← AppendSpecialChars[buff, buffIndex, needsDoubleCR]
ELSE {
streamData.prevGetBufState ← needsDoubleCR;
RETURN[buffIndex, normal, 0]};
noValueFieldAndendOfData =>
IF WillFit[numOfSpecialChars, buffIndex, block.stopIndexPlusOne] THEN
BEGIN
buffIndex ← AppendSpecialChars[buff, buffIndex, needsDoubleCR];
streamData.prevGetBufState ← normal;
streamData.fieldState ← normal;
RETURN[buffIndex, endOfStream, 0];
END
ELSE {
streamData.prevGetBufState ← needsDoubleCR;
RETURN[buffIndex, normal, 0]};
endOfData =>
BEGIN
IF WillFit[numOfSpecialChars, buffIndex, block.stopIndexPlusOne] THEN
BEGIN
buffIndex ← AppendSpecialChars[buff, buffIndex, needsDoubleCR];
streamData.prevGetBufState ← normal;
streamData.fieldState ← normal;
RETURN[buffIndex, endOfStream, 0];
END
ELSE {
streamData.prevGetBufState ← needsDoubleCR;
RETURN[buffIndex, normal, 0]};
END;
ENDCASE;
ENDLOOP;
RETURN[buffIndex, normal, 0];
END;
WillFit: PROCEDURE [numOfChars: CARDINAL, index: CARDINAL, length: CARDINAL]
RETURNS [itWill: BOOLEAN ¬ TRUE] = INLINE {RETURN[index + numOfChars - 1 < length]};
AppendSpecialChars: PROCEDURE[buff: BufferHandle, index: CARDINAL, specialCharType: GetStateType[needsDoubleCR..needsColonSpace]] RETURNS [newIndex: CARDINAL ¬ 0] = INLINE
BEGIN
SELECT specialCharType FROM
needsColonSpace => {
index ¬ CharToBuffer[colonChar, buff, index];
index ¬ CharToBuffer[spaceChar, buff, index]};
needsDoubleCR => {
index ¬ CharToBuffer[crChar, buff, index];
index ¬ CharToBuffer[crChar, buff, index]};
ENDCASE;
RETURN[index];
END;
CharToBuffer: PROCEDURE [
char: CHARACTER, buff: BufferHandle, index: CARDINAL]
RETURNS [newIndex: CARDINAL ¬ 0] = INLINE
BEGIN
buff[index] ¬ char;
newIndex ¬ index + 1;
END;
use ARAccess.AppendChar;
AppendChar: PROCEDURE [char: CHARACTER, string: REF Rope.ROPE] =
BEGIN
string^ ← string^.Concat[Convert.RopeFromChar[char, FALSE]];
String.AppendChar[
string­, char !
String.StringBoundsFault =>
BEGIN
additionalLength: CARDINALIF s.length < 120 THEN s.length/2 ELSE 480; -- characters
ns ← String.CopyToNewString[
s: s, longer: additionalLength, z: z];
z.FREE[@s];
RESUME [string­ ← ns];
END; ];
END;
StateOfLastChar: PROCEDURE [char: CHARACTER] RETURNS [type: PutStateType] =
BEGIN
RETURN[
SELECT char FROM
quoteChar => wasQuote,
crChar => wasCR,
colonChar => wasColon,
ENDCASE => normal];
END;
HandleLastBuffersSpecialCharOnPut: PROCEDURE [
buff: BufferHandle, index: CARDINAL, sData: ClientData]
RETURNS [newIndex: CARDINAL] =
BEGIN
SELECT sData.prevPutBufState FROM
wasQuote => AppendChar[buff[index], @sData.dataString];
wasCR =>
IF buff[index] # crChar THEN ERROR StreamError[badValueField]
ELSE
IF sData.cachedField = NIL THEN
ERROR StreamError[missingFieldNameField]
ELSE
BEGIN
sData.data[
SearchForField[sData.data, sData.cachedField]].value ←
IF sData.dataString.length > 0 THEN String.CopyToNewString[
sData.dataString, z] ELSE NIL;
z.FREE[@sData.cachedField];
sData.dataString.length ← 0;
END;
wasColon =>
IF buff[index] # spaceChar THEN ERROR StreamError[badFieldNameField]
ELSE
IF ~String.EmptyString[sData.cachedField] THEN
ERROR StreamError[missingValueField]
ELSE
BEGIN -- cache field name
sData.cachedField ← String.CopyToNewString[
sData.dataString, z];
sData.dataString.length ← 0;
END;
ENDCASE;
RETURN[index + 1];
END;
BuildDataTable: PROCEDURE [block: Stream.Block, streamData: ClientData] =
BEGIN
startingSize: CARDINAL = 100;
buffIndex: CARDINAL ← block.startIndex;
buff: BufferHandle ← LOOPHOLE[block.blockPointer];
IF streamData.dataString = NIL THEN
BEGIN
streamData.dataString ← z.NEW[StringBody [startingSize]];
streamData.dataString.length ← 0;
END;
IF streamData.prevPutBufState # normal THEN
buffIndex ← HandleLastBuffersSpecialCharOnPut[buff, buffIndex, streamData];
process characters up to but not including the last one
do this because a number of cases need to look one ahead
WHILE buffIndex < block.stopIndexPlusOne - 1 DO
BEGIN ENABLE
UNWIND => {
IF streamData.cachedField # NIL THEN {
streamData.cachedField.length ← 0;
streamData.dataString.length ← 0}};
char: CHARACTER ← buff[buffIndex];
SELECT char FROM
crChar => --end of value field
look ahead to next CR
IF buff[buffIndex + 1] # crChar THEN
ERROR StreamError[badValueField]
ELSE
IF String.EmptyString[streamData.cachedField] THEN
ERROR StreamError[missingFieldNameField]
ELSE
BEGIN
tableIndex: CARDINAL ← SearchForField[
streamData.data, streamData.cachedField];
IF streamData.data[tableIndex].value = NIL THEN
streamData.data[tableIndex].value ←
String.CopyToNewString[streamData.dataString, z]
ELSE {
streamData.data[tableIndex].value.length ← 0;
String.AppendStringAndGrow[
@streamData.data[tableIndex].value,
streamData.dataString, z, 20]};
streamData.cachedField.length ← 0;
streamData.dataString.length ← 0;
jump over the second CR
buffIndex ← buffIndex + 2;
END;
quoteChar =>
BEGIN --next character is NOT a special character
skip over quote and process next character
buffIndex ← buffIndex + 1;
char ← buff[buffIndex];
AppendChar[char, @streamData.dataString];
buffIndex ← buffIndex + 1;
END;
colonChar => --end of field name field
IF buff[buffIndex + 1] # spaceChar THEN
ERROR StreamError[badFieldNameField]
ELSE
IF ~String.EmptyString[streamData.cachedField] THEN
ERROR StreamError[missingValueField]
ELSE -- cache field name
BEGIN
String.AppendStringAndGrow[
@streamData.cachedField, streamData.dataString, z];
streamData.dataString.length ← 0;
skip over the space
buffIndex ← buffIndex + 2;
END;
ENDCASE =>
BEGIN
AppendChar[char, @streamData.dataString];
buffIndex ← buffIndex + 1;
END;
END;
ENDLOOP;
set last state of last character in the buffer.
If haven't processed last character, take a look at it
If special character, just set prevPutBufState value. If normal,
add it to dataString.
IF buffIndex = block.stopIndexPlusOne THEN streamData.prevPutBufState ← normal
ELSE
IF
(streamData.prevPutBufState ← StateOfLastChar[
buff[block.stopIndexPlusOne - 1]]) = normal THEN
AppendChar[buff[block.stopIndexPlusOne - 1], @streamData.dataString];
END;
SearchForField: PROCEDURE [
data: DataTableHandle, name: Rope.ROPE]
RETURNS [index: CARDINAL ¬ 0] =
BEGIN
FOR index IN [0..data.length) DO
IF Rope.Equal[data[index].fieldName, name] THEN RETURN[index] ENDLOOP;
did not match the field name
ERROR StreamError[fieldNameNotFound];
END;
ConvertStreamDataToUserContext: PUBLIC ENTRY PROCEDURE[
sH: Stream.Handle, to: AdobeToolContext.UserContext, z: UNCOUNTED ZONE] =
BEGIN
ENABLE UNWIND => NULL;
CopyDataIntoUC[sH.clientData, to, z];
END;
CopyDataIntoUC: PROCEDURE[
from: ClientData, to: AdobeToolContext.UserContext] =
BEGIN
FOR i: CARDINAL IN [0..from.data.length) DO
to[i].dirty ← FALSE;
WITH uC: to[i] SELECT FROM
nonDisplayedField =>
IF uC.readOnlyField # NIL THEN
String.Replace[@uC.readOnlyField, from.data[i].value, zone]
ELSE
uC.readOnlyField ← String.CopyToNewString[from.data[i].value,
zone];
displayedField =>
WITH body: uC.editableField SELECT FROM
arId =>
body.arn ← IF ~String.EmptyString[from.data[i].value]
THEN String.StringToLongNumber[from.data[i].value]
ELSE AdobeOps.nilARNumber;
string =>
IF body.s = NIL
THEN body.s ← String.CopyToNewString[from.data[i].value,
zone]
ELSE String.Replace[@body.s, from.data[i].value, zone];
fixedLengthString =>
If body.s = NIL there is an implementation error --
IF ~String.EmptyString[from.data[i].value] THEN
String.Copy[body.s, from.data[i].value
StringBoundsFault, fill in as much as will fit.--
!String.StringBoundsFault => RESUME[NIL]]
ELSE body.s.length ← 0;--prevent use of previous value
dateTime => {
IF body.temp = NIL THEN
body.temp ← String.CopyToNewString[
from.data[i].value, zone]
ELSE String.Replace[
@body.temp, from.data[i].value, zone];
BEGIN ENABLE Date.Unintelligible => {
body.dt ← Time.Current[]; CONTINUE};
body.dt ← IF String.EmptyString[body.temp] THEN
LOOPHOLE[LONG[0], Date.Packed]
ELSE Date.StringToPacked[body.temp].dt
END};
numeric =>
body.num ← IF ~String.EmptyString[from.data[i].value]
THEN String.StringToLongNumber[from.data[i].value]
ELSE 0;
enumerated =>
body.value ← IF ~String.EmptyString[from.data[i].value]
THEN GetValueFromEnumString[from.data[i].value, to, i]
ELSE AdobeOps.nilEnum;
ENDCASE;
ENDCASE;
Free stream stuff from stream's zone
z.FREE[@from.data[i].value]
ENDLOOP;
from.dataTableIsDirty ← FALSE;
END;
GetValueFromEnumString: PUBLIC PROCEDURE[
s: Rope.ROPE, uC: AdobeToolContext.UserContext,
index: CARDINAL] RETURNS[value: CARDINAL] =
BEGIN
WITH body: uC.arSH.fieldList[index] SELECT FROM
enumerated => BEGIN
host: CARDINAL ← body.field;
IF host = AdobeOps.nullDependsOnIndex
THEN RETURN[FindValueInPossibilities[s,
body.possibilities[0].enumRecs]]
ELSE RETURN[FindValueInPossibilities[s,
FindPossibilities[GetEnumValueFromUC[uC, host],
body.possibilities]]];
END;
ENDCASE => ERROR; --client error uC must be enumerated
END;
GetEnumValueFromUC: PUBLIC PROCEDURE[
uC: AdobeToolContext.UserContext, index: CARDINAL]
RETURNS[value: CARDINAL ← AdobeOps.nilEnum] =
BEGIN
WITH displayed: uC[index] SELECT FROM
displayedField => WITH body: displayed.editableField SELECT FROM
enumerated => RETURN[body.value]
ENDCASE => ERROR
ENDCASE => ERROR;
END;
FindPossibilities: PUBLIC PROCEDURE[value: CARDINAL,
possibilities: AdobeOps.KeyedPossibilities]
RETURNS[AdobeOps.EnumeratedSequence] =
BEGIN
FOR i: CARDINAL IN [0..possibilities.length) DO
IF possibilities[i].keyedDependency = value
THEN RETURN[possibilities[i].enumRecs]
ENDLOOP;
EnumError[noMatch];
END;
FindValueInPossibilities: PROCEDURE[s: Rope.ROPE,
poss: AdobeOps.EnumeratedSequence] RETURNS[value: CARDINAL] =
BEGIN
FOR i: CARDINAL IN [0..poss.length) DO
IF Rope.Equal[s, poss[i].tag] THEN
RETURN[poss[i].item]
ENDLOOP;
EnumError[noMatch];
END;
ConvertUserContextToStreamData: PUBLIC ENTRY PROCEDURE[
sH: Stream.Handle, from: AdobeToolContext.UserContext] =
BEGIN
ENABLE UNWIND => NULL;
CopyUCIntoData[sH.clientData, from];
END;
CopyUCIntoData: PROCEDURE[
from: ClientData, to: AdobeToolContext.UserContext] =
BEGIN
incr: CARDINAL = 10;
IF from.dataTableIsDirty THEN FreeValues[from.data];
FOR i: CARDINAL IN [0..to.length) DO
WITH uC: to[i] SELECT FROM
nonDisplayedField =>
from.data[i].value ← String.CopyToNewString[uC.readOnlyField, z];
displayedField =>
BEGIN
ENABLE
String.StringBoundsFault =>
BEGIN
ns ← String.CopyToNewString[s: s, z: z, longer: incr];
z.FREE[@s];
RESUME[from.data[i].value ← ns]
END;
WITH body: uC.editableField SELECT FROM
arId =>
IF (body.arn # AdobeOps.nilARNumber) THEN
BEGIN
from.data[i].value ← String.MakeString[z, 10];
String.AppendLongDecimal[s: from.data[i].value, n: body.arn];
END
ELSE from.data[i].value ← NIL;
fixedLengthString, string =>
from.data[i].value ←
IF body.s # NIL THEN String.CopyToNewString[body.s, z]
ELSE NIL;
dateTime => {
ENABLE Date.Unintelligible =>{ --put in currentTOD
from.data[i].value ← String.CopyToNewString[
Date.PackedToString[Time.Current[]], z];
CONTINUE};
from.data[i].value ←
IF ~String.EmptyString[body.temp] AND
(Date.StringToPacked[body.temp].dt # Time.defaultTime)
THEN String.CopyToNewString[body.temp, z]
ELSE NIL};
numeric =>
BEGIN
from.data[i].value ← String.MakeString[z, 10];
String.AppendLongDecimal[s: from.data[i].value, n: body.num];
END;
enumerated =>
IF body.value # AdobeOps.nilEnum THEN
from.data[i].value ←
String.CopyToNewString[GetEnumStringFromValue[body.value,
WITH body: to.arSH.fieldList[i] SELECT FROM
enumerated => body.possibilities
ENDCASE => ERROR], z]
ELSE from.data[i].value ← NIL;
ENDCASE;
END;
ENDCASE;
ENDLOOP;
END;
GetEnumStringFromValue: PROCEDURE[value: CARDINAL, possiblities:
AdobeOps.KeyedPossibilities] RETURNS [string: Rope.ROPE] =
BEGIN
<<This is not as efficient as finding the particular array the value/string
is in (we know this from folllowing the dependsOn index when possibilities
contains alot of arrays. The guess is it will never happen that possibilities
will contain so many arrays that performance will be noticably worse>>
FOR i: CARDINAL IN [0..possiblities.length) DO
FOR j: CARDINAL IN [0..possiblities[i].enumRecs.length) DO
IF possiblities[i].enumRecs[j].item = value
THEN RETURN[possiblities[i].enumRecs[j].tag]
ENDLOOP;
ENDLOOP;
ERROR;
END;
GetValuePairFromTable: PUBLIC PROCEDURE[
index: CARDINAL, sH: ARAccess.ARStorage]
RETURNS[value: Rope.ROPE] = {
This procedure returns the Rope.ROPE, not a copy. Clients of
this procedure should not attempt to free the string returned.
clientData: ClientData ← sH.clientData;
table: DataTableHandle ← clientData.data;
RETURN[sH[index].value]};
RETURN[table[index].value]};
FreeValues: PROCEDURE[table: DataTableHandle] =
BEGIN
FOR i: CARDINAL IN [0..table.length) DO
z.FREE[@table[i].value]
ENDLOOP;
table.index ¬ 0;
END;
ResetDataTableValues: PUBLIC PROCEDURE[sH: Stream.Handle] = {
clientData: ClientData ← sH.clientData;
FOR i: CARDINAL IN [0..clientData.data.length) DO
IF clientData.data[i].value # NIL THEN
clientData.data[i].value.length ← 0;
ENDLOOP};
END...