DIRECTORY AdobeOps USING [ EnumeratedSequence, FieldList, KeyedPossibilities], AdobeToolContext, ARAccess USING [--AppendChar, --ARStorage, DataTable], Ascii USING [CR, SP], Rope USING [Equal, ROPE]; 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 ¬ []]; 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 = ':; AllocateDataTable: PROCEDURE[fL: AdobeOps.FieldList] RETURNS[data: ARAccess.ARStorage] = { 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 ¬ AllocateDataTable[fL: fL]; }; 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; 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; StateOfLastChar: PROCEDURE [char: CHARACTER] RETURNS [type: PutStateType] = BEGIN RETURN[ SELECT char FROM quoteChar => wasQuote, crChar => wasCR, colonChar => wasColon, ENDCASE => normal]; 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; ERROR StreamError[fieldNameNotFound]; 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; GetEnumStringFromValue: PROCEDURE[value: CARDINAL, possiblities: AdobeOps.KeyedPossibilities] RETURNS [string: Rope.ROPE] = BEGIN <> 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] = { RETURN[sH[index].value]}; FreeValues: PROCEDURE[table: DataTableHandle] = BEGIN table.index ¬ 0; END; END... >4 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 Date USING [Packed, PackedToString, StringToPacked, Unintelligible], 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]; MyStreamHandle: TYPE = REF MyStreamObject; MyStreamObject: TYPE = RECORD [ lock: MONITORLOCK, stream: Stream.Object _ Stream.defaultObject]; AllocateStreamObject: PROCEDURE RETURNS[handle: LONG POINTER] = Loopholes MyStreamObject into StreamObject so can have a MONITOR LOCK {RETURN [z.NEW[MyStreamObject _ []]]}; allocate the table handle _ AllocateStreamObject[]; 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; 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: CHARACTER _ NULL; 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; 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: CARDINAL _ IF 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; 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; did not match the field name 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; 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; 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[table[index].value]}; FOR i: CARDINAL IN [0..table.length) DO z.FREE[@table[i].value] ENDLOOP; 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}; Κ‘•NewlineDelimiter –(cedarcode) style™šœ Οeœ=™IJšœ ™ Jšœ™Jšœ™Jšœ™Jšœ,™,J™+—Icode˜K˜šΟk ˜ šœ žœ˜K˜3—K˜Kšœ žœΟcœ˜6Kšœžœžœžœ˜Jšœžœ:™DKšœžœ žœ˜šœžœ™J™9J™J™3J™—šœžœ™J™6J™8J™—Jšœžœ™"—K˜šΟnœž œŸžœŸ9˜fKšžœŸœ ŸœŸ˜9Kšžœž˜!—˜Kšœžœžœ ˜&šœ žœžœ˜Kšœžœ˜Kšœžœ žœžœ ˜6—šœ žœžœ˜Kšœ ž œžœ˜Kšœž œžœ˜—Kš œžœžœžœžœžœž œ˜:Kšœžœ'˜9šœžœ˜K˜(—šœžœ˜K˜KK˜ —Kšœ žœ˜*šœžœžœ˜&Kšœ žœ˜K˜!Kšœžœ˜—Kšœ žœžœ˜šœžœžœ˜Kšœžœ˜Kšœžœžœ˜"Kšœ ž œžœ˜K˜'K˜'K˜$Kšœžœžœ˜ Kšœ ž œžœ˜K˜/——˜Jšœžœžœ™*šœžœžœ™Jšœž œ™J™.——˜Kš  œžœžœžœ˜#Kš  œžœžœ!žœ˜?Kš  œžœžœžœ˜Lš  œžœžœ˜Kšœ(žœ˜-——˜Kšœ ž œ˜Kšœž œ žœ˜Kšœ ž œ žœ˜ Kšœ ž œ˜˜K˜š  œž œžœ žœžœ™?JšœE™EJšœžœžœ™&J™—š œž œžœ˜Xšœ˜Jšœ™Kšœžœ ˜*šžœžœžœž˜&Kšœžœ˜—Kšžœ˜—Kšœ˜K˜——š  œžœž œ˜7šžœ!˜(J™ K˜#Jšœžœ+™BJ™J™J™—Kšœ˜——˜š  œ™&šž™Jšœ!žœ™.J™Jšœžœ™—Jšžœ™——˜š  œžœž œ™3Jšž™Jšžœžœžœ™J™)Jšœžœ™!Jšœžœ™"šžœžœžœž™3Jšœžœ"™(Jšœžœ™$—Jšžœ™Jšœžœ™Jšžœ™——˜š  œžœ™&Jšž™Jšžœžœžœ™šžœž™"J™%—Jšœ#™#Jšžœ™——˜š  œžœ™&Jšž™Jšžœžœžœ™J™Kšžœžœž™7Jšžœ&™,—Jšžœ™——K˜˜š !œž œ™.Jšœžœ™7Jšžœ žœ™"Jšž™šžœž™™Jšžœ(™*Jšžœ9™=Jšžœžœ ™*—™5Jšžœ&™(Jšžœ7™;Jšžœžœ™&——Jšžœ™J™Jšžœ ™Jšžœ™J™—š  œž œž œ˜<šžœ žœžœž˜)šž˜Kšžœžœžœžœ˜Cšžœžœž˜Kšœ žœžœ˜CKšžœžœžœ˜——Kšžœ˜K˜———˜š œž œ™.Jšžœž œ™2Jšžœžœ™'šžœž™™ Jšž™J™=šžœž™#šžœCžœ™KJšœ)žœ™>—Jšžœ'žœ™H—Jšžœžœ™ Jšžœ™—™ Jšž™š žœžœ$žœžœ-ž™xšžœ'žœ™/Jšœ(žœžœ™C—Jšžœžœžœ™F—J™9šžœž™#šžœ?žœ™GJšœ)žœ™>—šž™šžœ'žœ™/Jšœ(žœ™A—Jšžœžœ™6——Jšžœžœ™Jšžœ™—Jšžœ™—Jšžœ™——˜š œž œ.™Nšžœ™ Jšœžœ!™;J™—Jšž™Jšœ žœ™Jšœžœ™2Jšœ žœ™'Jšžœ1žœžœ™Lšžœ%ž™+šžœž™!™+™.J™——™šžœ™™?J™———Jšžœ™——šžœ$ž™+Jšœž œžœ™Jšœžœ™ J™<šžœ'™)Jšžœ3™6—Jšžœ1™5šžœž™!Jšœ žœ™™Jšž™Jšžœ>™@JšžœB™Fšžœ™J™-Jšžœ™—Jšžœ™—™ Jšž™Jšžœ>™@Jšžœ@™Dšžœ™J™+Jšžœ™—Jšžœ™—™Jšžœ>™@Jšžœ?™Cšžœ™J™+Jšžœ™——™šžœ?ž™EJšž™J™?J™$J™Jšžœ™"Jšž™—šžœ™J™+Jšžœ™——™ Jšž™šžœ?ž™EJšž™J™?J™$J™Jšžœ™"Jšž™—šžœ™J™+Jšžœ™—Jšžœ™—Jšžœ™—Jšžœ™—Jšžœ™Jšžœ™——K˜˜š  œž œžœ žœ žœ˜LKš žœ žœžœžœžœ#˜TK˜K˜—Kš  œž œžœAžœ žœž˜«Kšž˜šžœž˜˜K˜-K˜.—˜K˜*K˜+——Kšžœ˜Kšžœ˜Kšžœ˜K˜š  œž œ˜Kšœž œžœ˜5Kšžœ žœž˜)šž˜K˜K˜—Kšžœ˜K˜—K˜—˜Jšœ™š   œž œž œ žœžœ™@Jšž™Jšœ4žœ™<šœ™J™™Jšž™Jš œžœžœžœ žœŸ ™W™J™&—Jšœžœ™ Jšžœ™Jšžœ™——Jšžœ™——˜š œž œž œžœ˜KKšž˜šžœ˜šžœž˜K˜K˜K˜Kšžœ ˜——Kšžœ˜——˜š !œž œ™.Jšœžœ™7Jšžœ žœ™Jšž™šžœž™!J™7™Jšžœžœžœ™=šž™šžœžœž™Jšžœ#™(—šž™Jšž™™ J™6Jšžœžœ™;Jšœžœžœ™—Jšœžœ™J™Jšžœ™———™ Jšžœžœžœ™Dšž™šžœ(ž™.Jšžœ™$—šž™JšžœŸ™™+J™—J™Jšžœ™———Jšžœ™—Jšžœ ™Jšžœ™——K˜K˜˜š œž œ0™IJšž™Jšœžœ™Jšœ žœ™'Jšœžœ™2šžœžœž™#Jšž™Jšœžœ™9J™!Jšžœ™—šžœ%ž™+J™K—Jšœ7™7Jšœ8™8šžœ(ž™/šžœžœ™ šžœ™ šžœžœžœ™&J™"J™#—J™—Jšœž œ™"šžœž™šœ Ÿ™Jšœ™šžœž™$Jšžœ™ —šž™šžœ,ž™2Jšžœ#™(—šž™Jšž™šœ žœ™&J™)—šžœ%žœž™/™$J™0——šžœ™J™-™J™#J™——J™"J™!Jšœ™J™Jšžœ™———™ JšžœŸ+™2Jšœ*™*J™J™J™)J™Jšžœ™—šœŸ™'šžœ!ž™'Jšžœ™$—šž™šžœ-ž™3Jšžœ™$—šžœŸ™Jšž™™J™3—J™!Jšœ™J™Jšžœ™———šžœ™ Jšž™J™)J™Jšžœ™—Jšžœ™—Jšžœ™——Jšœ/™/Jšœ6™6JšœA™AJšœ™Jšžœ$žœ$™Nšž™šž™™.Jšœ,ž™0—J™E——Jšžœ™J™—š œž œ˜Kšœž œ˜'Kšžœ žœ˜Kšž˜šžœžœž˜ Kšžœ)žœžœžœ˜F—Jšœ™Kšžœ ˜%Kšžœ˜K˜—š œžœžœž œ™7Jšœ8ž œžœ™IJšž™šžœžœžœ™J™%—Jšžœ™—K˜š œž œ™Jšœ5™5Jšž™šžœžœžœž™+Jšœžœ™šžœ žœž™™šžœžœž™J™;—šž™J™=J™——™šžœžœž™'™šœ žœ)™6Jšžœ.™2Jšžœ™——™ šžœ ž™Jšžœ4™8J™Jšžœ3™7——™Jšœ3™3šžœ)ž™/™&Jšœ1™1Jšœžœžœ™)——JšžœŸ™6—™šžœ žœž™™#J™—šžœ™J™&——šžœžœ™%Jšœžœ™$Jšœ žœž™/Jšžœžœ™Jšžœ#™'—Jšžœ™—™ šœ žœ(™5Jšžœ.™2Jšžœ™——™ šœ žœ)™8Jšžœ2™6Jšžœ™———Jšžœ™—Jšžœ™Jšœ$™$Jšœžœ™——Jšžœ™Jšœžœ™Jšžœ™J™—š œžœž œ™)Jšœž œ$™0Jšœžœžœžœ™+Jšž™šžœ žœž™/šœž™Jšœžœ™šžœ#™%Jšžœžœ™'J™ —šžœžœ™'™/J™——Jšžœ™——JšžœžœŸ$™6Jšžœ™J™—š œžœž œ™%Jšœ)žœ™3Jšžœžœ™-Jšž™šžœžœž™%šœžœžœž™@Jšœžœ ™ Jšžœž™——Jšžœžœ™Jšžœ™J™—š œžœž œžœ˜4K˜+Kšžœ˜&Kšž˜šžœžœžœž˜/Kšžœ)˜+Kšžœžœ˜&—Kšžœ˜K˜Kšžœ˜K˜—š œž œž œ˜1Kšœ#žœžœ˜=Kšž˜šžœžœžœž˜&šžœž˜"Kšžœ˜——Kšžœ˜K˜Kšžœ˜——K˜˜š œžœžœž œ™7J™8Jšž™šžœžœžœ™J™$—Jšžœ™J™—š œž œ™J™5šž™Jšœžœ™Jšžœžœ™4šžœžœžœž™$šžœ žœž™™J™A—™Jšž™šž™™Jšž™J™6Jšœžœ™ Jšžœ™Jšžœ™——šžœžœž™'™šžœ#ž™)šž™J™.J™=—Jšž™—Jšžœžœ™—™™Jšžœ žœžœ"™6Jšžœžœ™ ——™ šžœŸ™2™,J™(—Jšžœ™ —™šžœ žœ™&J™7Jšžœ%™)Jšžœžœ™ ———™ šž™J™.J™=—Jšžœ™J™ šžœž™%™™9šžœžœž™+J™ —Jšžœžœ™———Jšžœžœ™——Jšžœ™Jšžœ™—Jšžœ™———Jšžœ™Jšžœ™J™—š œž œžœ˜@šœžœ ž œ˜:Kšž˜K˜KK˜JK˜MK˜Gšžœžœžœž˜.šžœžœžœ&ž˜:Kšžœ)˜+Kšžœžœ!˜,—Kšžœ˜—Kšžœ˜Kšžœ˜Kšžœ˜K˜——š œžœž œ˜(Kšœžœ˜)Kšžœ žœ˜Jšœ=™=Jšœ>™>J™'J™)Kšžœ˜Jšžœ™K˜—š  œž œ˜/Kšž˜šžœžœžœž™'Jšœžœ™Jšžœ™—K˜Kšžœ˜K˜—š œžœž œ™=J™'šžœžœžœž™1šžœžœžœ™'J™$—Jšžœ™ —J™—Kšžœ˜ —K˜K˜—…—>k