DIRECTORY BasicTime USING [GMT, nullGMT], DFInternal USING [Client, LocalFileInfo, RemoteFileInfo], DFOperations USING [AbortInteraction, DFInfoInteraction, FileInteraction, InfoClass, InfoInteraction, InteractionProc, YesNoInteraction, YesNoResponse], DFUtilities USING [Date, DateToRope, RemoveVersionNumber], FS USING [ComponentPositions, Error, ErrorDesc, ExpandName, FileInfo], IO USING [PutF, PutFR, rope, STREAM], Process USING [CheckForAbort, Pause, SecondsToTicks, Ticks], Rope USING [Concat, Flatten, Fetch, Length, ROPE]; DFInternalImpl: CEDAR PROGRAM IMPORTS DFUtilities, FS, IO, Process, Rope EXPORTS DFInternal = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; retryInterval: Process.Ticks _ Process.SecondsToTicks[5]; abort: REF DFOperations.AbortInteraction _ NIL; AbortDF: PUBLIC ERROR = CODE; SimpleInteraction: PUBLIC PROC [client: DFInternal.Client, interaction: REF ANY] = { abort: BOOL; message: ROPE; IF client = NIL THEN RETURN; DoLogging[interaction, client.log]; [abort: abort, abortMessageForLog: message] _ client.proc[interaction, client.data]; IF abort THEN { [] _ client.proc[NEW[DFOperations.InfoInteraction _ [class: $abort, message: message]], client.data]; DoAbort[client.log, message]; }; }; YesOrNo: PUBLIC PROC [client: DFInternal.Client, message: ROPE, default: BOOL, blunder: BOOL _ FALSE] RETURNS [choice: BOOL] = { response: REF ANY = DoInteraction[ client, NEW[DFOperations.YesNoInteraction _ [ message: message, blunder: blunder, default: default ]] ]; choice _ default; WITH response SELECT FROM r: REF DFOperations.YesNoResponse => choice _ r^; ENDCASE; }; DoInteraction: PUBLIC PROC [client: DFInternal.Client, interaction: REF ANY] RETURNS [response: REF ANY] = { abort: BOOL; message: ROPE; IF client = NIL THEN RETURN [NIL]; DoLogging[interaction, client.log]; [abort, message, response] _ client.proc[interaction, client.data]; IF abort THEN { [] _ client.proc[NEW[DFOperations.InfoInteraction _ [class: $abort, message: message]], client.data]; DoAbort[client.log, message]; }; }; CheckAbort: PUBLIC PROC [client: DFInternal.Client] = { Process.CheckForAbort[]; SimpleInteraction[client, abort]; }; DoAbort: PUBLIC PROC [log: STREAM, message: ROPE _ NIL, proc: DFOperations.InteractionProc _ NIL, clientData: REF ANY _ NIL] = { interaction: REF ANY = NEW[DFOperations.InfoInteraction _ [class: $abort, message: message]]; IF proc # NIL AND message # NIL THEN [] _ proc[interaction, clientData]; DoLogging[interaction, log]; ERROR AbortDF }; DefaultInteractionProc: PUBLIC DFOperations.InteractionProc -- [interaction: REF ANY] RETURNS [abort: BOOL _ FALSE, abortMessageForLog: ROPE _ NIL, response: REF ANY _ NIL] -- = { WITH interaction SELECT FROM a: REF DFOperations.AbortInteraction => RETURN[abort: a.fromABORTED]; ENDCASE; }; GetFileInfo: PUBLIC PROC [info: REF ANY, notFoundOK: BOOL _ FALSE, remoteCheck: BOOL _ FALSE, client: DFInternal.Client _ NIL, errorLevel: DFOperations.InfoClass _ $error] = { WITH info SELECT FROM local: REF DFInternal.LocalFileInfo => { date: DFUtilities.Date _ []; name: ROPE _ local.name; IF local.date.format # $explicit THEN name _ DFUtilities.RemoveVersionNumber[name]; [fullFName: local.name, attachedTo: local.attachedTo, created: date.gmt, keep: local.keep] _ FS.FileInfo[name: name, remoteCheck: remoteCheck ! FS.Error => SELECT TRUE FROM error.group = $user AND notFoundOK => CONTINUE; RetryFSOperation[error, client] => RETRY; client # NIL => ReportFSError[error, info, client, errorLevel]; ENDCASE ]; IF date.gmt # BasicTime.nullGMT THEN date.format _ $explicit; local.date _ date; }; remote: REF DFInternal.RemoteFileInfo => { date: DFUtilities.Date _ IF remote.date.format = $explicit THEN remote.date ELSE []; uName: ROPE _ DFUtilities.RemoveVersionNumber[remote.name]; gmt: BasicTime.GMT _ BasicTime.nullGMT; [fullFName: remote.name, created: gmt] _ FS.FileInfo[name: uName, wantedCreatedTime: date.gmt, remoteCheck: TRUE ! FS.Error => SELECT TRUE FROM error.group = $user AND notFoundOK => CONTINUE; RetryFSOperation[error, client] => RETRY; client # NIL => ReportFSError[error, info, client, errorLevel]; ENDCASE ]; IF gmt # BasicTime.nullGMT THEN date.format _ $explicit; date.gmt _ gmt; remote.date _ date; }; ENDCASE => ERROR; }; LocalFile: PUBLIC PROC [file: ROPE] RETURNS [BOOL _ FALSE] = { len: INT _ Rope.Length[file]; IF len > 2 THEN SELECT Rope.Fetch[file, 0] FROM '[, '/ => { SELECT Rope.Fetch[file, 1] FROM '], '/ => RETURN [TRUE]; ENDCASE => RETURN [FALSE]; }; ENDCASE; RETURN[FS.ExpandName[file ! FS.Error => CONTINUE].cp.server.length = 0] }; ShortName: PUBLIC PROC [file: ROPE, keepVersion: BOOL _ FALSE] RETURNS [ROPE] = { bang: INT _ Rope.Length[file]; pos: INT _ bang; WHILE pos # 0 DO SELECT Rope.Fetch[file, pos _ pos - 1] FROM '! => IF NOT keepVersion THEN bang _ pos; '>, '/, '] => {pos _ pos + 1; EXIT}; ENDCASE; ENDLOOP; RETURN [Rope.Flatten[file, pos, bang-pos]]; }; RetryFSOperation: PUBLIC PROC [error: FS.ErrorDesc, client: DFInternal.Client] RETURNS [retry: BOOL _ FALSE] = { IF error.group # $environment THEN RETURN[FALSE]; retry _ YesOrNo[client: client, message: error.explanation.Concat[". Retry?"], default: TRUE]; SELECT error.code FROM $serverInaccessible, $connectionRejected, $connectionTimedOut => Process.Pause[retryInterval]; ENDCASE; }; ReportFSError: PUBLIC PROC [error: FS.ErrorDesc, info: REF ANY, client: DFInternal.Client, errorLevel: DFOperations.InfoClass _ $error] = { name: ROPE; WITH info SELECT FROM remote: REF DFInternal.RemoteFileInfo => name _ remote.name; local: REF DFInternal.LocalFileInfo => name _ FS.ExpandName[name _ local.name ! FS.Error => CONTINUE].fullFName; ENDCASE => ERROR; SimpleInteraction[ client, NEW[DFOperations.InfoInteraction _ [ class: errorLevel, message: IO.PutFR["%gFS.Error%g: %g", IO.rope[IF error.group = $user THEN NIL ELSE "Unexpected "], IO.rope[ IF error.explanation.Length[] = 0 THEN Rope.Concat[" manipulating ", name] ELSE NIL ], IO.rope[ IF error.explanation.Length[] # 0 THEN error.explanation ELSE "(no explanation)" ] ] ]] ]; IF errorLevel = $abort AND client # NIL THEN DoAbort[client.log]; }; DoLogging: PROC [interaction: REF ANY, log: STREAM] = { IF log = NIL THEN RETURN; WITH interaction SELECT FROM info: REF DFOperations.InfoInteraction => log.PutF["%g%g\N", IO.rope[ SELECT info.class FROM warning => "Warning: ", error => "Error: ", abort => "Abort: ", ENDCASE => NIL ], IO.rope[info.message] ]; info: REF DFOperations.DFInfoInteraction => log.PutF["%g: %g%g\N", IO.rope[ SELECT info.action FROM $start => "Start", $end => "End", $abort => "Abort", ENDCASE => NIL ], IO.rope[info.dfFile], IO.rope[IF info.message = NIL THEN NIL ELSE IO.PutFR[" (%g)", IO.rope[info.message]]] ]; file: REF DFOperations.FileInteraction => { log.PutF["%g %g %g {%g}%g\N", IO.rope[file.localFile], IO.rope[ SELECT file.action FROM $fetch => "<--", $store => "-->", $check => "<-->", ENDCASE => NIL], IO.rope[file.remoteFile], IO.rope[DFUtilities.DateToRope[[$explicit, file.date]]], IO.rope[ IF file.dateFormat = $explicit THEN NIL ELSE IO.PutFR[" ('%g')", SELECT file.dateFormat FROM $greaterThan => [character['>]], $notEqual => [rope["#"]], ENDCASE => [null[]] ] ] ]; }; ENDCASE; }; Initialize: PROC = { abort _ NEW[DFOperations.AbortInteraction _ [FALSE]]; }; Initialize[]; END. `DFInternalImpl.mesa Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. Levin on December 16, 1983 2:05 pm Russ Atkinson, March 19, 1985 6:10:27 pm PST Russ Atkinson (RRA) May 15, 1985 6:53:19 pm PDT Global "variables" logically, this is constant; it is set by initialization and never changed Exported to DFInternal RRA: The preferred version, regardless of the one hinted at, is the highest version number. This crock helps avoid problems with deleting elderly (but still correct) versions using Chat. Ideally our tools would play together such that this did not happen. We have found an explcit date. Although the given file name does not start with a server, it could be a local file if the working directory is local, so we have to do this the hard way. We do our own parsing here for efficiency. Internal Procedures Initialization Κ E˜codešœ™Kšœ Οmœ7™BKšœ"™"K™,K™/K˜—šΟk ˜ Kšœ žœžœ ˜Kšœ žœ)˜9Kšœ žœ†˜˜Kšœ žœ)˜:Kšžœžœ>˜FKšžœžœžœ˜%Kšœžœ/˜Kšœžœ˜šžœ ž˜šžœž˜˜ šžœž˜Kšœ žœžœ˜Kšžœžœžœ˜—K˜—Kšžœ˜——Kšœš™šKšžœžœžœ žœ˜GK˜—K˜šŸ œžœžœžœžœžœžœžœ˜QKšœ*™*Kšœžœ˜Kšœžœ˜šžœ ž˜šžœ!ž˜+Kšœžœžœ žœ ˜)Kšœžœ˜$Kšžœ˜—Kšžœ˜—Kšžœ%˜+K˜—K˜šŸœžœžœ žœ&žœ žœžœ˜pKšžœžœžœžœ˜1KšœYžœ˜_šžœ ž˜šœ@˜@Kšœ˜—Kšžœ˜—K˜—K˜š Ÿ œžœžœ žœžœžœM˜‹Kšœžœ˜ šžœžœž˜Kšœžœ1˜<šœžœ˜&Kšœžœ žœ žœ ˜I—Kšžœžœ˜—šœ˜Kšœ˜šžœ!˜$Kšœ˜šœ ˜ šžœ˜Kš žœžœžœžœžœ˜<šžœ˜Kšžœ žœ$˜JKšžœž˜K˜—šžœ˜Kšžœ žœ˜8Kšžœ˜K˜—K˜——K˜—Kšœ˜—Kšžœžœ žœžœ˜AK˜—K™K™K˜š Ÿ œžœžœžœžœ˜7Kšžœžœžœžœ˜šžœ žœž˜šœžœ ˜)šœ˜šžœ˜šžœ ž˜Kšœ@žœž˜N—Kšœ˜—Kšžœ˜K˜——šœžœ"˜+šœ˜šžœ˜šžœ ž˜Kšœ5žœž˜C—Kšœ˜—Kšžœ˜Kšžœžœžœžœžœžœžœ˜UKšœ˜——šœžœ"˜+˜Kšžœ˜šžœ˜šžœ ž˜Kšœ4žœžœ˜D——Kšžœ˜Kšžœ6˜8šžœ˜Kšžœžœž˜'šžœžœ˜šžœž˜Kšœ ˜ Kšœ˜Kšžœ ˜—Kšœ˜—K˜—Kšœ˜—K˜—Kšžœ˜—K˜—K˜K™K–u -- [interaction: REF ANY] RETURNS [abort: BOOL _ FALSE, abortMessageForLog: ROPE _ NIL, response: REF ANY _ NIL] -- ˜šŸ œžœ˜Kšœžœ"žœ˜5K˜K˜—K˜ K˜Kšžœ˜K˜K˜K˜—…—”,9